1*0cbfa66cSDaniel Fojt /* $OpenBSD: readconf.c,v 1.329 2020/04/24 03:33:21 dtucker Exp $ */ 218de8d7fSPeter Avalos /* 318de8d7fSPeter Avalos * Author: Tatu Ylonen <ylo@cs.hut.fi> 418de8d7fSPeter Avalos * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 518de8d7fSPeter Avalos * All rights reserved 618de8d7fSPeter Avalos * Functions for reading the configuration files. 718de8d7fSPeter Avalos * 818de8d7fSPeter Avalos * As far as I am concerned, the code I have written for this software 918de8d7fSPeter Avalos * can be used freely for any purpose. Any derived versions of this 1018de8d7fSPeter Avalos * software must be clearly marked as such, and if the derived work is 1118de8d7fSPeter Avalos * incompatible with the protocol description in the RFC file, it must be 1218de8d7fSPeter Avalos * called by a name other than "ssh" or "Secure Shell". 1318de8d7fSPeter Avalos */ 1418de8d7fSPeter Avalos 1518de8d7fSPeter Avalos #include "includes.h" 1618de8d7fSPeter Avalos 1718de8d7fSPeter Avalos #include <sys/types.h> 1818de8d7fSPeter Avalos #include <sys/stat.h> 1918de8d7fSPeter Avalos #include <sys/socket.h> 2036e94dc5SPeter Avalos #include <sys/wait.h> 2136e94dc5SPeter Avalos #include <sys/un.h> 2218de8d7fSPeter Avalos 2318de8d7fSPeter Avalos #include <netinet/in.h> 249f304aafSPeter Avalos #include <netinet/in_systm.h> 259f304aafSPeter Avalos #include <netinet/ip.h> 2636e94dc5SPeter Avalos #include <arpa/inet.h> 2718de8d7fSPeter Avalos 2818de8d7fSPeter Avalos #include <ctype.h> 2918de8d7fSPeter Avalos #include <errno.h> 3036e94dc5SPeter Avalos #include <fcntl.h> 31e9778795SPeter Avalos #include <limits.h> 3218de8d7fSPeter Avalos #include <netdb.h> 3336e94dc5SPeter Avalos #ifdef HAVE_PATHS_H 3436e94dc5SPeter Avalos # include <paths.h> 3536e94dc5SPeter Avalos #endif 3636e94dc5SPeter Avalos #include <pwd.h> 3718de8d7fSPeter Avalos #include <signal.h> 3818de8d7fSPeter Avalos #include <stdio.h> 3918de8d7fSPeter Avalos #include <string.h> 40*0cbfa66cSDaniel Fojt #include <stdarg.h> 4118de8d7fSPeter Avalos #include <unistd.h> 42e9778795SPeter Avalos #ifdef USE_SYSTEM_GLOB 43e9778795SPeter Avalos # include <glob.h> 44e9778795SPeter Avalos #else 45e9778795SPeter Avalos # include "openbsd-compat/glob.h" 46e9778795SPeter Avalos #endif 4736e94dc5SPeter Avalos #ifdef HAVE_UTIL_H 4836e94dc5SPeter Avalos #include <util.h> 4936e94dc5SPeter Avalos #endif 50e9778795SPeter Avalos #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) 51e9778795SPeter Avalos # include <vis.h> 52e9778795SPeter Avalos #endif 5318de8d7fSPeter Avalos 5418de8d7fSPeter Avalos #include "xmalloc.h" 5518de8d7fSPeter Avalos #include "ssh.h" 56664f4763Szrj #include "ssherr.h" 5718de8d7fSPeter Avalos #include "compat.h" 5818de8d7fSPeter Avalos #include "cipher.h" 5918de8d7fSPeter Avalos #include "pathnames.h" 6018de8d7fSPeter Avalos #include "log.h" 61e9778795SPeter Avalos #include "sshkey.h" 6236e94dc5SPeter Avalos #include "misc.h" 6318de8d7fSPeter Avalos #include "readconf.h" 6418de8d7fSPeter Avalos #include "match.h" 6518de8d7fSPeter Avalos #include "kex.h" 6618de8d7fSPeter Avalos #include "mac.h" 6736e94dc5SPeter Avalos #include "uidswap.h" 68e9778795SPeter Avalos #include "myproposal.h" 69e9778795SPeter Avalos #include "digest.h" 7018de8d7fSPeter Avalos 7118de8d7fSPeter Avalos /* Format of the configuration file: 7218de8d7fSPeter Avalos 7318de8d7fSPeter Avalos # Configuration data is parsed as follows: 7418de8d7fSPeter Avalos # 1. command line options 7518de8d7fSPeter Avalos # 2. user-specific file 7618de8d7fSPeter Avalos # 3. system-wide file 7718de8d7fSPeter Avalos # Any configuration value is only changed the first time it is set. 7818de8d7fSPeter Avalos # Thus, host-specific definitions should be at the beginning of the 7918de8d7fSPeter Avalos # configuration file, and defaults at the end. 8018de8d7fSPeter Avalos 8118de8d7fSPeter Avalos # Host-specific declarations. These may override anything above. A single 8218de8d7fSPeter Avalos # host may match multiple declarations; these are processed in the order 8318de8d7fSPeter Avalos # that they are given in. 8418de8d7fSPeter Avalos 8518de8d7fSPeter Avalos Host *.ngs.fi ngs.fi 8618de8d7fSPeter Avalos User foo 8718de8d7fSPeter Avalos 8818de8d7fSPeter Avalos Host fake.com 89*0cbfa66cSDaniel Fojt Hostname another.host.name.real.org 9018de8d7fSPeter Avalos User blaah 9118de8d7fSPeter Avalos Port 34289 9218de8d7fSPeter Avalos ForwardX11 no 9318de8d7fSPeter Avalos ForwardAgent no 9418de8d7fSPeter Avalos 9518de8d7fSPeter Avalos Host books.com 9618de8d7fSPeter Avalos RemoteForward 9999 shadows.cs.hut.fi:9999 97ce74bacaSMatthew Dillon Ciphers 3des-cbc 9818de8d7fSPeter Avalos 9918de8d7fSPeter Avalos Host fascist.blob.com 10018de8d7fSPeter Avalos Port 23123 10118de8d7fSPeter Avalos User tylonen 10218de8d7fSPeter Avalos PasswordAuthentication no 10318de8d7fSPeter Avalos 10418de8d7fSPeter Avalos Host puukko.hut.fi 10518de8d7fSPeter Avalos User t35124p 10618de8d7fSPeter Avalos ProxyCommand ssh-proxy %h %p 10718de8d7fSPeter Avalos 10818de8d7fSPeter Avalos Host *.fr 10918de8d7fSPeter Avalos PublicKeyAuthentication no 11018de8d7fSPeter Avalos 11118de8d7fSPeter Avalos Host *.su 112ce74bacaSMatthew Dillon Ciphers aes128-ctr 11318de8d7fSPeter Avalos PasswordAuthentication no 11418de8d7fSPeter Avalos 11518de8d7fSPeter Avalos Host vpn.fake.com 11618de8d7fSPeter Avalos Tunnel yes 11718de8d7fSPeter Avalos TunnelDevice 3 11818de8d7fSPeter Avalos 11918de8d7fSPeter Avalos # Defaults for various options 12018de8d7fSPeter Avalos Host * 12118de8d7fSPeter Avalos ForwardAgent no 12218de8d7fSPeter Avalos ForwardX11 no 12318de8d7fSPeter Avalos PasswordAuthentication yes 12418de8d7fSPeter Avalos StrictHostKeyChecking yes 12518de8d7fSPeter Avalos TcpKeepAlive no 12618de8d7fSPeter Avalos IdentityFile ~/.ssh/identity 12718de8d7fSPeter Avalos Port 22 12818de8d7fSPeter Avalos EscapeChar ~ 12918de8d7fSPeter Avalos 13018de8d7fSPeter Avalos */ 13118de8d7fSPeter Avalos 132e9778795SPeter Avalos static int read_config_file_depth(const char *filename, struct passwd *pw, 133e9778795SPeter Avalos const char *host, const char *original_host, Options *options, 134664f4763Szrj int flags, int *activep, int *want_final_pass, int depth); 135e9778795SPeter Avalos static int process_config_line_depth(Options *options, struct passwd *pw, 136e9778795SPeter Avalos const char *host, const char *original_host, char *line, 137664f4763Szrj const char *filename, int linenum, int *activep, int flags, 138664f4763Szrj int *want_final_pass, int depth); 139e9778795SPeter Avalos 14018de8d7fSPeter Avalos /* Keyword tokens. */ 14118de8d7fSPeter Avalos 14218de8d7fSPeter Avalos typedef enum { 14318de8d7fSPeter Avalos oBadOption, 144e9778795SPeter Avalos oHost, oMatch, oInclude, 145856ea928SPeter Avalos oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout, 146856ea928SPeter Avalos oGatewayPorts, oExitOnForwardFailure, 147*0cbfa66cSDaniel Fojt oPasswordAuthentication, 14818de8d7fSPeter Avalos oChallengeResponseAuthentication, oXAuthLocation, 149*0cbfa66cSDaniel Fojt oIdentityFile, oHostname, oPort, oRemoteForward, oLocalForward, 150e9778795SPeter Avalos oCertificateFile, oAddKeysToAgent, oIdentityAgent, 151*0cbfa66cSDaniel Fojt oUser, oEscapeChar, oProxyCommand, 15218de8d7fSPeter Avalos oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, 15318de8d7fSPeter Avalos oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, 154*0cbfa66cSDaniel Fojt oTCPKeepAlive, oNumberOfPasswordPrompts, 155*0cbfa66cSDaniel Fojt oLogFacility, oLogLevel, oCiphers, oMacs, 156e9778795SPeter Avalos oPubkeyAuthentication, 15718de8d7fSPeter Avalos oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, 15818de8d7fSPeter Avalos oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, 159664f4763Szrj oHostKeyAlgorithms, oBindAddress, oBindInterface, oPKCS11Provider, 16018de8d7fSPeter Avalos oClearAllForwardings, oNoHostAuthenticationForLocalhost, 16118de8d7fSPeter Avalos oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, 16218de8d7fSPeter Avalos oAddressFamily, oGssAuthentication, oGssDelegateCreds, 16318de8d7fSPeter Avalos oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, 164664f4763Szrj oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist, 165856ea928SPeter Avalos oHashKnownHosts, 166ce74bacaSMatthew Dillon oTunnel, oTunnelDevice, 167ce74bacaSMatthew Dillon oLocalCommand, oPermitLocalCommand, oRemoteCommand, 168e9778795SPeter Avalos oVisualHostKey, 16936e94dc5SPeter Avalos oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, 17036e94dc5SPeter Avalos oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, 17136e94dc5SPeter Avalos oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, 172e9778795SPeter Avalos oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, 173e9778795SPeter Avalos oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes, 174664f4763Szrj oPubkeyAcceptedKeyTypes, oCASignatureAlgorithms, oProxyJump, 175*0cbfa66cSDaniel Fojt oSecurityKeyProvider, 176ce74bacaSMatthew Dillon oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported 17718de8d7fSPeter Avalos } OpCodes; 17818de8d7fSPeter Avalos 17918de8d7fSPeter Avalos /* Textual representations of the tokens. */ 18018de8d7fSPeter Avalos 18118de8d7fSPeter Avalos static struct { 18218de8d7fSPeter Avalos const char *name; 18318de8d7fSPeter Avalos OpCodes opcode; 18418de8d7fSPeter Avalos } keywords[] = { 185ce74bacaSMatthew Dillon /* Deprecated options */ 186ce74bacaSMatthew Dillon { "protocol", oIgnore }, /* NB. silently ignored */ 187ce74bacaSMatthew Dillon { "cipher", oDeprecated }, 188ce74bacaSMatthew Dillon { "fallbacktorsh", oDeprecated }, 189ce74bacaSMatthew Dillon { "globalknownhostsfile2", oDeprecated }, 190ce74bacaSMatthew Dillon { "rhostsauthentication", oDeprecated }, 191ce74bacaSMatthew Dillon { "userknownhostsfile2", oDeprecated }, 192ce74bacaSMatthew Dillon { "useroaming", oDeprecated }, 193ce74bacaSMatthew Dillon { "usersh", oDeprecated }, 194664f4763Szrj { "useprivilegedport", oDeprecated }, 195ce74bacaSMatthew Dillon 196ce74bacaSMatthew Dillon /* Unsupported options */ 197ce74bacaSMatthew Dillon { "afstokenpassing", oUnsupported }, 198ce74bacaSMatthew Dillon { "kerberosauthentication", oUnsupported }, 199ce74bacaSMatthew Dillon { "kerberostgtpassing", oUnsupported }, 200*0cbfa66cSDaniel Fojt { "rsaauthentication", oUnsupported }, 201*0cbfa66cSDaniel Fojt { "rhostsrsaauthentication", oUnsupported }, 202*0cbfa66cSDaniel Fojt { "compressionlevel", oUnsupported }, 203ce74bacaSMatthew Dillon 204ce74bacaSMatthew Dillon /* Sometimes-unsupported options */ 205ce74bacaSMatthew Dillon #if defined(GSSAPI) 206ce74bacaSMatthew Dillon { "gssapiauthentication", oGssAuthentication }, 207ce74bacaSMatthew Dillon { "gssapidelegatecredentials", oGssDelegateCreds }, 208ce74bacaSMatthew Dillon # else 209ce74bacaSMatthew Dillon { "gssapiauthentication", oUnsupported }, 210ce74bacaSMatthew Dillon { "gssapidelegatecredentials", oUnsupported }, 211ce74bacaSMatthew Dillon #endif 212ce74bacaSMatthew Dillon #ifdef ENABLE_PKCS11 213ce74bacaSMatthew Dillon { "pkcs11provider", oPKCS11Provider }, 214664f4763Szrj { "smartcarddevice", oPKCS11Provider }, 215ce74bacaSMatthew Dillon # else 216ce74bacaSMatthew Dillon { "smartcarddevice", oUnsupported }, 217ce74bacaSMatthew Dillon { "pkcs11provider", oUnsupported }, 218ce74bacaSMatthew Dillon #endif 219ce74bacaSMatthew Dillon 22018de8d7fSPeter Avalos { "forwardagent", oForwardAgent }, 22118de8d7fSPeter Avalos { "forwardx11", oForwardX11 }, 22218de8d7fSPeter Avalos { "forwardx11trusted", oForwardX11Trusted }, 223856ea928SPeter Avalos { "forwardx11timeout", oForwardX11Timeout }, 22418de8d7fSPeter Avalos { "exitonforwardfailure", oExitOnForwardFailure }, 22518de8d7fSPeter Avalos { "xauthlocation", oXAuthLocation }, 22618de8d7fSPeter Avalos { "gatewayports", oGatewayPorts }, 22718de8d7fSPeter Avalos { "passwordauthentication", oPasswordAuthentication }, 22818de8d7fSPeter Avalos { "kbdinteractiveauthentication", oKbdInteractiveAuthentication }, 22918de8d7fSPeter Avalos { "kbdinteractivedevices", oKbdInteractiveDevices }, 23018de8d7fSPeter Avalos { "pubkeyauthentication", oPubkeyAuthentication }, 23118de8d7fSPeter Avalos { "dsaauthentication", oPubkeyAuthentication }, /* alias */ 23218de8d7fSPeter Avalos { "hostbasedauthentication", oHostbasedAuthentication }, 23318de8d7fSPeter Avalos { "challengeresponseauthentication", oChallengeResponseAuthentication }, 234664f4763Szrj { "skeyauthentication", oUnsupported }, 23518de8d7fSPeter Avalos { "tisauthentication", oChallengeResponseAuthentication }, /* alias */ 23618de8d7fSPeter Avalos { "identityfile", oIdentityFile }, 237cb5eb4f1SPeter Avalos { "identityfile2", oIdentityFile }, /* obsolete */ 23818de8d7fSPeter Avalos { "identitiesonly", oIdentitiesOnly }, 239e9778795SPeter Avalos { "certificatefile", oCertificateFile }, 240e9778795SPeter Avalos { "addkeystoagent", oAddKeysToAgent }, 241e9778795SPeter Avalos { "identityagent", oIdentityAgent }, 242*0cbfa66cSDaniel Fojt { "hostname", oHostname }, 24318de8d7fSPeter Avalos { "hostkeyalias", oHostKeyAlias }, 24418de8d7fSPeter Avalos { "proxycommand", oProxyCommand }, 24518de8d7fSPeter Avalos { "port", oPort }, 24618de8d7fSPeter Avalos { "ciphers", oCiphers }, 24718de8d7fSPeter Avalos { "macs", oMacs }, 24818de8d7fSPeter Avalos { "remoteforward", oRemoteForward }, 24918de8d7fSPeter Avalos { "localforward", oLocalForward }, 25018de8d7fSPeter Avalos { "user", oUser }, 25118de8d7fSPeter Avalos { "host", oHost }, 25236e94dc5SPeter Avalos { "match", oMatch }, 25318de8d7fSPeter Avalos { "escapechar", oEscapeChar }, 25418de8d7fSPeter Avalos { "globalknownhostsfile", oGlobalKnownHostsFile }, 255cb5eb4f1SPeter Avalos { "userknownhostsfile", oUserKnownHostsFile }, 25618de8d7fSPeter Avalos { "connectionattempts", oConnectionAttempts }, 25718de8d7fSPeter Avalos { "batchmode", oBatchMode }, 25818de8d7fSPeter Avalos { "checkhostip", oCheckHostIP }, 25918de8d7fSPeter Avalos { "stricthostkeychecking", oStrictHostKeyChecking }, 26018de8d7fSPeter Avalos { "compression", oCompression }, 26118de8d7fSPeter Avalos { "tcpkeepalive", oTCPKeepAlive }, 26218de8d7fSPeter Avalos { "keepalive", oTCPKeepAlive }, /* obsolete */ 26318de8d7fSPeter Avalos { "numberofpasswordprompts", oNumberOfPasswordPrompts }, 264ce74bacaSMatthew Dillon { "syslogfacility", oLogFacility }, 26518de8d7fSPeter Avalos { "loglevel", oLogLevel }, 26618de8d7fSPeter Avalos { "dynamicforward", oDynamicForward }, 26718de8d7fSPeter Avalos { "preferredauthentications", oPreferredAuthentications }, 26818de8d7fSPeter Avalos { "hostkeyalgorithms", oHostKeyAlgorithms }, 269664f4763Szrj { "casignaturealgorithms", oCASignatureAlgorithms }, 27018de8d7fSPeter Avalos { "bindaddress", oBindAddress }, 271664f4763Szrj { "bindinterface", oBindInterface }, 27218de8d7fSPeter Avalos { "clearallforwardings", oClearAllForwardings }, 27318de8d7fSPeter Avalos { "enablesshkeysign", oEnableSSHKeysign }, 27418de8d7fSPeter Avalos { "verifyhostkeydns", oVerifyHostKeyDNS }, 27518de8d7fSPeter Avalos { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost }, 27618de8d7fSPeter Avalos { "rekeylimit", oRekeyLimit }, 27718de8d7fSPeter Avalos { "connecttimeout", oConnectTimeout }, 27818de8d7fSPeter Avalos { "addressfamily", oAddressFamily }, 27918de8d7fSPeter Avalos { "serveraliveinterval", oServerAliveInterval }, 28018de8d7fSPeter Avalos { "serveralivecountmax", oServerAliveCountMax }, 28118de8d7fSPeter Avalos { "sendenv", oSendEnv }, 282664f4763Szrj { "setenv", oSetEnv }, 28318de8d7fSPeter Avalos { "controlpath", oControlPath }, 28418de8d7fSPeter Avalos { "controlmaster", oControlMaster }, 285856ea928SPeter Avalos { "controlpersist", oControlPersist }, 28618de8d7fSPeter Avalos { "hashknownhosts", oHashKnownHosts }, 287e9778795SPeter Avalos { "include", oInclude }, 28818de8d7fSPeter Avalos { "tunnel", oTunnel }, 28918de8d7fSPeter Avalos { "tunneldevice", oTunnelDevice }, 29018de8d7fSPeter Avalos { "localcommand", oLocalCommand }, 29118de8d7fSPeter Avalos { "permitlocalcommand", oPermitLocalCommand }, 292ce74bacaSMatthew Dillon { "remotecommand", oRemoteCommand }, 29318de8d7fSPeter Avalos { "visualhostkey", oVisualHostKey }, 2949f304aafSPeter Avalos { "kexalgorithms", oKexAlgorithms }, 2959f304aafSPeter Avalos { "ipqos", oIPQoS }, 2961c188a7fSPeter Avalos { "requesttty", oRequestTTY }, 29736e94dc5SPeter Avalos { "proxyusefdpass", oProxyUseFdpass }, 29836e94dc5SPeter Avalos { "canonicaldomains", oCanonicalDomains }, 29936e94dc5SPeter Avalos { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal }, 30036e94dc5SPeter Avalos { "canonicalizehostname", oCanonicalizeHostname }, 30136e94dc5SPeter Avalos { "canonicalizemaxdots", oCanonicalizeMaxDots }, 30236e94dc5SPeter Avalos { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs }, 30336e94dc5SPeter Avalos { "streamlocalbindmask", oStreamLocalBindMask }, 30436e94dc5SPeter Avalos { "streamlocalbindunlink", oStreamLocalBindUnlink }, 305e9778795SPeter Avalos { "revokedhostkeys", oRevokedHostKeys }, 306e9778795SPeter Avalos { "fingerprinthash", oFingerprintHash }, 307e9778795SPeter Avalos { "updatehostkeys", oUpdateHostkeys }, 308e9778795SPeter Avalos { "hostbasedkeytypes", oHostbasedKeyTypes }, 309e9778795SPeter Avalos { "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes }, 31036e94dc5SPeter Avalos { "ignoreunknown", oIgnoreUnknown }, 311e9778795SPeter Avalos { "proxyjump", oProxyJump }, 312*0cbfa66cSDaniel Fojt { "securitykeyprovider", oSecurityKeyProvider }, 313cb5eb4f1SPeter Avalos 31418de8d7fSPeter Avalos { NULL, oBadOption } 31518de8d7fSPeter Avalos }; 31618de8d7fSPeter Avalos 317*0cbfa66cSDaniel Fojt static char *kex_default_pk_alg_filtered; 318*0cbfa66cSDaniel Fojt 319*0cbfa66cSDaniel Fojt const char * 320*0cbfa66cSDaniel Fojt kex_default_pk_alg(void) 321*0cbfa66cSDaniel Fojt { 322*0cbfa66cSDaniel Fojt if (kex_default_pk_alg_filtered == NULL) 323*0cbfa66cSDaniel Fojt fatal("kex_default_pk_alg not initialized."); 324*0cbfa66cSDaniel Fojt return kex_default_pk_alg_filtered; 325*0cbfa66cSDaniel Fojt } 326*0cbfa66cSDaniel Fojt 327*0cbfa66cSDaniel Fojt char * 328*0cbfa66cSDaniel Fojt ssh_connection_hash(const char *thishost, const char *host, const char *portstr, 329*0cbfa66cSDaniel Fojt const char *user) 330*0cbfa66cSDaniel Fojt { 331*0cbfa66cSDaniel Fojt struct ssh_digest_ctx *md; 332*0cbfa66cSDaniel Fojt u_char conn_hash[SSH_DIGEST_MAX_LENGTH]; 333*0cbfa66cSDaniel Fojt 334*0cbfa66cSDaniel Fojt if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL || 335*0cbfa66cSDaniel Fojt ssh_digest_update(md, thishost, strlen(thishost)) < 0 || 336*0cbfa66cSDaniel Fojt ssh_digest_update(md, host, strlen(host)) < 0 || 337*0cbfa66cSDaniel Fojt ssh_digest_update(md, portstr, strlen(portstr)) < 0 || 338*0cbfa66cSDaniel Fojt ssh_digest_update(md, user, strlen(user)) < 0 || 339*0cbfa66cSDaniel Fojt ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0) 340*0cbfa66cSDaniel Fojt fatal("%s: mux digest failed", __func__); 341*0cbfa66cSDaniel Fojt ssh_digest_free(md); 342*0cbfa66cSDaniel Fojt return tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1)); 343*0cbfa66cSDaniel Fojt } 344*0cbfa66cSDaniel Fojt 34518de8d7fSPeter Avalos /* 34618de8d7fSPeter Avalos * Adds a local TCP/IP port forward to options. Never returns if there is an 34718de8d7fSPeter Avalos * error. 34818de8d7fSPeter Avalos */ 34918de8d7fSPeter Avalos 35018de8d7fSPeter Avalos void 35136e94dc5SPeter Avalos add_local_forward(Options *options, const struct Forward *newfwd) 35218de8d7fSPeter Avalos { 35336e94dc5SPeter Avalos struct Forward *fwd; 354e9778795SPeter Avalos int i; 355e9778795SPeter Avalos 356e9778795SPeter Avalos /* Don't add duplicates */ 357e9778795SPeter Avalos for (i = 0; i < options->num_local_forwards; i++) { 358e9778795SPeter Avalos if (forward_equals(newfwd, options->local_forwards + i)) 359e9778795SPeter Avalos return; 360e9778795SPeter Avalos } 361e9778795SPeter Avalos options->local_forwards = xreallocarray(options->local_forwards, 362856ea928SPeter Avalos options->num_local_forwards + 1, 363856ea928SPeter Avalos sizeof(*options->local_forwards)); 36418de8d7fSPeter Avalos fwd = &options->local_forwards[options->num_local_forwards++]; 36518de8d7fSPeter Avalos 366cb5eb4f1SPeter Avalos fwd->listen_host = newfwd->listen_host; 36718de8d7fSPeter Avalos fwd->listen_port = newfwd->listen_port; 36836e94dc5SPeter Avalos fwd->listen_path = newfwd->listen_path; 369cb5eb4f1SPeter Avalos fwd->connect_host = newfwd->connect_host; 37018de8d7fSPeter Avalos fwd->connect_port = newfwd->connect_port; 37136e94dc5SPeter Avalos fwd->connect_path = newfwd->connect_path; 37218de8d7fSPeter Avalos } 37318de8d7fSPeter Avalos 37418de8d7fSPeter Avalos /* 37518de8d7fSPeter Avalos * Adds a remote TCP/IP port forward to options. Never returns if there is 37618de8d7fSPeter Avalos * an error. 37718de8d7fSPeter Avalos */ 37818de8d7fSPeter Avalos 37918de8d7fSPeter Avalos void 38036e94dc5SPeter Avalos add_remote_forward(Options *options, const struct Forward *newfwd) 38118de8d7fSPeter Avalos { 38236e94dc5SPeter Avalos struct Forward *fwd; 383e9778795SPeter Avalos int i; 384856ea928SPeter Avalos 385e9778795SPeter Avalos /* Don't add duplicates */ 386e9778795SPeter Avalos for (i = 0; i < options->num_remote_forwards; i++) { 387e9778795SPeter Avalos if (forward_equals(newfwd, options->remote_forwards + i)) 388e9778795SPeter Avalos return; 389e9778795SPeter Avalos } 390e9778795SPeter Avalos options->remote_forwards = xreallocarray(options->remote_forwards, 391856ea928SPeter Avalos options->num_remote_forwards + 1, 392856ea928SPeter Avalos sizeof(*options->remote_forwards)); 39318de8d7fSPeter Avalos fwd = &options->remote_forwards[options->num_remote_forwards++]; 39418de8d7fSPeter Avalos 395cb5eb4f1SPeter Avalos fwd->listen_host = newfwd->listen_host; 39618de8d7fSPeter Avalos fwd->listen_port = newfwd->listen_port; 39736e94dc5SPeter Avalos fwd->listen_path = newfwd->listen_path; 398cb5eb4f1SPeter Avalos fwd->connect_host = newfwd->connect_host; 39918de8d7fSPeter Avalos fwd->connect_port = newfwd->connect_port; 40036e94dc5SPeter Avalos fwd->connect_path = newfwd->connect_path; 40199e85e0dSPeter Avalos fwd->handle = newfwd->handle; 402856ea928SPeter Avalos fwd->allocated_port = 0; 40318de8d7fSPeter Avalos } 40418de8d7fSPeter Avalos 40518de8d7fSPeter Avalos static void 40618de8d7fSPeter Avalos clear_forwardings(Options *options) 40718de8d7fSPeter Avalos { 40818de8d7fSPeter Avalos int i; 40918de8d7fSPeter Avalos 41018de8d7fSPeter Avalos for (i = 0; i < options->num_local_forwards; i++) { 41136e94dc5SPeter Avalos free(options->local_forwards[i].listen_host); 41236e94dc5SPeter Avalos free(options->local_forwards[i].listen_path); 41336e94dc5SPeter Avalos free(options->local_forwards[i].connect_host); 41436e94dc5SPeter Avalos free(options->local_forwards[i].connect_path); 41518de8d7fSPeter Avalos } 416856ea928SPeter Avalos if (options->num_local_forwards > 0) { 41736e94dc5SPeter Avalos free(options->local_forwards); 418856ea928SPeter Avalos options->local_forwards = NULL; 419856ea928SPeter Avalos } 42018de8d7fSPeter Avalos options->num_local_forwards = 0; 42118de8d7fSPeter Avalos for (i = 0; i < options->num_remote_forwards; i++) { 42236e94dc5SPeter Avalos free(options->remote_forwards[i].listen_host); 42336e94dc5SPeter Avalos free(options->remote_forwards[i].listen_path); 42436e94dc5SPeter Avalos free(options->remote_forwards[i].connect_host); 42536e94dc5SPeter Avalos free(options->remote_forwards[i].connect_path); 42618de8d7fSPeter Avalos } 427856ea928SPeter Avalos if (options->num_remote_forwards > 0) { 42836e94dc5SPeter Avalos free(options->remote_forwards); 429856ea928SPeter Avalos options->remote_forwards = NULL; 430856ea928SPeter Avalos } 43118de8d7fSPeter Avalos options->num_remote_forwards = 0; 43218de8d7fSPeter Avalos options->tun_open = SSH_TUNMODE_NO; 43318de8d7fSPeter Avalos } 43418de8d7fSPeter Avalos 43536e94dc5SPeter Avalos void 436e9778795SPeter Avalos add_certificate_file(Options *options, const char *path, int userprovided) 437e9778795SPeter Avalos { 438e9778795SPeter Avalos int i; 439e9778795SPeter Avalos 440e9778795SPeter Avalos if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES) 441e9778795SPeter Avalos fatal("Too many certificate files specified (max %d)", 442e9778795SPeter Avalos SSH_MAX_CERTIFICATE_FILES); 443e9778795SPeter Avalos 444e9778795SPeter Avalos /* Avoid registering duplicates */ 445e9778795SPeter Avalos for (i = 0; i < options->num_certificate_files; i++) { 446e9778795SPeter Avalos if (options->certificate_file_userprovided[i] == userprovided && 447e9778795SPeter Avalos strcmp(options->certificate_files[i], path) == 0) { 448e9778795SPeter Avalos debug2("%s: ignoring duplicate key %s", __func__, path); 449e9778795SPeter Avalos return; 450e9778795SPeter Avalos } 451e9778795SPeter Avalos } 452e9778795SPeter Avalos 453e9778795SPeter Avalos options->certificate_file_userprovided[options->num_certificate_files] = 454e9778795SPeter Avalos userprovided; 455e9778795SPeter Avalos options->certificate_files[options->num_certificate_files++] = 456e9778795SPeter Avalos xstrdup(path); 457e9778795SPeter Avalos } 458e9778795SPeter Avalos 459e9778795SPeter Avalos void 46036e94dc5SPeter Avalos add_identity_file(Options *options, const char *dir, const char *filename, 46136e94dc5SPeter Avalos int userprovided) 46236e94dc5SPeter Avalos { 46336e94dc5SPeter Avalos char *path; 46436e94dc5SPeter Avalos int i; 46536e94dc5SPeter Avalos 46636e94dc5SPeter Avalos if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES) 46736e94dc5SPeter Avalos fatal("Too many identity files specified (max %d)", 46836e94dc5SPeter Avalos SSH_MAX_IDENTITY_FILES); 46936e94dc5SPeter Avalos 47036e94dc5SPeter Avalos if (dir == NULL) /* no dir, filename is absolute */ 47136e94dc5SPeter Avalos path = xstrdup(filename); 472ce74bacaSMatthew Dillon else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX) 473ce74bacaSMatthew Dillon fatal("Identity file path %s too long", path); 47436e94dc5SPeter Avalos 47536e94dc5SPeter Avalos /* Avoid registering duplicates */ 47636e94dc5SPeter Avalos for (i = 0; i < options->num_identity_files; i++) { 47736e94dc5SPeter Avalos if (options->identity_file_userprovided[i] == userprovided && 47836e94dc5SPeter Avalos strcmp(options->identity_files[i], path) == 0) { 47936e94dc5SPeter Avalos debug2("%s: ignoring duplicate key %s", __func__, path); 48036e94dc5SPeter Avalos free(path); 48136e94dc5SPeter Avalos return; 48236e94dc5SPeter Avalos } 48336e94dc5SPeter Avalos } 48436e94dc5SPeter Avalos 48536e94dc5SPeter Avalos options->identity_file_userprovided[options->num_identity_files] = 48636e94dc5SPeter Avalos userprovided; 48736e94dc5SPeter Avalos options->identity_files[options->num_identity_files++] = path; 48836e94dc5SPeter Avalos } 48936e94dc5SPeter Avalos 49036e94dc5SPeter Avalos int 49136e94dc5SPeter Avalos default_ssh_port(void) 49236e94dc5SPeter Avalos { 49336e94dc5SPeter Avalos static int port; 49436e94dc5SPeter Avalos struct servent *sp; 49536e94dc5SPeter Avalos 49636e94dc5SPeter Avalos if (port == 0) { 49736e94dc5SPeter Avalos sp = getservbyname(SSH_SERVICE_NAME, "tcp"); 49836e94dc5SPeter Avalos port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT; 49936e94dc5SPeter Avalos } 50036e94dc5SPeter Avalos return port; 50136e94dc5SPeter Avalos } 50236e94dc5SPeter Avalos 50336e94dc5SPeter Avalos /* 50436e94dc5SPeter Avalos * Execute a command in a shell. 50536e94dc5SPeter Avalos * Return its exit status or -1 on abnormal exit. 50636e94dc5SPeter Avalos */ 50736e94dc5SPeter Avalos static int 50836e94dc5SPeter Avalos execute_in_shell(const char *cmd) 50936e94dc5SPeter Avalos { 510e9778795SPeter Avalos char *shell; 51136e94dc5SPeter Avalos pid_t pid; 51236e94dc5SPeter Avalos int devnull, status; 51336e94dc5SPeter Avalos 51436e94dc5SPeter Avalos if ((shell = getenv("SHELL")) == NULL) 51536e94dc5SPeter Avalos shell = _PATH_BSHELL; 51636e94dc5SPeter Avalos 517*0cbfa66cSDaniel Fojt if (access(shell, X_OK) == -1) { 518*0cbfa66cSDaniel Fojt fatal("Shell \"%s\" is not executable: %s", 519*0cbfa66cSDaniel Fojt shell, strerror(errno)); 520*0cbfa66cSDaniel Fojt } 521*0cbfa66cSDaniel Fojt 52236e94dc5SPeter Avalos /* Need this to redirect subprocess stdin/out */ 52336e94dc5SPeter Avalos if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) 52436e94dc5SPeter Avalos fatal("open(/dev/null): %s", strerror(errno)); 52536e94dc5SPeter Avalos 52636e94dc5SPeter Avalos debug("Executing command: '%.500s'", cmd); 52736e94dc5SPeter Avalos 52836e94dc5SPeter Avalos /* Fork and execute the command. */ 52936e94dc5SPeter Avalos if ((pid = fork()) == 0) { 53036e94dc5SPeter Avalos char *argv[4]; 53136e94dc5SPeter Avalos 53236e94dc5SPeter Avalos /* Redirect child stdin and stdout. Leave stderr */ 53336e94dc5SPeter Avalos if (dup2(devnull, STDIN_FILENO) == -1) 53436e94dc5SPeter Avalos fatal("dup2: %s", strerror(errno)); 53536e94dc5SPeter Avalos if (dup2(devnull, STDOUT_FILENO) == -1) 53636e94dc5SPeter Avalos fatal("dup2: %s", strerror(errno)); 53736e94dc5SPeter Avalos if (devnull > STDERR_FILENO) 53836e94dc5SPeter Avalos close(devnull); 53936e94dc5SPeter Avalos closefrom(STDERR_FILENO + 1); 54036e94dc5SPeter Avalos 54136e94dc5SPeter Avalos argv[0] = shell; 54236e94dc5SPeter Avalos argv[1] = "-c"; 543e9778795SPeter Avalos argv[2] = xstrdup(cmd); 54436e94dc5SPeter Avalos argv[3] = NULL; 54536e94dc5SPeter Avalos 54636e94dc5SPeter Avalos execv(argv[0], argv); 54736e94dc5SPeter Avalos error("Unable to execute '%.100s': %s", cmd, strerror(errno)); 54836e94dc5SPeter Avalos /* Die with signal to make this error apparent to parent. */ 549*0cbfa66cSDaniel Fojt ssh_signal(SIGTERM, SIG_DFL); 55036e94dc5SPeter Avalos kill(getpid(), SIGTERM); 55136e94dc5SPeter Avalos _exit(1); 55236e94dc5SPeter Avalos } 55336e94dc5SPeter Avalos /* Parent. */ 554*0cbfa66cSDaniel Fojt if (pid == -1) 55536e94dc5SPeter Avalos fatal("%s: fork: %.100s", __func__, strerror(errno)); 55636e94dc5SPeter Avalos 55736e94dc5SPeter Avalos close(devnull); 55836e94dc5SPeter Avalos 55936e94dc5SPeter Avalos while (waitpid(pid, &status, 0) == -1) { 56036e94dc5SPeter Avalos if (errno != EINTR && errno != EAGAIN) 56136e94dc5SPeter Avalos fatal("%s: waitpid: %s", __func__, strerror(errno)); 56236e94dc5SPeter Avalos } 56336e94dc5SPeter Avalos if (!WIFEXITED(status)) { 56436e94dc5SPeter Avalos error("command '%.100s' exited abnormally", cmd); 56536e94dc5SPeter Avalos return -1; 56636e94dc5SPeter Avalos } 56736e94dc5SPeter Avalos debug3("command returned status %d", WEXITSTATUS(status)); 56836e94dc5SPeter Avalos return WEXITSTATUS(status); 56936e94dc5SPeter Avalos } 57036e94dc5SPeter Avalos 57136e94dc5SPeter Avalos /* 57236e94dc5SPeter Avalos * Parse and execute a Match directive. 57336e94dc5SPeter Avalos */ 57436e94dc5SPeter Avalos static int 57536e94dc5SPeter Avalos match_cfg_line(Options *options, char **condition, struct passwd *pw, 576664f4763Szrj const char *host_arg, const char *original_host, int final_pass, 577664f4763Szrj int *want_final_pass, const char *filename, int linenum) 57836e94dc5SPeter Avalos { 579e9778795SPeter Avalos char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria; 58036e94dc5SPeter Avalos const char *ruser; 581e9778795SPeter Avalos int r, port, this_result, result = 1, attributes = 0, negate; 58236e94dc5SPeter Avalos char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; 583664f4763Szrj char uidstr[32]; 58436e94dc5SPeter Avalos 58536e94dc5SPeter Avalos /* 58636e94dc5SPeter Avalos * Configuration is likely to be incomplete at this point so we 58736e94dc5SPeter Avalos * must be prepared to use default values. 58836e94dc5SPeter Avalos */ 58936e94dc5SPeter Avalos port = options->port <= 0 ? default_ssh_port() : options->port; 59036e94dc5SPeter Avalos ruser = options->user == NULL ? pw->pw_name : options->user; 591664f4763Szrj if (final_pass) { 592e9778795SPeter Avalos host = xstrdup(options->hostname); 593e9778795SPeter Avalos } else if (options->hostname != NULL) { 59436e94dc5SPeter Avalos /* NB. Please keep in sync with ssh.c:main() */ 59536e94dc5SPeter Avalos host = percent_expand(options->hostname, 59636e94dc5SPeter Avalos "h", host_arg, (char *)NULL); 597e9778795SPeter Avalos } else { 59836e94dc5SPeter Avalos host = xstrdup(host_arg); 599e9778795SPeter Avalos } 60036e94dc5SPeter Avalos 601e9778795SPeter Avalos debug2("checking match for '%s' host %s originally %s", 602e9778795SPeter Avalos cp, host, original_host); 603e9778795SPeter Avalos while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') { 604e9778795SPeter Avalos criteria = NULL; 605e9778795SPeter Avalos this_result = 1; 606e9778795SPeter Avalos if ((negate = attrib[0] == '!')) 607e9778795SPeter Avalos attrib++; 608e9778795SPeter Avalos /* criteria "all" and "canonical" have no argument */ 60936e94dc5SPeter Avalos if (strcasecmp(attrib, "all") == 0) { 610e9778795SPeter Avalos if (attributes > 1 || 61136e94dc5SPeter Avalos ((arg = strdelim(&cp)) != NULL && *arg != '\0')) { 612e9778795SPeter Avalos error("%.200s line %d: '%s' cannot be combined " 613e9778795SPeter Avalos "with other Match attributes", 614e9778795SPeter Avalos filename, linenum, oattrib); 61536e94dc5SPeter Avalos result = -1; 61636e94dc5SPeter Avalos goto out; 61736e94dc5SPeter Avalos } 618e9778795SPeter Avalos if (result) 619e9778795SPeter Avalos result = negate ? 0 : 1; 62036e94dc5SPeter Avalos goto out; 62136e94dc5SPeter Avalos } 622e9778795SPeter Avalos attributes++; 623664f4763Szrj if (strcasecmp(attrib, "canonical") == 0 || 624664f4763Szrj strcasecmp(attrib, "final") == 0) { 625664f4763Szrj /* 626664f4763Szrj * If the config requests "Match final" then remember 627664f4763Szrj * this so we can perform a second pass later. 628664f4763Szrj */ 629664f4763Szrj if (strcasecmp(attrib, "final") == 0 && 630664f4763Szrj want_final_pass != NULL) 631664f4763Szrj *want_final_pass = 1; 632664f4763Szrj r = !!final_pass; /* force bitmask member to boolean */ 633e9778795SPeter Avalos if (r == (negate ? 1 : 0)) 634e9778795SPeter Avalos this_result = result = 0; 635e9778795SPeter Avalos debug3("%.200s line %d: %smatched '%s'", 636e9778795SPeter Avalos filename, linenum, 637e9778795SPeter Avalos this_result ? "" : "not ", oattrib); 638e9778795SPeter Avalos continue; 639e9778795SPeter Avalos } 640e9778795SPeter Avalos /* All other criteria require an argument */ 64136e94dc5SPeter Avalos if ((arg = strdelim(&cp)) == NULL || *arg == '\0') { 64236e94dc5SPeter Avalos error("Missing Match criteria for %s", attrib); 64336e94dc5SPeter Avalos result = -1; 64436e94dc5SPeter Avalos goto out; 64536e94dc5SPeter Avalos } 64636e94dc5SPeter Avalos if (strcasecmp(attrib, "host") == 0) { 647e9778795SPeter Avalos criteria = xstrdup(host); 648e9778795SPeter Avalos r = match_hostname(host, arg) == 1; 649e9778795SPeter Avalos if (r == (negate ? 1 : 0)) 650e9778795SPeter Avalos this_result = result = 0; 65136e94dc5SPeter Avalos } else if (strcasecmp(attrib, "originalhost") == 0) { 652e9778795SPeter Avalos criteria = xstrdup(original_host); 653e9778795SPeter Avalos r = match_hostname(original_host, arg) == 1; 654e9778795SPeter Avalos if (r == (negate ? 1 : 0)) 655e9778795SPeter Avalos this_result = result = 0; 65636e94dc5SPeter Avalos } else if (strcasecmp(attrib, "user") == 0) { 657e9778795SPeter Avalos criteria = xstrdup(ruser); 658e9778795SPeter Avalos r = match_pattern_list(ruser, arg, 0) == 1; 659e9778795SPeter Avalos if (r == (negate ? 1 : 0)) 660e9778795SPeter Avalos this_result = result = 0; 66136e94dc5SPeter Avalos } else if (strcasecmp(attrib, "localuser") == 0) { 662e9778795SPeter Avalos criteria = xstrdup(pw->pw_name); 663e9778795SPeter Avalos r = match_pattern_list(pw->pw_name, arg, 0) == 1; 664e9778795SPeter Avalos if (r == (negate ? 1 : 0)) 665e9778795SPeter Avalos this_result = result = 0; 66636e94dc5SPeter Avalos } else if (strcasecmp(attrib, "exec") == 0) { 667*0cbfa66cSDaniel Fojt char *conn_hash_hex; 668*0cbfa66cSDaniel Fojt 66936e94dc5SPeter Avalos if (gethostname(thishost, sizeof(thishost)) == -1) 67036e94dc5SPeter Avalos fatal("gethostname: %s", strerror(errno)); 67136e94dc5SPeter Avalos strlcpy(shorthost, thishost, sizeof(shorthost)); 67236e94dc5SPeter Avalos shorthost[strcspn(thishost, ".")] = '\0'; 67336e94dc5SPeter Avalos snprintf(portstr, sizeof(portstr), "%d", port); 674664f4763Szrj snprintf(uidstr, sizeof(uidstr), "%llu", 675664f4763Szrj (unsigned long long)pw->pw_uid); 676*0cbfa66cSDaniel Fojt conn_hash_hex = ssh_connection_hash(thishost, host, 677*0cbfa66cSDaniel Fojt portstr, ruser); 67836e94dc5SPeter Avalos 67936e94dc5SPeter Avalos cmd = percent_expand(arg, 680*0cbfa66cSDaniel Fojt "C", conn_hash_hex, 68136e94dc5SPeter Avalos "L", shorthost, 68236e94dc5SPeter Avalos "d", pw->pw_dir, 68336e94dc5SPeter Avalos "h", host, 68436e94dc5SPeter Avalos "l", thishost, 685e9778795SPeter Avalos "n", original_host, 68636e94dc5SPeter Avalos "p", portstr, 68736e94dc5SPeter Avalos "r", ruser, 68836e94dc5SPeter Avalos "u", pw->pw_name, 689664f4763Szrj "i", uidstr, 69036e94dc5SPeter Avalos (char *)NULL); 691*0cbfa66cSDaniel Fojt free(conn_hash_hex); 69236e94dc5SPeter Avalos if (result != 1) { 69336e94dc5SPeter Avalos /* skip execution if prior predicate failed */ 694e9778795SPeter Avalos debug3("%.200s line %d: skipped exec " 695e9778795SPeter Avalos "\"%.100s\"", filename, linenum, cmd); 696e9778795SPeter Avalos free(cmd); 697e9778795SPeter Avalos continue; 698e9778795SPeter Avalos } 69936e94dc5SPeter Avalos r = execute_in_shell(cmd); 70036e94dc5SPeter Avalos if (r == -1) { 70136e94dc5SPeter Avalos fatal("%.200s line %d: match exec " 70236e94dc5SPeter Avalos "'%.100s' error", filename, 70336e94dc5SPeter Avalos linenum, cmd); 70436e94dc5SPeter Avalos } 705e9778795SPeter Avalos criteria = xstrdup(cmd); 70636e94dc5SPeter Avalos free(cmd); 707e9778795SPeter Avalos /* Force exit status to boolean */ 708e9778795SPeter Avalos r = r == 0; 709e9778795SPeter Avalos if (r == (negate ? 1 : 0)) 710e9778795SPeter Avalos this_result = result = 0; 71136e94dc5SPeter Avalos } else { 71236e94dc5SPeter Avalos error("Unsupported Match attribute %s", attrib); 71336e94dc5SPeter Avalos result = -1; 71436e94dc5SPeter Avalos goto out; 71536e94dc5SPeter Avalos } 716e9778795SPeter Avalos debug3("%.200s line %d: %smatched '%s \"%.100s\"' ", 717e9778795SPeter Avalos filename, linenum, this_result ? "": "not ", 718e9778795SPeter Avalos oattrib, criteria); 719e9778795SPeter Avalos free(criteria); 72036e94dc5SPeter Avalos } 72136e94dc5SPeter Avalos if (attributes == 0) { 72236e94dc5SPeter Avalos error("One or more attributes required for Match"); 72336e94dc5SPeter Avalos result = -1; 72436e94dc5SPeter Avalos goto out; 72536e94dc5SPeter Avalos } 72636e94dc5SPeter Avalos out: 727e9778795SPeter Avalos if (result != -1) 728e9778795SPeter Avalos debug2("match %sfound", result ? "" : "not "); 729e9778795SPeter Avalos *condition = cp; 73036e94dc5SPeter Avalos free(host); 73136e94dc5SPeter Avalos return result; 73236e94dc5SPeter Avalos } 73336e94dc5SPeter Avalos 734664f4763Szrj /* Remove environment variable by pattern */ 73536e94dc5SPeter Avalos static void 736664f4763Szrj rm_env(Options *options, const char *arg, const char *filename, int linenum) 73736e94dc5SPeter Avalos { 738664f4763Szrj int i, j; 739664f4763Szrj char *cp; 74036e94dc5SPeter Avalos 741664f4763Szrj /* Remove an environment variable */ 742664f4763Szrj for (i = 0; i < options->num_send_env; ) { 743664f4763Szrj cp = xstrdup(options->send_env[i]); 744664f4763Szrj if (!match_pattern(cp, arg + 1)) { 745664f4763Szrj free(cp); 746664f4763Szrj i++; 747664f4763Szrj continue; 74836e94dc5SPeter Avalos } 749664f4763Szrj debug3("%s line %d: removing environment %s", 750664f4763Szrj filename, linenum, cp); 751664f4763Szrj free(cp); 752664f4763Szrj free(options->send_env[i]); 753664f4763Szrj options->send_env[i] = NULL; 754664f4763Szrj for (j = i; j < options->num_send_env - 1; j++) { 755664f4763Szrj options->send_env[j] = options->send_env[j + 1]; 756664f4763Szrj options->send_env[j + 1] = NULL; 757664f4763Szrj } 758664f4763Szrj options->num_send_env--; 759664f4763Szrj /* NB. don't increment i */ 760664f4763Szrj } 76136e94dc5SPeter Avalos } 76236e94dc5SPeter Avalos 76318de8d7fSPeter Avalos /* 76418de8d7fSPeter Avalos * Returns the number of the token pointed to by cp or oBadOption. 76518de8d7fSPeter Avalos */ 76618de8d7fSPeter Avalos static OpCodes 76736e94dc5SPeter Avalos parse_token(const char *cp, const char *filename, int linenum, 76836e94dc5SPeter Avalos const char *ignored_unknown) 76918de8d7fSPeter Avalos { 77036e94dc5SPeter Avalos int i; 77118de8d7fSPeter Avalos 77218de8d7fSPeter Avalos for (i = 0; keywords[i].name; i++) 77336e94dc5SPeter Avalos if (strcmp(cp, keywords[i].name) == 0) 77418de8d7fSPeter Avalos return keywords[i].opcode; 775e9778795SPeter Avalos if (ignored_unknown != NULL && 776e9778795SPeter Avalos match_pattern_list(cp, ignored_unknown, 1) == 1) 77736e94dc5SPeter Avalos return oIgnoredUnknownOption; 77818de8d7fSPeter Avalos error("%s: line %d: Bad configuration option: %s", 77918de8d7fSPeter Avalos filename, linenum, cp); 78018de8d7fSPeter Avalos return oBadOption; 78118de8d7fSPeter Avalos } 78218de8d7fSPeter Avalos 78336e94dc5SPeter Avalos /* Multistate option parsing */ 78436e94dc5SPeter Avalos struct multistate { 78536e94dc5SPeter Avalos char *key; 78636e94dc5SPeter Avalos int value; 78736e94dc5SPeter Avalos }; 78836e94dc5SPeter Avalos static const struct multistate multistate_flag[] = { 78936e94dc5SPeter Avalos { "true", 1 }, 79036e94dc5SPeter Avalos { "false", 0 }, 79136e94dc5SPeter Avalos { "yes", 1 }, 79236e94dc5SPeter Avalos { "no", 0 }, 79336e94dc5SPeter Avalos { NULL, -1 } 79436e94dc5SPeter Avalos }; 79536e94dc5SPeter Avalos static const struct multistate multistate_yesnoask[] = { 79636e94dc5SPeter Avalos { "true", 1 }, 79736e94dc5SPeter Avalos { "false", 0 }, 79836e94dc5SPeter Avalos { "yes", 1 }, 79936e94dc5SPeter Avalos { "no", 0 }, 80036e94dc5SPeter Avalos { "ask", 2 }, 80136e94dc5SPeter Avalos { NULL, -1 } 80236e94dc5SPeter Avalos }; 803ce74bacaSMatthew Dillon static const struct multistate multistate_strict_hostkey[] = { 804ce74bacaSMatthew Dillon { "true", SSH_STRICT_HOSTKEY_YES }, 805ce74bacaSMatthew Dillon { "false", SSH_STRICT_HOSTKEY_OFF }, 806ce74bacaSMatthew Dillon { "yes", SSH_STRICT_HOSTKEY_YES }, 807ce74bacaSMatthew Dillon { "no", SSH_STRICT_HOSTKEY_OFF }, 808ce74bacaSMatthew Dillon { "ask", SSH_STRICT_HOSTKEY_ASK }, 809ce74bacaSMatthew Dillon { "off", SSH_STRICT_HOSTKEY_OFF }, 810ce74bacaSMatthew Dillon { "accept-new", SSH_STRICT_HOSTKEY_NEW }, 811ce74bacaSMatthew Dillon { NULL, -1 } 812ce74bacaSMatthew Dillon }; 813e9778795SPeter Avalos static const struct multistate multistate_yesnoaskconfirm[] = { 814e9778795SPeter Avalos { "true", 1 }, 815e9778795SPeter Avalos { "false", 0 }, 816e9778795SPeter Avalos { "yes", 1 }, 817e9778795SPeter Avalos { "no", 0 }, 818e9778795SPeter Avalos { "ask", 2 }, 819e9778795SPeter Avalos { "confirm", 3 }, 820e9778795SPeter Avalos { NULL, -1 } 821e9778795SPeter Avalos }; 82236e94dc5SPeter Avalos static const struct multistate multistate_addressfamily[] = { 82336e94dc5SPeter Avalos { "inet", AF_INET }, 82436e94dc5SPeter Avalos { "inet6", AF_INET6 }, 82536e94dc5SPeter Avalos { "any", AF_UNSPEC }, 82636e94dc5SPeter Avalos { NULL, -1 } 82736e94dc5SPeter Avalos }; 82836e94dc5SPeter Avalos static const struct multistate multistate_controlmaster[] = { 82936e94dc5SPeter Avalos { "true", SSHCTL_MASTER_YES }, 83036e94dc5SPeter Avalos { "yes", SSHCTL_MASTER_YES }, 83136e94dc5SPeter Avalos { "false", SSHCTL_MASTER_NO }, 83236e94dc5SPeter Avalos { "no", SSHCTL_MASTER_NO }, 83336e94dc5SPeter Avalos { "auto", SSHCTL_MASTER_AUTO }, 83436e94dc5SPeter Avalos { "ask", SSHCTL_MASTER_ASK }, 83536e94dc5SPeter Avalos { "autoask", SSHCTL_MASTER_AUTO_ASK }, 83636e94dc5SPeter Avalos { NULL, -1 } 83736e94dc5SPeter Avalos }; 83836e94dc5SPeter Avalos static const struct multistate multistate_tunnel[] = { 83936e94dc5SPeter Avalos { "ethernet", SSH_TUNMODE_ETHERNET }, 84036e94dc5SPeter Avalos { "point-to-point", SSH_TUNMODE_POINTOPOINT }, 84136e94dc5SPeter Avalos { "true", SSH_TUNMODE_DEFAULT }, 84236e94dc5SPeter Avalos { "yes", SSH_TUNMODE_DEFAULT }, 84336e94dc5SPeter Avalos { "false", SSH_TUNMODE_NO }, 84436e94dc5SPeter Avalos { "no", SSH_TUNMODE_NO }, 84536e94dc5SPeter Avalos { NULL, -1 } 84636e94dc5SPeter Avalos }; 84736e94dc5SPeter Avalos static const struct multistate multistate_requesttty[] = { 84836e94dc5SPeter Avalos { "true", REQUEST_TTY_YES }, 84936e94dc5SPeter Avalos { "yes", REQUEST_TTY_YES }, 85036e94dc5SPeter Avalos { "false", REQUEST_TTY_NO }, 85136e94dc5SPeter Avalos { "no", REQUEST_TTY_NO }, 85236e94dc5SPeter Avalos { "force", REQUEST_TTY_FORCE }, 85336e94dc5SPeter Avalos { "auto", REQUEST_TTY_AUTO }, 85436e94dc5SPeter Avalos { NULL, -1 } 85536e94dc5SPeter Avalos }; 85636e94dc5SPeter Avalos static const struct multistate multistate_canonicalizehostname[] = { 85736e94dc5SPeter Avalos { "true", SSH_CANONICALISE_YES }, 85836e94dc5SPeter Avalos { "false", SSH_CANONICALISE_NO }, 85936e94dc5SPeter Avalos { "yes", SSH_CANONICALISE_YES }, 86036e94dc5SPeter Avalos { "no", SSH_CANONICALISE_NO }, 86136e94dc5SPeter Avalos { "always", SSH_CANONICALISE_ALWAYS }, 86236e94dc5SPeter Avalos { NULL, -1 } 86336e94dc5SPeter Avalos }; 864*0cbfa66cSDaniel Fojt static const struct multistate multistate_compression[] = { 865*0cbfa66cSDaniel Fojt #ifdef WITH_ZLIB 866*0cbfa66cSDaniel Fojt { "yes", COMP_ZLIB }, 867*0cbfa66cSDaniel Fojt #endif 868*0cbfa66cSDaniel Fojt { "no", COMP_NONE }, 869*0cbfa66cSDaniel Fojt { NULL, -1 } 870*0cbfa66cSDaniel Fojt }; 87136e94dc5SPeter Avalos 87218de8d7fSPeter Avalos /* 87318de8d7fSPeter Avalos * Processes a single option line as used in the configuration files. This 87418de8d7fSPeter Avalos * only sets those values that have not already been set. 87518de8d7fSPeter Avalos */ 87618de8d7fSPeter Avalos int 87736e94dc5SPeter Avalos process_config_line(Options *options, struct passwd *pw, const char *host, 878e9778795SPeter Avalos const char *original_host, char *line, const char *filename, 879e9778795SPeter Avalos int linenum, int *activep, int flags) 880e9778795SPeter Avalos { 881e9778795SPeter Avalos return process_config_line_depth(options, pw, host, original_host, 882664f4763Szrj line, filename, linenum, activep, flags, NULL, 0); 883e9778795SPeter Avalos } 884e9778795SPeter Avalos 885e9778795SPeter Avalos #define WHITESPACE " \t\r\n" 886e9778795SPeter Avalos static int 887e9778795SPeter Avalos process_config_line_depth(Options *options, struct passwd *pw, const char *host, 888e9778795SPeter Avalos const char *original_host, char *line, const char *filename, 889664f4763Szrj int linenum, int *activep, int flags, int *want_final_pass, int depth) 89018de8d7fSPeter Avalos { 8911c188a7fSPeter Avalos char *s, **charptr, *endofnumber, *keyword, *arg, *arg2; 8921c188a7fSPeter Avalos char **cpptr, fwdarg[256]; 89336e94dc5SPeter Avalos u_int i, *uintptr, max_entries = 0; 894e9778795SPeter Avalos int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0; 895ce74bacaSMatthew Dillon int remotefwd, dynamicfwd; 89618de8d7fSPeter Avalos LogLevel *log_level_ptr; 897ce74bacaSMatthew Dillon SyslogFacility *log_facility_ptr; 89836e94dc5SPeter Avalos long long val64; 89918de8d7fSPeter Avalos size_t len; 90036e94dc5SPeter Avalos struct Forward fwd; 90136e94dc5SPeter Avalos const struct multistate *multistate_ptr; 90236e94dc5SPeter Avalos struct allowed_cname *cname; 903e9778795SPeter Avalos glob_t gl; 904664f4763Szrj const char *errstr; 90536e94dc5SPeter Avalos 90636e94dc5SPeter Avalos if (activep == NULL) { /* We are processing a command line directive */ 90736e94dc5SPeter Avalos cmdline = 1; 90836e94dc5SPeter Avalos activep = &cmdline; 90936e94dc5SPeter Avalos } 91018de8d7fSPeter Avalos 911ce74bacaSMatthew Dillon /* Strip trailing whitespace. Allow \f (form feed) at EOL only */ 912e9778795SPeter Avalos if ((len = strlen(line)) == 0) 913e9778795SPeter Avalos return 0; 914e9778795SPeter Avalos for (len--; len > 0; len--) { 915ce74bacaSMatthew Dillon if (strchr(WHITESPACE "\f", line[len]) == NULL) 91618de8d7fSPeter Avalos break; 91718de8d7fSPeter Avalos line[len] = '\0'; 91818de8d7fSPeter Avalos } 91918de8d7fSPeter Avalos 92018de8d7fSPeter Avalos s = line; 92118de8d7fSPeter Avalos /* Get the keyword. (Each line is supposed to begin with a keyword). */ 92218de8d7fSPeter Avalos if ((keyword = strdelim(&s)) == NULL) 92318de8d7fSPeter Avalos return 0; 92418de8d7fSPeter Avalos /* Ignore leading whitespace. */ 92518de8d7fSPeter Avalos if (*keyword == '\0') 92618de8d7fSPeter Avalos keyword = strdelim(&s); 92718de8d7fSPeter Avalos if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#') 92818de8d7fSPeter Avalos return 0; 92936e94dc5SPeter Avalos /* Match lowercase keyword */ 93036e94dc5SPeter Avalos lowercase(keyword); 93118de8d7fSPeter Avalos 93236e94dc5SPeter Avalos opcode = parse_token(keyword, filename, linenum, 93336e94dc5SPeter Avalos options->ignored_unknown); 93418de8d7fSPeter Avalos 93518de8d7fSPeter Avalos switch (opcode) { 93618de8d7fSPeter Avalos case oBadOption: 93718de8d7fSPeter Avalos /* don't panic, but count bad options */ 93818de8d7fSPeter Avalos return -1; 939ce74bacaSMatthew Dillon case oIgnore: 940ce74bacaSMatthew Dillon return 0; 94136e94dc5SPeter Avalos case oIgnoredUnknownOption: 94236e94dc5SPeter Avalos debug("%s line %d: Ignored unknown option \"%s\"", 94336e94dc5SPeter Avalos filename, linenum, keyword); 94436e94dc5SPeter Avalos return 0; 94518de8d7fSPeter Avalos case oConnectTimeout: 94618de8d7fSPeter Avalos intptr = &options->connection_timeout; 94718de8d7fSPeter Avalos parse_time: 94818de8d7fSPeter Avalos arg = strdelim(&s); 94918de8d7fSPeter Avalos if (!arg || *arg == '\0') 95018de8d7fSPeter Avalos fatal("%s line %d: missing time value.", 95118de8d7fSPeter Avalos filename, linenum); 952e9778795SPeter Avalos if (strcmp(arg, "none") == 0) 953e9778795SPeter Avalos value = -1; 954e9778795SPeter Avalos else if ((value = convtime(arg)) == -1) 95518de8d7fSPeter Avalos fatal("%s line %d: invalid time value.", 95618de8d7fSPeter Avalos filename, linenum); 95718de8d7fSPeter Avalos if (*activep && *intptr == -1) 95818de8d7fSPeter Avalos *intptr = value; 95918de8d7fSPeter Avalos break; 96018de8d7fSPeter Avalos 96118de8d7fSPeter Avalos case oForwardAgent: 96218de8d7fSPeter Avalos intptr = &options->forward_agent; 963*0cbfa66cSDaniel Fojt 964*0cbfa66cSDaniel Fojt arg = strdelim(&s); 965*0cbfa66cSDaniel Fojt if (!arg || *arg == '\0') 966*0cbfa66cSDaniel Fojt fatal("%s line %d: missing argument.", 967*0cbfa66cSDaniel Fojt filename, linenum); 968*0cbfa66cSDaniel Fojt 969*0cbfa66cSDaniel Fojt value = -1; 970*0cbfa66cSDaniel Fojt multistate_ptr = multistate_flag; 971*0cbfa66cSDaniel Fojt for (i = 0; multistate_ptr[i].key != NULL; i++) { 972*0cbfa66cSDaniel Fojt if (strcasecmp(arg, multistate_ptr[i].key) == 0) { 973*0cbfa66cSDaniel Fojt value = multistate_ptr[i].value; 974*0cbfa66cSDaniel Fojt break; 975*0cbfa66cSDaniel Fojt } 976*0cbfa66cSDaniel Fojt } 977*0cbfa66cSDaniel Fojt if (value != -1) { 978*0cbfa66cSDaniel Fojt if (*activep && *intptr == -1) 979*0cbfa66cSDaniel Fojt *intptr = value; 980*0cbfa66cSDaniel Fojt break; 981*0cbfa66cSDaniel Fojt } 982*0cbfa66cSDaniel Fojt /* ForwardAgent wasn't 'yes' or 'no', assume a path */ 983*0cbfa66cSDaniel Fojt if (*activep && *intptr == -1) 984*0cbfa66cSDaniel Fojt *intptr = 1; 985*0cbfa66cSDaniel Fojt 986*0cbfa66cSDaniel Fojt charptr = &options->forward_agent_sock_path; 987*0cbfa66cSDaniel Fojt goto parse_agent_path; 988*0cbfa66cSDaniel Fojt 989*0cbfa66cSDaniel Fojt case oForwardX11: 990*0cbfa66cSDaniel Fojt intptr = &options->forward_x11; 99118de8d7fSPeter Avalos parse_flag: 99236e94dc5SPeter Avalos multistate_ptr = multistate_flag; 99336e94dc5SPeter Avalos parse_multistate: 99418de8d7fSPeter Avalos arg = strdelim(&s); 99518de8d7fSPeter Avalos if (!arg || *arg == '\0') 99636e94dc5SPeter Avalos fatal("%s line %d: missing argument.", 99736e94dc5SPeter Avalos filename, linenum); 99836e94dc5SPeter Avalos value = -1; 99936e94dc5SPeter Avalos for (i = 0; multistate_ptr[i].key != NULL; i++) { 100036e94dc5SPeter Avalos if (strcasecmp(arg, multistate_ptr[i].key) == 0) { 100136e94dc5SPeter Avalos value = multistate_ptr[i].value; 100236e94dc5SPeter Avalos break; 100336e94dc5SPeter Avalos } 100436e94dc5SPeter Avalos } 100536e94dc5SPeter Avalos if (value == -1) 100636e94dc5SPeter Avalos fatal("%s line %d: unsupported option \"%s\".", 100736e94dc5SPeter Avalos filename, linenum, arg); 100818de8d7fSPeter Avalos if (*activep && *intptr == -1) 100918de8d7fSPeter Avalos *intptr = value; 101018de8d7fSPeter Avalos break; 101118de8d7fSPeter Avalos 101218de8d7fSPeter Avalos case oForwardX11Trusted: 101318de8d7fSPeter Avalos intptr = &options->forward_x11_trusted; 101418de8d7fSPeter Avalos goto parse_flag; 101518de8d7fSPeter Avalos 1016856ea928SPeter Avalos case oForwardX11Timeout: 1017856ea928SPeter Avalos intptr = &options->forward_x11_timeout; 1018856ea928SPeter Avalos goto parse_time; 1019856ea928SPeter Avalos 102018de8d7fSPeter Avalos case oGatewayPorts: 102136e94dc5SPeter Avalos intptr = &options->fwd_opts.gateway_ports; 102218de8d7fSPeter Avalos goto parse_flag; 102318de8d7fSPeter Avalos 102418de8d7fSPeter Avalos case oExitOnForwardFailure: 102518de8d7fSPeter Avalos intptr = &options->exit_on_forward_failure; 102618de8d7fSPeter Avalos goto parse_flag; 102718de8d7fSPeter Avalos 102818de8d7fSPeter Avalos case oPasswordAuthentication: 102918de8d7fSPeter Avalos intptr = &options->password_authentication; 103018de8d7fSPeter Avalos goto parse_flag; 103118de8d7fSPeter Avalos 103218de8d7fSPeter Avalos case oKbdInteractiveAuthentication: 103318de8d7fSPeter Avalos intptr = &options->kbd_interactive_authentication; 103418de8d7fSPeter Avalos goto parse_flag; 103518de8d7fSPeter Avalos 103618de8d7fSPeter Avalos case oKbdInteractiveDevices: 103718de8d7fSPeter Avalos charptr = &options->kbd_interactive_devices; 103818de8d7fSPeter Avalos goto parse_string; 103918de8d7fSPeter Avalos 104018de8d7fSPeter Avalos case oPubkeyAuthentication: 104118de8d7fSPeter Avalos intptr = &options->pubkey_authentication; 104218de8d7fSPeter Avalos goto parse_flag; 104318de8d7fSPeter Avalos 104418de8d7fSPeter Avalos case oHostbasedAuthentication: 104518de8d7fSPeter Avalos intptr = &options->hostbased_authentication; 104618de8d7fSPeter Avalos goto parse_flag; 104718de8d7fSPeter Avalos 104818de8d7fSPeter Avalos case oChallengeResponseAuthentication: 104918de8d7fSPeter Avalos intptr = &options->challenge_response_authentication; 105018de8d7fSPeter Avalos goto parse_flag; 105118de8d7fSPeter Avalos 105218de8d7fSPeter Avalos case oGssAuthentication: 105318de8d7fSPeter Avalos intptr = &options->gss_authentication; 105418de8d7fSPeter Avalos goto parse_flag; 105518de8d7fSPeter Avalos 105618de8d7fSPeter Avalos case oGssDelegateCreds: 105718de8d7fSPeter Avalos intptr = &options->gss_deleg_creds; 105818de8d7fSPeter Avalos goto parse_flag; 105918de8d7fSPeter Avalos 106018de8d7fSPeter Avalos case oBatchMode: 106118de8d7fSPeter Avalos intptr = &options->batch_mode; 106218de8d7fSPeter Avalos goto parse_flag; 106318de8d7fSPeter Avalos 106418de8d7fSPeter Avalos case oCheckHostIP: 106518de8d7fSPeter Avalos intptr = &options->check_host_ip; 106618de8d7fSPeter Avalos goto parse_flag; 106718de8d7fSPeter Avalos 106818de8d7fSPeter Avalos case oVerifyHostKeyDNS: 106918de8d7fSPeter Avalos intptr = &options->verify_host_key_dns; 107036e94dc5SPeter Avalos multistate_ptr = multistate_yesnoask; 107136e94dc5SPeter Avalos goto parse_multistate; 107218de8d7fSPeter Avalos 107318de8d7fSPeter Avalos case oStrictHostKeyChecking: 107418de8d7fSPeter Avalos intptr = &options->strict_host_key_checking; 1075ce74bacaSMatthew Dillon multistate_ptr = multistate_strict_hostkey; 107636e94dc5SPeter Avalos goto parse_multistate; 107718de8d7fSPeter Avalos 107818de8d7fSPeter Avalos case oCompression: 107918de8d7fSPeter Avalos intptr = &options->compression; 1080*0cbfa66cSDaniel Fojt multistate_ptr = multistate_compression; 1081*0cbfa66cSDaniel Fojt goto parse_multistate; 108218de8d7fSPeter Avalos 108318de8d7fSPeter Avalos case oTCPKeepAlive: 108418de8d7fSPeter Avalos intptr = &options->tcp_keep_alive; 108518de8d7fSPeter Avalos goto parse_flag; 108618de8d7fSPeter Avalos 108718de8d7fSPeter Avalos case oNoHostAuthenticationForLocalhost: 108818de8d7fSPeter Avalos intptr = &options->no_host_authentication_for_localhost; 108918de8d7fSPeter Avalos goto parse_flag; 109018de8d7fSPeter Avalos 109118de8d7fSPeter Avalos case oNumberOfPasswordPrompts: 109218de8d7fSPeter Avalos intptr = &options->number_of_password_prompts; 109318de8d7fSPeter Avalos goto parse_int; 109418de8d7fSPeter Avalos 109518de8d7fSPeter Avalos case oRekeyLimit: 109618de8d7fSPeter Avalos arg = strdelim(&s); 109718de8d7fSPeter Avalos if (!arg || *arg == '\0') 109836e94dc5SPeter Avalos fatal("%.200s line %d: Missing argument.", filename, 109936e94dc5SPeter Avalos linenum); 110036e94dc5SPeter Avalos if (strcmp(arg, "default") == 0) { 110136e94dc5SPeter Avalos val64 = 0; 110236e94dc5SPeter Avalos } else { 110336e94dc5SPeter Avalos if (scan_scaled(arg, &val64) == -1) 110436e94dc5SPeter Avalos fatal("%.200s line %d: Bad number '%s': %s", 110536e94dc5SPeter Avalos filename, linenum, arg, strerror(errno)); 110636e94dc5SPeter Avalos if (val64 != 0 && val64 < 16) 110718de8d7fSPeter Avalos fatal("%.200s line %d: RekeyLimit too small", 110818de8d7fSPeter Avalos filename, linenum); 110936e94dc5SPeter Avalos } 111018de8d7fSPeter Avalos if (*activep && options->rekey_limit == -1) 1111e9778795SPeter Avalos options->rekey_limit = val64; 111236e94dc5SPeter Avalos if (s != NULL) { /* optional rekey interval present */ 111336e94dc5SPeter Avalos if (strcmp(s, "none") == 0) { 111436e94dc5SPeter Avalos (void)strdelim(&s); /* discard */ 111536e94dc5SPeter Avalos break; 111636e94dc5SPeter Avalos } 111736e94dc5SPeter Avalos intptr = &options->rekey_interval; 111836e94dc5SPeter Avalos goto parse_time; 111936e94dc5SPeter Avalos } 112018de8d7fSPeter Avalos break; 112118de8d7fSPeter Avalos 112218de8d7fSPeter Avalos case oIdentityFile: 112318de8d7fSPeter Avalos arg = strdelim(&s); 112418de8d7fSPeter Avalos if (!arg || *arg == '\0') 112518de8d7fSPeter Avalos fatal("%.200s line %d: Missing argument.", filename, linenum); 112618de8d7fSPeter Avalos if (*activep) { 112718de8d7fSPeter Avalos intptr = &options->num_identity_files; 112818de8d7fSPeter Avalos if (*intptr >= SSH_MAX_IDENTITY_FILES) 112918de8d7fSPeter Avalos fatal("%.200s line %d: Too many identity files specified (max %d).", 113018de8d7fSPeter Avalos filename, linenum, SSH_MAX_IDENTITY_FILES); 1131e9778795SPeter Avalos add_identity_file(options, NULL, 1132e9778795SPeter Avalos arg, flags & SSHCONF_USERCONF); 1133e9778795SPeter Avalos } 1134e9778795SPeter Avalos break; 1135e9778795SPeter Avalos 1136e9778795SPeter Avalos case oCertificateFile: 1137e9778795SPeter Avalos arg = strdelim(&s); 1138e9778795SPeter Avalos if (!arg || *arg == '\0') 1139e9778795SPeter Avalos fatal("%.200s line %d: Missing argument.", 1140e9778795SPeter Avalos filename, linenum); 1141e9778795SPeter Avalos if (*activep) { 1142e9778795SPeter Avalos intptr = &options->num_certificate_files; 1143e9778795SPeter Avalos if (*intptr >= SSH_MAX_CERTIFICATE_FILES) { 1144e9778795SPeter Avalos fatal("%.200s line %d: Too many certificate " 1145e9778795SPeter Avalos "files specified (max %d).", 1146e9778795SPeter Avalos filename, linenum, 1147e9778795SPeter Avalos SSH_MAX_CERTIFICATE_FILES); 1148e9778795SPeter Avalos } 1149e9778795SPeter Avalos add_certificate_file(options, arg, 1150e9778795SPeter Avalos flags & SSHCONF_USERCONF); 115118de8d7fSPeter Avalos } 115218de8d7fSPeter Avalos break; 115318de8d7fSPeter Avalos 115418de8d7fSPeter Avalos case oXAuthLocation: 115518de8d7fSPeter Avalos charptr=&options->xauth_location; 115618de8d7fSPeter Avalos goto parse_string; 115718de8d7fSPeter Avalos 115818de8d7fSPeter Avalos case oUser: 115918de8d7fSPeter Avalos charptr = &options->user; 116018de8d7fSPeter Avalos parse_string: 116118de8d7fSPeter Avalos arg = strdelim(&s); 116218de8d7fSPeter Avalos if (!arg || *arg == '\0') 11631c188a7fSPeter Avalos fatal("%.200s line %d: Missing argument.", 11641c188a7fSPeter Avalos filename, linenum); 116518de8d7fSPeter Avalos if (*activep && *charptr == NULL) 116618de8d7fSPeter Avalos *charptr = xstrdup(arg); 116718de8d7fSPeter Avalos break; 116818de8d7fSPeter Avalos 116918de8d7fSPeter Avalos case oGlobalKnownHostsFile: 11701c188a7fSPeter Avalos cpptr = (char **)&options->system_hostfiles; 11711c188a7fSPeter Avalos uintptr = &options->num_system_hostfiles; 11721c188a7fSPeter Avalos max_entries = SSH_MAX_HOSTS_FILES; 11731c188a7fSPeter Avalos parse_char_array: 11741c188a7fSPeter Avalos if (*activep && *uintptr == 0) { 11751c188a7fSPeter Avalos while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 11761c188a7fSPeter Avalos if ((*uintptr) >= max_entries) 11771c188a7fSPeter Avalos fatal("%s line %d: " 1178*0cbfa66cSDaniel Fojt "too many known hosts files.", 11791c188a7fSPeter Avalos filename, linenum); 11801c188a7fSPeter Avalos cpptr[(*uintptr)++] = xstrdup(arg); 11811c188a7fSPeter Avalos } 11821c188a7fSPeter Avalos } 11831c188a7fSPeter Avalos return 0; 118418de8d7fSPeter Avalos 118518de8d7fSPeter Avalos case oUserKnownHostsFile: 11861c188a7fSPeter Avalos cpptr = (char **)&options->user_hostfiles; 11871c188a7fSPeter Avalos uintptr = &options->num_user_hostfiles; 11881c188a7fSPeter Avalos max_entries = SSH_MAX_HOSTS_FILES; 11891c188a7fSPeter Avalos goto parse_char_array; 119018de8d7fSPeter Avalos 1191*0cbfa66cSDaniel Fojt case oHostname: 119218de8d7fSPeter Avalos charptr = &options->hostname; 119318de8d7fSPeter Avalos goto parse_string; 119418de8d7fSPeter Avalos 119518de8d7fSPeter Avalos case oHostKeyAlias: 119618de8d7fSPeter Avalos charptr = &options->host_key_alias; 119718de8d7fSPeter Avalos goto parse_string; 119818de8d7fSPeter Avalos 119918de8d7fSPeter Avalos case oPreferredAuthentications: 120018de8d7fSPeter Avalos charptr = &options->preferred_authentications; 120118de8d7fSPeter Avalos goto parse_string; 120218de8d7fSPeter Avalos 120318de8d7fSPeter Avalos case oBindAddress: 120418de8d7fSPeter Avalos charptr = &options->bind_address; 120518de8d7fSPeter Avalos goto parse_string; 120618de8d7fSPeter Avalos 1207664f4763Szrj case oBindInterface: 1208664f4763Szrj charptr = &options->bind_interface; 1209664f4763Szrj goto parse_string; 1210664f4763Szrj 1211856ea928SPeter Avalos case oPKCS11Provider: 1212856ea928SPeter Avalos charptr = &options->pkcs11_provider; 121318de8d7fSPeter Avalos goto parse_string; 121418de8d7fSPeter Avalos 1215*0cbfa66cSDaniel Fojt case oSecurityKeyProvider: 1216*0cbfa66cSDaniel Fojt charptr = &options->sk_provider; 1217*0cbfa66cSDaniel Fojt goto parse_string; 1218*0cbfa66cSDaniel Fojt 121918de8d7fSPeter Avalos case oProxyCommand: 122018de8d7fSPeter Avalos charptr = &options->proxy_command; 1221e9778795SPeter Avalos /* Ignore ProxyCommand if ProxyJump already specified */ 1222e9778795SPeter Avalos if (options->jump_host != NULL) 1223e9778795SPeter Avalos charptr = &options->jump_host; /* Skip below */ 122418de8d7fSPeter Avalos parse_command: 122518de8d7fSPeter Avalos if (s == NULL) 122618de8d7fSPeter Avalos fatal("%.200s line %d: Missing argument.", filename, linenum); 122718de8d7fSPeter Avalos len = strspn(s, WHITESPACE "="); 122818de8d7fSPeter Avalos if (*activep && *charptr == NULL) 122918de8d7fSPeter Avalos *charptr = xstrdup(s + len); 123018de8d7fSPeter Avalos return 0; 123118de8d7fSPeter Avalos 1232e9778795SPeter Avalos case oProxyJump: 1233e9778795SPeter Avalos if (s == NULL) { 1234e9778795SPeter Avalos fatal("%.200s line %d: Missing argument.", 1235e9778795SPeter Avalos filename, linenum); 1236e9778795SPeter Avalos } 1237e9778795SPeter Avalos len = strspn(s, WHITESPACE "="); 1238e9778795SPeter Avalos if (parse_jump(s + len, options, *activep) == -1) { 1239e9778795SPeter Avalos fatal("%.200s line %d: Invalid ProxyJump \"%s\"", 1240e9778795SPeter Avalos filename, linenum, s + len); 1241e9778795SPeter Avalos } 1242e9778795SPeter Avalos return 0; 1243e9778795SPeter Avalos 124418de8d7fSPeter Avalos case oPort: 124518de8d7fSPeter Avalos arg = strdelim(&s); 124618de8d7fSPeter Avalos if (!arg || *arg == '\0') 1247664f4763Szrj fatal("%.200s line %d: Missing argument.", 1248664f4763Szrj filename, linenum); 1249664f4763Szrj value = a2port(arg); 1250664f4763Szrj if (value <= 0) 1251664f4763Szrj fatal("%.200s line %d: Bad port '%s'.", 1252664f4763Szrj filename, linenum, arg); 1253664f4763Szrj if (*activep && options->port == -1) 1254664f4763Szrj options->port = value; 125518de8d7fSPeter Avalos break; 125618de8d7fSPeter Avalos 125718de8d7fSPeter Avalos case oConnectionAttempts: 125818de8d7fSPeter Avalos intptr = &options->connection_attempts; 1259664f4763Szrj parse_int: 1260664f4763Szrj arg = strdelim(&s); 1261664f4763Szrj if ((errstr = atoi_err(arg, &value)) != NULL) 1262664f4763Szrj fatal("%s line %d: integer value %s.", 1263664f4763Szrj filename, linenum, errstr); 1264664f4763Szrj if (*activep && *intptr == -1) 1265664f4763Szrj *intptr = value; 1266664f4763Szrj break; 126718de8d7fSPeter Avalos 126818de8d7fSPeter Avalos case oCiphers: 126918de8d7fSPeter Avalos arg = strdelim(&s); 127018de8d7fSPeter Avalos if (!arg || *arg == '\0') 127118de8d7fSPeter Avalos fatal("%.200s line %d: Missing argument.", filename, linenum); 1272*0cbfa66cSDaniel Fojt if (*arg != '-' && 1273*0cbfa66cSDaniel Fojt !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)) 127418de8d7fSPeter Avalos fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.", 127518de8d7fSPeter Avalos filename, linenum, arg ? arg : "<NONE>"); 127618de8d7fSPeter Avalos if (*activep && options->ciphers == NULL) 127718de8d7fSPeter Avalos options->ciphers = xstrdup(arg); 127818de8d7fSPeter Avalos break; 127918de8d7fSPeter Avalos 128018de8d7fSPeter Avalos case oMacs: 128118de8d7fSPeter Avalos arg = strdelim(&s); 128218de8d7fSPeter Avalos if (!arg || *arg == '\0') 128318de8d7fSPeter Avalos fatal("%.200s line %d: Missing argument.", filename, linenum); 1284*0cbfa66cSDaniel Fojt if (*arg != '-' && 1285*0cbfa66cSDaniel Fojt !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)) 1286*0cbfa66cSDaniel Fojt fatal("%.200s line %d: Bad SSH2 MAC spec '%s'.", 128718de8d7fSPeter Avalos filename, linenum, arg ? arg : "<NONE>"); 128818de8d7fSPeter Avalos if (*activep && options->macs == NULL) 128918de8d7fSPeter Avalos options->macs = xstrdup(arg); 129018de8d7fSPeter Avalos break; 129118de8d7fSPeter Avalos 12929f304aafSPeter Avalos case oKexAlgorithms: 12939f304aafSPeter Avalos arg = strdelim(&s); 12949f304aafSPeter Avalos if (!arg || *arg == '\0') 12959f304aafSPeter Avalos fatal("%.200s line %d: Missing argument.", 12969f304aafSPeter Avalos filename, linenum); 1297ce74bacaSMatthew Dillon if (*arg != '-' && 1298*0cbfa66cSDaniel Fojt !kex_names_valid(*arg == '+' || *arg == '^' ? 1299*0cbfa66cSDaniel Fojt arg + 1 : arg)) 13009f304aafSPeter Avalos fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.", 13019f304aafSPeter Avalos filename, linenum, arg ? arg : "<NONE>"); 13029f304aafSPeter Avalos if (*activep && options->kex_algorithms == NULL) 13039f304aafSPeter Avalos options->kex_algorithms = xstrdup(arg); 13049f304aafSPeter Avalos break; 13059f304aafSPeter Avalos 130618de8d7fSPeter Avalos case oHostKeyAlgorithms: 1307e9778795SPeter Avalos charptr = &options->hostkeyalgorithms; 1308e9778795SPeter Avalos parse_keytypes: 130918de8d7fSPeter Avalos arg = strdelim(&s); 131018de8d7fSPeter Avalos if (!arg || *arg == '\0') 1311e9778795SPeter Avalos fatal("%.200s line %d: Missing argument.", 1312e9778795SPeter Avalos filename, linenum); 1313ce74bacaSMatthew Dillon if (*arg != '-' && 1314*0cbfa66cSDaniel Fojt !sshkey_names_valid2(*arg == '+' || *arg == '^' ? 1315*0cbfa66cSDaniel Fojt arg + 1 : arg, 1)) 1316e9778795SPeter Avalos fatal("%s line %d: Bad key types '%s'.", 131718de8d7fSPeter Avalos filename, linenum, arg ? arg : "<NONE>"); 1318e9778795SPeter Avalos if (*activep && *charptr == NULL) 1319e9778795SPeter Avalos *charptr = xstrdup(arg); 132018de8d7fSPeter Avalos break; 132118de8d7fSPeter Avalos 1322664f4763Szrj case oCASignatureAlgorithms: 1323664f4763Szrj charptr = &options->ca_sign_algorithms; 1324664f4763Szrj goto parse_keytypes; 1325664f4763Szrj 132618de8d7fSPeter Avalos case oLogLevel: 132718de8d7fSPeter Avalos log_level_ptr = &options->log_level; 132818de8d7fSPeter Avalos arg = strdelim(&s); 132918de8d7fSPeter Avalos value = log_level_number(arg); 133018de8d7fSPeter Avalos if (value == SYSLOG_LEVEL_NOT_SET) 133118de8d7fSPeter Avalos fatal("%.200s line %d: unsupported log level '%s'", 133218de8d7fSPeter Avalos filename, linenum, arg ? arg : "<NONE>"); 133318de8d7fSPeter Avalos if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET) 133418de8d7fSPeter Avalos *log_level_ptr = (LogLevel) value; 133518de8d7fSPeter Avalos break; 133618de8d7fSPeter Avalos 1337ce74bacaSMatthew Dillon case oLogFacility: 1338ce74bacaSMatthew Dillon log_facility_ptr = &options->log_facility; 1339ce74bacaSMatthew Dillon arg = strdelim(&s); 1340ce74bacaSMatthew Dillon value = log_facility_number(arg); 1341ce74bacaSMatthew Dillon if (value == SYSLOG_FACILITY_NOT_SET) 1342ce74bacaSMatthew Dillon fatal("%.200s line %d: unsupported log facility '%s'", 1343ce74bacaSMatthew Dillon filename, linenum, arg ? arg : "<NONE>"); 1344ce74bacaSMatthew Dillon if (*log_facility_ptr == -1) 1345ce74bacaSMatthew Dillon *log_facility_ptr = (SyslogFacility) value; 1346ce74bacaSMatthew Dillon break; 1347ce74bacaSMatthew Dillon 134818de8d7fSPeter Avalos case oLocalForward: 134918de8d7fSPeter Avalos case oRemoteForward: 1350cb5eb4f1SPeter Avalos case oDynamicForward: 135118de8d7fSPeter Avalos arg = strdelim(&s); 135218de8d7fSPeter Avalos if (arg == NULL || *arg == '\0') 135318de8d7fSPeter Avalos fatal("%.200s line %d: Missing port argument.", 135418de8d7fSPeter Avalos filename, linenum); 1355cb5eb4f1SPeter Avalos 1356ce74bacaSMatthew Dillon remotefwd = (opcode == oRemoteForward); 1357ce74bacaSMatthew Dillon dynamicfwd = (opcode == oDynamicForward); 1358ce74bacaSMatthew Dillon 1359ce74bacaSMatthew Dillon if (!dynamicfwd) { 136018de8d7fSPeter Avalos arg2 = strdelim(&s); 1361ce74bacaSMatthew Dillon if (arg2 == NULL || *arg2 == '\0') { 1362ce74bacaSMatthew Dillon if (remotefwd) 1363ce74bacaSMatthew Dillon dynamicfwd = 1; 1364ce74bacaSMatthew Dillon else 1365ce74bacaSMatthew Dillon fatal("%.200s line %d: Missing target " 1366ce74bacaSMatthew Dillon "argument.", filename, linenum); 1367ce74bacaSMatthew Dillon } else { 136818de8d7fSPeter Avalos /* construct a string for parse_forward */ 1369ce74bacaSMatthew Dillon snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, 1370ce74bacaSMatthew Dillon arg2); 1371cb5eb4f1SPeter Avalos } 1372ce74bacaSMatthew Dillon } 1373ce74bacaSMatthew Dillon if (dynamicfwd) 1374ce74bacaSMatthew Dillon strlcpy(fwdarg, arg, sizeof(fwdarg)); 137518de8d7fSPeter Avalos 1376ce74bacaSMatthew Dillon if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0) 137718de8d7fSPeter Avalos fatal("%.200s line %d: Bad forwarding specification.", 137818de8d7fSPeter Avalos filename, linenum); 137918de8d7fSPeter Avalos 138018de8d7fSPeter Avalos if (*activep) { 1381ce74bacaSMatthew Dillon if (remotefwd) { 138218de8d7fSPeter Avalos add_remote_forward(options, &fwd); 1383ce74bacaSMatthew Dillon } else { 1384ce74bacaSMatthew Dillon add_local_forward(options, &fwd); 1385ce74bacaSMatthew Dillon } 138618de8d7fSPeter Avalos } 138718de8d7fSPeter Avalos break; 138818de8d7fSPeter Avalos 138918de8d7fSPeter Avalos case oClearAllForwardings: 139018de8d7fSPeter Avalos intptr = &options->clear_forwardings; 139118de8d7fSPeter Avalos goto parse_flag; 139218de8d7fSPeter Avalos 139318de8d7fSPeter Avalos case oHost: 139436e94dc5SPeter Avalos if (cmdline) 139536e94dc5SPeter Avalos fatal("Host directive not supported as a command-line " 139636e94dc5SPeter Avalos "option"); 139718de8d7fSPeter Avalos *activep = 0; 13981c188a7fSPeter Avalos arg2 = NULL; 13991c188a7fSPeter Avalos while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 1400e9778795SPeter Avalos if ((flags & SSHCONF_NEVERMATCH) != 0) 1401e9778795SPeter Avalos break; 14021c188a7fSPeter Avalos negated = *arg == '!'; 14031c188a7fSPeter Avalos if (negated) 14041c188a7fSPeter Avalos arg++; 140518de8d7fSPeter Avalos if (match_pattern(host, arg)) { 14061c188a7fSPeter Avalos if (negated) { 14071c188a7fSPeter Avalos debug("%.200s line %d: Skipping Host " 14081c188a7fSPeter Avalos "block because of negated match " 14091c188a7fSPeter Avalos "for %.100s", filename, linenum, 14101c188a7fSPeter Avalos arg); 14111c188a7fSPeter Avalos *activep = 0; 141218de8d7fSPeter Avalos break; 141318de8d7fSPeter Avalos } 14141c188a7fSPeter Avalos if (!*activep) 14151c188a7fSPeter Avalos arg2 = arg; /* logged below */ 14161c188a7fSPeter Avalos *activep = 1; 14171c188a7fSPeter Avalos } 14181c188a7fSPeter Avalos } 14191c188a7fSPeter Avalos if (*activep) 14201c188a7fSPeter Avalos debug("%.200s line %d: Applying options for %.100s", 14211c188a7fSPeter Avalos filename, linenum, arg2); 142218de8d7fSPeter Avalos /* Avoid garbage check below, as strdelim is done. */ 142318de8d7fSPeter Avalos return 0; 142418de8d7fSPeter Avalos 142536e94dc5SPeter Avalos case oMatch: 142636e94dc5SPeter Avalos if (cmdline) 142736e94dc5SPeter Avalos fatal("Host directive not supported as a command-line " 142836e94dc5SPeter Avalos "option"); 1429e9778795SPeter Avalos value = match_cfg_line(options, &s, pw, host, original_host, 1430664f4763Szrj flags & SSHCONF_FINAL, want_final_pass, 1431664f4763Szrj filename, linenum); 143236e94dc5SPeter Avalos if (value < 0) 143336e94dc5SPeter Avalos fatal("%.200s line %d: Bad Match condition", filename, 143436e94dc5SPeter Avalos linenum); 1435e9778795SPeter Avalos *activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value; 143636e94dc5SPeter Avalos break; 143736e94dc5SPeter Avalos 143818de8d7fSPeter Avalos case oEscapeChar: 143918de8d7fSPeter Avalos intptr = &options->escape_char; 144018de8d7fSPeter Avalos arg = strdelim(&s); 144118de8d7fSPeter Avalos if (!arg || *arg == '\0') 144218de8d7fSPeter Avalos fatal("%.200s line %d: Missing argument.", filename, linenum); 1443e9778795SPeter Avalos if (strcmp(arg, "none") == 0) 1444e9778795SPeter Avalos value = SSH_ESCAPECHAR_NONE; 1445e9778795SPeter Avalos else if (arg[1] == '\0') 1446e9778795SPeter Avalos value = (u_char) arg[0]; 1447e9778795SPeter Avalos else if (arg[0] == '^' && arg[2] == 0 && 144818de8d7fSPeter Avalos (u_char) arg[1] >= 64 && (u_char) arg[1] < 128) 144918de8d7fSPeter Avalos value = (u_char) arg[1] & 31; 145018de8d7fSPeter Avalos else { 145118de8d7fSPeter Avalos fatal("%.200s line %d: Bad escape character.", 145218de8d7fSPeter Avalos filename, linenum); 145318de8d7fSPeter Avalos /* NOTREACHED */ 145418de8d7fSPeter Avalos value = 0; /* Avoid compiler warning. */ 145518de8d7fSPeter Avalos } 145618de8d7fSPeter Avalos if (*activep && *intptr == -1) 145718de8d7fSPeter Avalos *intptr = value; 145818de8d7fSPeter Avalos break; 145918de8d7fSPeter Avalos 146018de8d7fSPeter Avalos case oAddressFamily: 146118de8d7fSPeter Avalos intptr = &options->address_family; 146236e94dc5SPeter Avalos multistate_ptr = multistate_addressfamily; 146336e94dc5SPeter Avalos goto parse_multistate; 146418de8d7fSPeter Avalos 146518de8d7fSPeter Avalos case oEnableSSHKeysign: 146618de8d7fSPeter Avalos intptr = &options->enable_ssh_keysign; 146718de8d7fSPeter Avalos goto parse_flag; 146818de8d7fSPeter Avalos 146918de8d7fSPeter Avalos case oIdentitiesOnly: 147018de8d7fSPeter Avalos intptr = &options->identities_only; 147118de8d7fSPeter Avalos goto parse_flag; 147218de8d7fSPeter Avalos 147318de8d7fSPeter Avalos case oServerAliveInterval: 147418de8d7fSPeter Avalos intptr = &options->server_alive_interval; 147518de8d7fSPeter Avalos goto parse_time; 147618de8d7fSPeter Avalos 147718de8d7fSPeter Avalos case oServerAliveCountMax: 147818de8d7fSPeter Avalos intptr = &options->server_alive_count_max; 147918de8d7fSPeter Avalos goto parse_int; 148018de8d7fSPeter Avalos 148118de8d7fSPeter Avalos case oSendEnv: 148218de8d7fSPeter Avalos while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 148318de8d7fSPeter Avalos if (strchr(arg, '=') != NULL) 148418de8d7fSPeter Avalos fatal("%s line %d: Invalid environment name.", 148518de8d7fSPeter Avalos filename, linenum); 148618de8d7fSPeter Avalos if (!*activep) 148718de8d7fSPeter Avalos continue; 1488664f4763Szrj if (*arg == '-') { 1489664f4763Szrj /* Removing an env var */ 1490664f4763Szrj rm_env(options, arg, filename, linenum); 1491664f4763Szrj continue; 1492664f4763Szrj } else { 1493664f4763Szrj /* Adding an env var */ 1494664f4763Szrj if (options->num_send_env >= INT_MAX) 149518de8d7fSPeter Avalos fatal("%s line %d: too many send env.", 149618de8d7fSPeter Avalos filename, linenum); 1497664f4763Szrj options->send_env = xrecallocarray( 1498664f4763Szrj options->send_env, options->num_send_env, 1499664f4763Szrj options->num_send_env + 1, 1500664f4763Szrj sizeof(*options->send_env)); 150118de8d7fSPeter Avalos options->send_env[options->num_send_env++] = 150218de8d7fSPeter Avalos xstrdup(arg); 150318de8d7fSPeter Avalos } 1504664f4763Szrj } 1505664f4763Szrj break; 1506664f4763Szrj 1507664f4763Szrj case oSetEnv: 1508664f4763Szrj value = options->num_setenv; 1509664f4763Szrj while ((arg = strdelimw(&s)) != NULL && *arg != '\0') { 1510664f4763Szrj if (strchr(arg, '=') == NULL) 1511664f4763Szrj fatal("%s line %d: Invalid SetEnv.", 1512664f4763Szrj filename, linenum); 1513664f4763Szrj if (!*activep || value != 0) 1514664f4763Szrj continue; 1515664f4763Szrj /* Adding a setenv var */ 1516664f4763Szrj if (options->num_setenv >= INT_MAX) 1517664f4763Szrj fatal("%s line %d: too many SetEnv.", 1518664f4763Szrj filename, linenum); 1519664f4763Szrj options->setenv = xrecallocarray( 1520664f4763Szrj options->setenv, options->num_setenv, 1521664f4763Szrj options->num_setenv + 1, sizeof(*options->setenv)); 1522664f4763Szrj options->setenv[options->num_setenv++] = xstrdup(arg); 1523664f4763Szrj } 152418de8d7fSPeter Avalos break; 152518de8d7fSPeter Avalos 152618de8d7fSPeter Avalos case oControlPath: 152718de8d7fSPeter Avalos charptr = &options->control_path; 152818de8d7fSPeter Avalos goto parse_string; 152918de8d7fSPeter Avalos 153018de8d7fSPeter Avalos case oControlMaster: 153118de8d7fSPeter Avalos intptr = &options->control_master; 153236e94dc5SPeter Avalos multistate_ptr = multistate_controlmaster; 153336e94dc5SPeter Avalos goto parse_multistate; 153418de8d7fSPeter Avalos 1535856ea928SPeter Avalos case oControlPersist: 1536856ea928SPeter Avalos /* no/false/yes/true, or a time spec */ 1537856ea928SPeter Avalos intptr = &options->control_persist; 1538856ea928SPeter Avalos arg = strdelim(&s); 1539856ea928SPeter Avalos if (!arg || *arg == '\0') 1540856ea928SPeter Avalos fatal("%.200s line %d: Missing ControlPersist" 1541856ea928SPeter Avalos " argument.", filename, linenum); 1542856ea928SPeter Avalos value = 0; 1543856ea928SPeter Avalos value2 = 0; /* timeout */ 1544856ea928SPeter Avalos if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 1545856ea928SPeter Avalos value = 0; 1546856ea928SPeter Avalos else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 1547856ea928SPeter Avalos value = 1; 1548856ea928SPeter Avalos else if ((value2 = convtime(arg)) >= 0) 1549856ea928SPeter Avalos value = 1; 1550856ea928SPeter Avalos else 1551856ea928SPeter Avalos fatal("%.200s line %d: Bad ControlPersist argument.", 1552856ea928SPeter Avalos filename, linenum); 1553856ea928SPeter Avalos if (*activep && *intptr == -1) { 1554856ea928SPeter Avalos *intptr = value; 1555856ea928SPeter Avalos options->control_persist_timeout = value2; 1556856ea928SPeter Avalos } 1557856ea928SPeter Avalos break; 1558856ea928SPeter Avalos 155918de8d7fSPeter Avalos case oHashKnownHosts: 156018de8d7fSPeter Avalos intptr = &options->hash_known_hosts; 156118de8d7fSPeter Avalos goto parse_flag; 156218de8d7fSPeter Avalos 156318de8d7fSPeter Avalos case oTunnel: 156418de8d7fSPeter Avalos intptr = &options->tun_open; 156536e94dc5SPeter Avalos multistate_ptr = multistate_tunnel; 156636e94dc5SPeter Avalos goto parse_multistate; 156718de8d7fSPeter Avalos 156818de8d7fSPeter Avalos case oTunnelDevice: 156918de8d7fSPeter Avalos arg = strdelim(&s); 157018de8d7fSPeter Avalos if (!arg || *arg == '\0') 157118de8d7fSPeter Avalos fatal("%.200s line %d: Missing argument.", filename, linenum); 157218de8d7fSPeter Avalos value = a2tun(arg, &value2); 157318de8d7fSPeter Avalos if (value == SSH_TUNID_ERR) 157418de8d7fSPeter Avalos fatal("%.200s line %d: Bad tun device.", filename, linenum); 157518de8d7fSPeter Avalos if (*activep) { 157618de8d7fSPeter Avalos options->tun_local = value; 157718de8d7fSPeter Avalos options->tun_remote = value2; 157818de8d7fSPeter Avalos } 157918de8d7fSPeter Avalos break; 158018de8d7fSPeter Avalos 158118de8d7fSPeter Avalos case oLocalCommand: 158218de8d7fSPeter Avalos charptr = &options->local_command; 158318de8d7fSPeter Avalos goto parse_command; 158418de8d7fSPeter Avalos 158518de8d7fSPeter Avalos case oPermitLocalCommand: 158618de8d7fSPeter Avalos intptr = &options->permit_local_command; 158718de8d7fSPeter Avalos goto parse_flag; 158818de8d7fSPeter Avalos 1589ce74bacaSMatthew Dillon case oRemoteCommand: 1590ce74bacaSMatthew Dillon charptr = &options->remote_command; 1591ce74bacaSMatthew Dillon goto parse_command; 1592ce74bacaSMatthew Dillon 159318de8d7fSPeter Avalos case oVisualHostKey: 159418de8d7fSPeter Avalos intptr = &options->visual_host_key; 159518de8d7fSPeter Avalos goto parse_flag; 159618de8d7fSPeter Avalos 1597e9778795SPeter Avalos case oInclude: 1598e9778795SPeter Avalos if (cmdline) 1599e9778795SPeter Avalos fatal("Include directive not supported as a " 1600e9778795SPeter Avalos "command-line option"); 1601e9778795SPeter Avalos value = 0; 1602e9778795SPeter Avalos while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 1603e9778795SPeter Avalos /* 1604e9778795SPeter Avalos * Ensure all paths are anchored. User configuration 1605e9778795SPeter Avalos * files may begin with '~/' but system configurations 1606e9778795SPeter Avalos * must not. If the path is relative, then treat it 1607e9778795SPeter Avalos * as living in ~/.ssh for user configurations or 1608e9778795SPeter Avalos * /etc/ssh for system ones. 1609e9778795SPeter Avalos */ 1610e9778795SPeter Avalos if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0) 1611e9778795SPeter Avalos fatal("%.200s line %d: bad include path %s.", 1612e9778795SPeter Avalos filename, linenum, arg); 1613664f4763Szrj if (!path_absolute(arg) && *arg != '~') { 1614e9778795SPeter Avalos xasprintf(&arg2, "%s/%s", 1615e9778795SPeter Avalos (flags & SSHCONF_USERCONF) ? 1616e9778795SPeter Avalos "~/" _PATH_SSH_USER_DIR : SSHDIR, arg); 1617e9778795SPeter Avalos } else 1618e9778795SPeter Avalos arg2 = xstrdup(arg); 1619e9778795SPeter Avalos memset(&gl, 0, sizeof(gl)); 1620e9778795SPeter Avalos r = glob(arg2, GLOB_TILDE, NULL, &gl); 1621e9778795SPeter Avalos if (r == GLOB_NOMATCH) { 1622e9778795SPeter Avalos debug("%.200s line %d: include %s matched no " 1623e9778795SPeter Avalos "files",filename, linenum, arg2); 1624ce74bacaSMatthew Dillon free(arg2); 1625e9778795SPeter Avalos continue; 1626*0cbfa66cSDaniel Fojt } else if (r != 0) 1627e9778795SPeter Avalos fatal("%.200s line %d: glob failed for %s.", 1628e9778795SPeter Avalos filename, linenum, arg2); 1629e9778795SPeter Avalos free(arg2); 1630e9778795SPeter Avalos oactive = *activep; 1631*0cbfa66cSDaniel Fojt for (i = 0; i < gl.gl_pathc; i++) { 1632e9778795SPeter Avalos debug3("%.200s line %d: Including file %s " 1633e9778795SPeter Avalos "depth %d%s", filename, linenum, 1634e9778795SPeter Avalos gl.gl_pathv[i], depth, 1635e9778795SPeter Avalos oactive ? "" : " (parse only)"); 1636e9778795SPeter Avalos r = read_config_file_depth(gl.gl_pathv[i], 1637e9778795SPeter Avalos pw, host, original_host, options, 1638e9778795SPeter Avalos flags | SSHCONF_CHECKPERM | 1639e9778795SPeter Avalos (oactive ? 0 : SSHCONF_NEVERMATCH), 1640664f4763Szrj activep, want_final_pass, depth + 1); 1641ce74bacaSMatthew Dillon if (r != 1 && errno != ENOENT) { 1642ce74bacaSMatthew Dillon fatal("Can't open user config file " 1643ce74bacaSMatthew Dillon "%.100s: %.100s", gl.gl_pathv[i], 1644ce74bacaSMatthew Dillon strerror(errno)); 1645ce74bacaSMatthew Dillon } 1646e9778795SPeter Avalos /* 1647e9778795SPeter Avalos * don't let Match in includes clobber the 1648e9778795SPeter Avalos * containing file's Match state. 1649e9778795SPeter Avalos */ 1650e9778795SPeter Avalos *activep = oactive; 1651e9778795SPeter Avalos if (r != 1) 1652e9778795SPeter Avalos value = -1; 1653e9778795SPeter Avalos } 1654e9778795SPeter Avalos globfree(&gl); 1655e9778795SPeter Avalos } 1656e9778795SPeter Avalos if (value != 0) 1657e9778795SPeter Avalos return value; 1658e9778795SPeter Avalos break; 1659e9778795SPeter Avalos 16609f304aafSPeter Avalos case oIPQoS: 16619f304aafSPeter Avalos arg = strdelim(&s); 16629f304aafSPeter Avalos if ((value = parse_ipqos(arg)) == -1) 16639f304aafSPeter Avalos fatal("%s line %d: Bad IPQoS value: %s", 16649f304aafSPeter Avalos filename, linenum, arg); 16659f304aafSPeter Avalos arg = strdelim(&s); 16669f304aafSPeter Avalos if (arg == NULL) 16679f304aafSPeter Avalos value2 = value; 16689f304aafSPeter Avalos else if ((value2 = parse_ipqos(arg)) == -1) 16699f304aafSPeter Avalos fatal("%s line %d: Bad IPQoS value: %s", 16709f304aafSPeter Avalos filename, linenum, arg); 16719f304aafSPeter Avalos if (*activep) { 16729f304aafSPeter Avalos options->ip_qos_interactive = value; 16739f304aafSPeter Avalos options->ip_qos_bulk = value2; 16749f304aafSPeter Avalos } 16759f304aafSPeter Avalos break; 16769f304aafSPeter Avalos 16771c188a7fSPeter Avalos case oRequestTTY: 167836e94dc5SPeter Avalos intptr = &options->request_tty; 167936e94dc5SPeter Avalos multistate_ptr = multistate_requesttty; 168036e94dc5SPeter Avalos goto parse_multistate; 168136e94dc5SPeter Avalos 168236e94dc5SPeter Avalos case oIgnoreUnknown: 168336e94dc5SPeter Avalos charptr = &options->ignored_unknown; 168436e94dc5SPeter Avalos goto parse_string; 168536e94dc5SPeter Avalos 168636e94dc5SPeter Avalos case oProxyUseFdpass: 168736e94dc5SPeter Avalos intptr = &options->proxy_use_fdpass; 168836e94dc5SPeter Avalos goto parse_flag; 168936e94dc5SPeter Avalos 169036e94dc5SPeter Avalos case oCanonicalDomains: 169136e94dc5SPeter Avalos value = options->num_canonical_domains != 0; 169236e94dc5SPeter Avalos while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 1693664f4763Szrj if (!valid_domain(arg, 1, &errstr)) { 1694664f4763Szrj fatal("%s line %d: %s", filename, linenum, 1695664f4763Szrj errstr); 1696664f4763Szrj } 169736e94dc5SPeter Avalos if (!*activep || value) 169836e94dc5SPeter Avalos continue; 169936e94dc5SPeter Avalos if (options->num_canonical_domains >= MAX_CANON_DOMAINS) 170036e94dc5SPeter Avalos fatal("%s line %d: too many hostname suffixes.", 170136e94dc5SPeter Avalos filename, linenum); 170236e94dc5SPeter Avalos options->canonical_domains[ 170336e94dc5SPeter Avalos options->num_canonical_domains++] = xstrdup(arg); 170436e94dc5SPeter Avalos } 170536e94dc5SPeter Avalos break; 170636e94dc5SPeter Avalos 170736e94dc5SPeter Avalos case oCanonicalizePermittedCNAMEs: 170836e94dc5SPeter Avalos value = options->num_permitted_cnames != 0; 170936e94dc5SPeter Avalos while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 171036e94dc5SPeter Avalos /* Either '*' for everything or 'list:list' */ 171136e94dc5SPeter Avalos if (strcmp(arg, "*") == 0) 171236e94dc5SPeter Avalos arg2 = arg; 171336e94dc5SPeter Avalos else { 171436e94dc5SPeter Avalos lowercase(arg); 171536e94dc5SPeter Avalos if ((arg2 = strchr(arg, ':')) == NULL || 171636e94dc5SPeter Avalos arg2[1] == '\0') { 171736e94dc5SPeter Avalos fatal("%s line %d: " 171836e94dc5SPeter Avalos "Invalid permitted CNAME \"%s\"", 171936e94dc5SPeter Avalos filename, linenum, arg); 172036e94dc5SPeter Avalos } 172136e94dc5SPeter Avalos *arg2 = '\0'; 172236e94dc5SPeter Avalos arg2++; 172336e94dc5SPeter Avalos } 172436e94dc5SPeter Avalos if (!*activep || value) 172536e94dc5SPeter Avalos continue; 172636e94dc5SPeter Avalos if (options->num_permitted_cnames >= MAX_CANON_DOMAINS) 172736e94dc5SPeter Avalos fatal("%s line %d: too many permitted CNAMEs.", 172836e94dc5SPeter Avalos filename, linenum); 172936e94dc5SPeter Avalos cname = options->permitted_cnames + 173036e94dc5SPeter Avalos options->num_permitted_cnames++; 173136e94dc5SPeter Avalos cname->source_list = xstrdup(arg); 173236e94dc5SPeter Avalos cname->target_list = xstrdup(arg2); 173336e94dc5SPeter Avalos } 173436e94dc5SPeter Avalos break; 173536e94dc5SPeter Avalos 173636e94dc5SPeter Avalos case oCanonicalizeHostname: 173736e94dc5SPeter Avalos intptr = &options->canonicalize_hostname; 173836e94dc5SPeter Avalos multistate_ptr = multistate_canonicalizehostname; 173936e94dc5SPeter Avalos goto parse_multistate; 174036e94dc5SPeter Avalos 174136e94dc5SPeter Avalos case oCanonicalizeMaxDots: 174236e94dc5SPeter Avalos intptr = &options->canonicalize_max_dots; 174336e94dc5SPeter Avalos goto parse_int; 174436e94dc5SPeter Avalos 174536e94dc5SPeter Avalos case oCanonicalizeFallbackLocal: 174636e94dc5SPeter Avalos intptr = &options->canonicalize_fallback_local; 174736e94dc5SPeter Avalos goto parse_flag; 174836e94dc5SPeter Avalos 174936e94dc5SPeter Avalos case oStreamLocalBindMask: 17501c188a7fSPeter Avalos arg = strdelim(&s); 17511c188a7fSPeter Avalos if (!arg || *arg == '\0') 175236e94dc5SPeter Avalos fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum); 175336e94dc5SPeter Avalos /* Parse mode in octal format */ 175436e94dc5SPeter Avalos value = strtol(arg, &endofnumber, 8); 175536e94dc5SPeter Avalos if (arg == endofnumber || value < 0 || value > 0777) 175636e94dc5SPeter Avalos fatal("%.200s line %d: Bad mask.", filename, linenum); 175736e94dc5SPeter Avalos options->fwd_opts.streamlocal_bind_mask = (mode_t)value; 17581c188a7fSPeter Avalos break; 17591c188a7fSPeter Avalos 176036e94dc5SPeter Avalos case oStreamLocalBindUnlink: 176136e94dc5SPeter Avalos intptr = &options->fwd_opts.streamlocal_bind_unlink; 176236e94dc5SPeter Avalos goto parse_flag; 176336e94dc5SPeter Avalos 1764e9778795SPeter Avalos case oRevokedHostKeys: 1765e9778795SPeter Avalos charptr = &options->revoked_host_keys; 1766e9778795SPeter Avalos goto parse_string; 1767e9778795SPeter Avalos 1768e9778795SPeter Avalos case oFingerprintHash: 1769e9778795SPeter Avalos intptr = &options->fingerprint_hash; 1770e9778795SPeter Avalos arg = strdelim(&s); 1771e9778795SPeter Avalos if (!arg || *arg == '\0') 1772e9778795SPeter Avalos fatal("%.200s line %d: Missing argument.", 1773e9778795SPeter Avalos filename, linenum); 1774e9778795SPeter Avalos if ((value = ssh_digest_alg_by_name(arg)) == -1) 1775e9778795SPeter Avalos fatal("%.200s line %d: Invalid hash algorithm \"%s\".", 1776e9778795SPeter Avalos filename, linenum, arg); 1777e9778795SPeter Avalos if (*activep && *intptr == -1) 1778e9778795SPeter Avalos *intptr = value; 1779e9778795SPeter Avalos break; 1780e9778795SPeter Avalos 1781e9778795SPeter Avalos case oUpdateHostkeys: 1782e9778795SPeter Avalos intptr = &options->update_hostkeys; 1783e9778795SPeter Avalos multistate_ptr = multistate_yesnoask; 1784e9778795SPeter Avalos goto parse_multistate; 1785e9778795SPeter Avalos 1786e9778795SPeter Avalos case oHostbasedKeyTypes: 1787e9778795SPeter Avalos charptr = &options->hostbased_key_types; 1788e9778795SPeter Avalos goto parse_keytypes; 1789e9778795SPeter Avalos 1790e9778795SPeter Avalos case oPubkeyAcceptedKeyTypes: 1791e9778795SPeter Avalos charptr = &options->pubkey_key_types; 1792e9778795SPeter Avalos goto parse_keytypes; 1793e9778795SPeter Avalos 1794e9778795SPeter Avalos case oAddKeysToAgent: 1795e9778795SPeter Avalos intptr = &options->add_keys_to_agent; 1796e9778795SPeter Avalos multistate_ptr = multistate_yesnoaskconfirm; 1797e9778795SPeter Avalos goto parse_multistate; 1798e9778795SPeter Avalos 1799e9778795SPeter Avalos case oIdentityAgent: 1800e9778795SPeter Avalos charptr = &options->identity_agent; 1801664f4763Szrj arg = strdelim(&s); 1802664f4763Szrj if (!arg || *arg == '\0') 1803664f4763Szrj fatal("%.200s line %d: Missing argument.", 1804664f4763Szrj filename, linenum); 1805*0cbfa66cSDaniel Fojt parse_agent_path: 1806664f4763Szrj /* Extra validation if the string represents an env var. */ 1807664f4763Szrj if (arg[0] == '$' && !valid_env_name(arg + 1)) { 1808664f4763Szrj fatal("%.200s line %d: Invalid environment name %s.", 1809664f4763Szrj filename, linenum, arg); 1810664f4763Szrj } 1811664f4763Szrj if (*activep && *charptr == NULL) 1812664f4763Szrj *charptr = xstrdup(arg); 1813664f4763Szrj break; 1814e9778795SPeter Avalos 181518de8d7fSPeter Avalos case oDeprecated: 181618de8d7fSPeter Avalos debug("%s line %d: Deprecated option \"%s\"", 181718de8d7fSPeter Avalos filename, linenum, keyword); 181818de8d7fSPeter Avalos return 0; 181918de8d7fSPeter Avalos 182018de8d7fSPeter Avalos case oUnsupported: 182118de8d7fSPeter Avalos error("%s line %d: Unsupported option \"%s\"", 182218de8d7fSPeter Avalos filename, linenum, keyword); 182318de8d7fSPeter Avalos return 0; 182418de8d7fSPeter Avalos 182518de8d7fSPeter Avalos default: 1826e9778795SPeter Avalos fatal("%s: Unimplemented opcode %d", __func__, opcode); 182718de8d7fSPeter Avalos } 182818de8d7fSPeter Avalos 182918de8d7fSPeter Avalos /* Check that there is no garbage at end of line. */ 183018de8d7fSPeter Avalos if ((arg = strdelim(&s)) != NULL && *arg != '\0') { 183118de8d7fSPeter Avalos fatal("%.200s line %d: garbage at end of line; \"%.200s\".", 183218de8d7fSPeter Avalos filename, linenum, arg); 183318de8d7fSPeter Avalos } 183418de8d7fSPeter Avalos return 0; 183518de8d7fSPeter Avalos } 183618de8d7fSPeter Avalos 183718de8d7fSPeter Avalos /* 183818de8d7fSPeter Avalos * Reads the config file and modifies the options accordingly. Options 183918de8d7fSPeter Avalos * should already be initialized before this call. This never returns if 184018de8d7fSPeter Avalos * there is an error. If the file does not exist, this returns 0. 184118de8d7fSPeter Avalos */ 184218de8d7fSPeter Avalos int 184336e94dc5SPeter Avalos read_config_file(const char *filename, struct passwd *pw, const char *host, 1844664f4763Szrj const char *original_host, Options *options, int flags, 1845664f4763Szrj int *want_final_pass) 1846e9778795SPeter Avalos { 1847e9778795SPeter Avalos int active = 1; 1848e9778795SPeter Avalos 1849e9778795SPeter Avalos return read_config_file_depth(filename, pw, host, original_host, 1850664f4763Szrj options, flags, &active, want_final_pass, 0); 1851e9778795SPeter Avalos } 1852e9778795SPeter Avalos 1853e9778795SPeter Avalos #define READCONF_MAX_DEPTH 16 1854e9778795SPeter Avalos static int 1855e9778795SPeter Avalos read_config_file_depth(const char *filename, struct passwd *pw, 1856e9778795SPeter Avalos const char *host, const char *original_host, Options *options, 1857664f4763Szrj int flags, int *activep, int *want_final_pass, int depth) 185818de8d7fSPeter Avalos { 185918de8d7fSPeter Avalos FILE *f; 1860664f4763Szrj char *line = NULL; 1861664f4763Szrj size_t linesize = 0; 1862e9778795SPeter Avalos int linenum; 186318de8d7fSPeter Avalos int bad_options = 0; 186418de8d7fSPeter Avalos 1865e9778795SPeter Avalos if (depth < 0 || depth > READCONF_MAX_DEPTH) 1866e9778795SPeter Avalos fatal("Too many recursive configuration includes"); 1867e9778795SPeter Avalos 186818de8d7fSPeter Avalos if ((f = fopen(filename, "r")) == NULL) 186918de8d7fSPeter Avalos return 0; 187018de8d7fSPeter Avalos 187136e94dc5SPeter Avalos if (flags & SSHCONF_CHECKPERM) { 187218de8d7fSPeter Avalos struct stat sb; 187318de8d7fSPeter Avalos 187418de8d7fSPeter Avalos if (fstat(fileno(f), &sb) == -1) 187518de8d7fSPeter Avalos fatal("fstat %s: %s", filename, strerror(errno)); 187618de8d7fSPeter Avalos if (((sb.st_uid != 0 && sb.st_uid != getuid()) || 187718de8d7fSPeter Avalos (sb.st_mode & 022) != 0)) 187818de8d7fSPeter Avalos fatal("Bad owner or permissions on %s", filename); 187918de8d7fSPeter Avalos } 188018de8d7fSPeter Avalos 188118de8d7fSPeter Avalos debug("Reading configuration data %.200s", filename); 188218de8d7fSPeter Avalos 188318de8d7fSPeter Avalos /* 188418de8d7fSPeter Avalos * Mark that we are now processing the options. This flag is turned 188518de8d7fSPeter Avalos * on/off by Host specifications. 188618de8d7fSPeter Avalos */ 188718de8d7fSPeter Avalos linenum = 0; 1888664f4763Szrj while (getline(&line, &linesize, f) != -1) { 188918de8d7fSPeter Avalos /* Update line number counter. */ 189018de8d7fSPeter Avalos linenum++; 1891e9778795SPeter Avalos if (process_config_line_depth(options, pw, host, original_host, 1892664f4763Szrj line, filename, linenum, activep, flags, want_final_pass, 1893664f4763Szrj depth) != 0) 189418de8d7fSPeter Avalos bad_options++; 189518de8d7fSPeter Avalos } 1896664f4763Szrj free(line); 189718de8d7fSPeter Avalos fclose(f); 189818de8d7fSPeter Avalos if (bad_options > 0) 189918de8d7fSPeter Avalos fatal("%s: terminating, %d bad configuration options", 190018de8d7fSPeter Avalos filename, bad_options); 190118de8d7fSPeter Avalos return 1; 190218de8d7fSPeter Avalos } 190318de8d7fSPeter Avalos 190436e94dc5SPeter Avalos /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ 190536e94dc5SPeter Avalos int 190636e94dc5SPeter Avalos option_clear_or_none(const char *o) 190736e94dc5SPeter Avalos { 190836e94dc5SPeter Avalos return o == NULL || strcasecmp(o, "none") == 0; 190936e94dc5SPeter Avalos } 191036e94dc5SPeter Avalos 191118de8d7fSPeter Avalos /* 191218de8d7fSPeter Avalos * Initializes options to special values that indicate that they have not yet 191318de8d7fSPeter Avalos * been set. Read_config_file will only set options with this value. Options 191418de8d7fSPeter Avalos * are processed in the following order: command line, user config file, 191518de8d7fSPeter Avalos * system config file. Last, fill_default_options is called. 191618de8d7fSPeter Avalos */ 191718de8d7fSPeter Avalos 191818de8d7fSPeter Avalos void 191918de8d7fSPeter Avalos initialize_options(Options * options) 192018de8d7fSPeter Avalos { 192118de8d7fSPeter Avalos memset(options, 'X', sizeof(*options)); 192218de8d7fSPeter Avalos options->forward_agent = -1; 1923*0cbfa66cSDaniel Fojt options->forward_agent_sock_path = NULL; 192418de8d7fSPeter Avalos options->forward_x11 = -1; 192518de8d7fSPeter Avalos options->forward_x11_trusted = -1; 1926856ea928SPeter Avalos options->forward_x11_timeout = -1; 1927e9778795SPeter Avalos options->stdio_forward_host = NULL; 1928e9778795SPeter Avalos options->stdio_forward_port = 0; 1929e9778795SPeter Avalos options->clear_forwardings = -1; 193018de8d7fSPeter Avalos options->exit_on_forward_failure = -1; 193118de8d7fSPeter Avalos options->xauth_location = NULL; 193236e94dc5SPeter Avalos options->fwd_opts.gateway_ports = -1; 193336e94dc5SPeter Avalos options->fwd_opts.streamlocal_bind_mask = (mode_t)-1; 193436e94dc5SPeter Avalos options->fwd_opts.streamlocal_bind_unlink = -1; 193518de8d7fSPeter Avalos options->pubkey_authentication = -1; 193618de8d7fSPeter Avalos options->challenge_response_authentication = -1; 193718de8d7fSPeter Avalos options->gss_authentication = -1; 193818de8d7fSPeter Avalos options->gss_deleg_creds = -1; 193918de8d7fSPeter Avalos options->password_authentication = -1; 194018de8d7fSPeter Avalos options->kbd_interactive_authentication = -1; 194118de8d7fSPeter Avalos options->kbd_interactive_devices = NULL; 194218de8d7fSPeter Avalos options->hostbased_authentication = -1; 194318de8d7fSPeter Avalos options->batch_mode = -1; 194418de8d7fSPeter Avalos options->check_host_ip = -1; 194518de8d7fSPeter Avalos options->strict_host_key_checking = -1; 194618de8d7fSPeter Avalos options->compression = -1; 194718de8d7fSPeter Avalos options->tcp_keep_alive = -1; 194818de8d7fSPeter Avalos options->port = -1; 194918de8d7fSPeter Avalos options->address_family = -1; 195018de8d7fSPeter Avalos options->connection_attempts = -1; 195118de8d7fSPeter Avalos options->connection_timeout = -1; 195218de8d7fSPeter Avalos options->number_of_password_prompts = -1; 195318de8d7fSPeter Avalos options->ciphers = NULL; 195418de8d7fSPeter Avalos options->macs = NULL; 19559f304aafSPeter Avalos options->kex_algorithms = NULL; 195618de8d7fSPeter Avalos options->hostkeyalgorithms = NULL; 1957664f4763Szrj options->ca_sign_algorithms = NULL; 195818de8d7fSPeter Avalos options->num_identity_files = 0; 1959e9778795SPeter Avalos options->num_certificate_files = 0; 196018de8d7fSPeter Avalos options->hostname = NULL; 196118de8d7fSPeter Avalos options->host_key_alias = NULL; 196218de8d7fSPeter Avalos options->proxy_command = NULL; 1963e9778795SPeter Avalos options->jump_user = NULL; 1964e9778795SPeter Avalos options->jump_host = NULL; 1965e9778795SPeter Avalos options->jump_port = -1; 1966e9778795SPeter Avalos options->jump_extra = NULL; 196718de8d7fSPeter Avalos options->user = NULL; 196818de8d7fSPeter Avalos options->escape_char = -1; 19691c188a7fSPeter Avalos options->num_system_hostfiles = 0; 19701c188a7fSPeter Avalos options->num_user_hostfiles = 0; 1971856ea928SPeter Avalos options->local_forwards = NULL; 197218de8d7fSPeter Avalos options->num_local_forwards = 0; 1973856ea928SPeter Avalos options->remote_forwards = NULL; 197418de8d7fSPeter Avalos options->num_remote_forwards = 0; 1975ce74bacaSMatthew Dillon options->log_facility = SYSLOG_FACILITY_NOT_SET; 197618de8d7fSPeter Avalos options->log_level = SYSLOG_LEVEL_NOT_SET; 197718de8d7fSPeter Avalos options->preferred_authentications = NULL; 197818de8d7fSPeter Avalos options->bind_address = NULL; 1979664f4763Szrj options->bind_interface = NULL; 1980856ea928SPeter Avalos options->pkcs11_provider = NULL; 1981*0cbfa66cSDaniel Fojt options->sk_provider = NULL; 198218de8d7fSPeter Avalos options->enable_ssh_keysign = - 1; 198318de8d7fSPeter Avalos options->no_host_authentication_for_localhost = - 1; 198418de8d7fSPeter Avalos options->identities_only = - 1; 198518de8d7fSPeter Avalos options->rekey_limit = - 1; 198636e94dc5SPeter Avalos options->rekey_interval = -1; 198718de8d7fSPeter Avalos options->verify_host_key_dns = -1; 198818de8d7fSPeter Avalos options->server_alive_interval = -1; 198918de8d7fSPeter Avalos options->server_alive_count_max = -1; 1990664f4763Szrj options->send_env = NULL; 199118de8d7fSPeter Avalos options->num_send_env = 0; 1992664f4763Szrj options->setenv = NULL; 1993664f4763Szrj options->num_setenv = 0; 199418de8d7fSPeter Avalos options->control_path = NULL; 199518de8d7fSPeter Avalos options->control_master = -1; 1996856ea928SPeter Avalos options->control_persist = -1; 1997856ea928SPeter Avalos options->control_persist_timeout = 0; 199818de8d7fSPeter Avalos options->hash_known_hosts = -1; 199918de8d7fSPeter Avalos options->tun_open = -1; 200018de8d7fSPeter Avalos options->tun_local = -1; 200118de8d7fSPeter Avalos options->tun_remote = -1; 200218de8d7fSPeter Avalos options->local_command = NULL; 200318de8d7fSPeter Avalos options->permit_local_command = -1; 2004ce74bacaSMatthew Dillon options->remote_command = NULL; 2005e9778795SPeter Avalos options->add_keys_to_agent = -1; 2006e9778795SPeter Avalos options->identity_agent = NULL; 200718de8d7fSPeter Avalos options->visual_host_key = -1; 20089f304aafSPeter Avalos options->ip_qos_interactive = -1; 20099f304aafSPeter Avalos options->ip_qos_bulk = -1; 20101c188a7fSPeter Avalos options->request_tty = -1; 201136e94dc5SPeter Avalos options->proxy_use_fdpass = -1; 201236e94dc5SPeter Avalos options->ignored_unknown = NULL; 201336e94dc5SPeter Avalos options->num_canonical_domains = 0; 201436e94dc5SPeter Avalos options->num_permitted_cnames = 0; 201536e94dc5SPeter Avalos options->canonicalize_max_dots = -1; 201636e94dc5SPeter Avalos options->canonicalize_fallback_local = -1; 201736e94dc5SPeter Avalos options->canonicalize_hostname = -1; 2018e9778795SPeter Avalos options->revoked_host_keys = NULL; 2019e9778795SPeter Avalos options->fingerprint_hash = -1; 2020e9778795SPeter Avalos options->update_hostkeys = -1; 2021e9778795SPeter Avalos options->hostbased_key_types = NULL; 2022e9778795SPeter Avalos options->pubkey_key_types = NULL; 202336e94dc5SPeter Avalos } 202436e94dc5SPeter Avalos 202536e94dc5SPeter Avalos /* 202636e94dc5SPeter Avalos * A petite version of fill_default_options() that just fills the options 202736e94dc5SPeter Avalos * needed for hostname canonicalization to proceed. 202836e94dc5SPeter Avalos */ 202936e94dc5SPeter Avalos void 203036e94dc5SPeter Avalos fill_default_options_for_canonicalization(Options *options) 203136e94dc5SPeter Avalos { 203236e94dc5SPeter Avalos if (options->canonicalize_max_dots == -1) 203336e94dc5SPeter Avalos options->canonicalize_max_dots = 1; 203436e94dc5SPeter Avalos if (options->canonicalize_fallback_local == -1) 203536e94dc5SPeter Avalos options->canonicalize_fallback_local = 1; 203636e94dc5SPeter Avalos if (options->canonicalize_hostname == -1) 203736e94dc5SPeter Avalos options->canonicalize_hostname = SSH_CANONICALISE_NO; 203818de8d7fSPeter Avalos } 203918de8d7fSPeter Avalos 204018de8d7fSPeter Avalos /* 204118de8d7fSPeter Avalos * Called after processing other sources of option data, this fills those 204218de8d7fSPeter Avalos * options for which no value has been specified with their default values. 204318de8d7fSPeter Avalos */ 204418de8d7fSPeter Avalos void 204518de8d7fSPeter Avalos fill_default_options(Options * options) 204618de8d7fSPeter Avalos { 2047664f4763Szrj char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig; 2048*0cbfa66cSDaniel Fojt char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig; 2049664f4763Szrj int r; 2050664f4763Szrj 205118de8d7fSPeter Avalos if (options->forward_agent == -1) 205218de8d7fSPeter Avalos options->forward_agent = 0; 205318de8d7fSPeter Avalos if (options->forward_x11 == -1) 205418de8d7fSPeter Avalos options->forward_x11 = 0; 205518de8d7fSPeter Avalos if (options->forward_x11_trusted == -1) 205618de8d7fSPeter Avalos options->forward_x11_trusted = 0; 2057856ea928SPeter Avalos if (options->forward_x11_timeout == -1) 2058856ea928SPeter Avalos options->forward_x11_timeout = 1200; 2059e9778795SPeter Avalos /* 2060e9778795SPeter Avalos * stdio forwarding (-W) changes the default for these but we defer 2061e9778795SPeter Avalos * setting the values so they can be overridden. 2062e9778795SPeter Avalos */ 206318de8d7fSPeter Avalos if (options->exit_on_forward_failure == -1) 2064e9778795SPeter Avalos options->exit_on_forward_failure = 2065e9778795SPeter Avalos options->stdio_forward_host != NULL ? 1 : 0; 2066e9778795SPeter Avalos if (options->clear_forwardings == -1) 2067e9778795SPeter Avalos options->clear_forwardings = 2068e9778795SPeter Avalos options->stdio_forward_host != NULL ? 1 : 0; 2069e9778795SPeter Avalos if (options->clear_forwardings == 1) 2070e9778795SPeter Avalos clear_forwardings(options); 2071e9778795SPeter Avalos 207218de8d7fSPeter Avalos if (options->xauth_location == NULL) 207318de8d7fSPeter Avalos options->xauth_location = _PATH_XAUTH; 207436e94dc5SPeter Avalos if (options->fwd_opts.gateway_ports == -1) 207536e94dc5SPeter Avalos options->fwd_opts.gateway_ports = 0; 207636e94dc5SPeter Avalos if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1) 207736e94dc5SPeter Avalos options->fwd_opts.streamlocal_bind_mask = 0177; 207836e94dc5SPeter Avalos if (options->fwd_opts.streamlocal_bind_unlink == -1) 207936e94dc5SPeter Avalos options->fwd_opts.streamlocal_bind_unlink = 0; 208018de8d7fSPeter Avalos if (options->pubkey_authentication == -1) 208118de8d7fSPeter Avalos options->pubkey_authentication = 1; 208218de8d7fSPeter Avalos if (options->challenge_response_authentication == -1) 208318de8d7fSPeter Avalos options->challenge_response_authentication = 1; 208418de8d7fSPeter Avalos if (options->gss_authentication == -1) 208518de8d7fSPeter Avalos options->gss_authentication = 0; 208618de8d7fSPeter Avalos if (options->gss_deleg_creds == -1) 208718de8d7fSPeter Avalos options->gss_deleg_creds = 0; 208818de8d7fSPeter Avalos if (options->password_authentication == -1) 208918de8d7fSPeter Avalos options->password_authentication = 1; 209018de8d7fSPeter Avalos if (options->kbd_interactive_authentication == -1) 209118de8d7fSPeter Avalos options->kbd_interactive_authentication = 1; 209218de8d7fSPeter Avalos if (options->hostbased_authentication == -1) 209318de8d7fSPeter Avalos options->hostbased_authentication = 0; 209418de8d7fSPeter Avalos if (options->batch_mode == -1) 209518de8d7fSPeter Avalos options->batch_mode = 0; 209618de8d7fSPeter Avalos if (options->check_host_ip == -1) 209718de8d7fSPeter Avalos options->check_host_ip = 1; 209818de8d7fSPeter Avalos if (options->strict_host_key_checking == -1) 2099ce74bacaSMatthew Dillon options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK; 210018de8d7fSPeter Avalos if (options->compression == -1) 210118de8d7fSPeter Avalos options->compression = 0; 210218de8d7fSPeter Avalos if (options->tcp_keep_alive == -1) 210318de8d7fSPeter Avalos options->tcp_keep_alive = 1; 210418de8d7fSPeter Avalos if (options->port == -1) 210518de8d7fSPeter Avalos options->port = 0; /* Filled in ssh_connect. */ 210618de8d7fSPeter Avalos if (options->address_family == -1) 210718de8d7fSPeter Avalos options->address_family = AF_UNSPEC; 210818de8d7fSPeter Avalos if (options->connection_attempts == -1) 210918de8d7fSPeter Avalos options->connection_attempts = 1; 211018de8d7fSPeter Avalos if (options->number_of_password_prompts == -1) 211118de8d7fSPeter Avalos options->number_of_password_prompts = 3; 211218de8d7fSPeter Avalos /* options->hostkeyalgorithms, default set in myproposals.h */ 2113e9778795SPeter Avalos if (options->add_keys_to_agent == -1) 2114e9778795SPeter Avalos options->add_keys_to_agent = 0; 211518de8d7fSPeter Avalos if (options->num_identity_files == 0) { 2116ce74bacaSMatthew Dillon add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0); 2117ce74bacaSMatthew Dillon add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0); 21189f304aafSPeter Avalos #ifdef OPENSSL_HAS_ECC 2119ce74bacaSMatthew Dillon add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0); 2120*0cbfa66cSDaniel Fojt add_identity_file(options, "~/", 2121*0cbfa66cSDaniel Fojt _PATH_SSH_CLIENT_ID_ECDSA_SK, 0); 21229f304aafSPeter Avalos #endif 212336e94dc5SPeter Avalos add_identity_file(options, "~/", 212436e94dc5SPeter Avalos _PATH_SSH_CLIENT_ID_ED25519, 0); 2125*0cbfa66cSDaniel Fojt add_identity_file(options, "~/", 2126*0cbfa66cSDaniel Fojt _PATH_SSH_CLIENT_ID_ED25519_SK, 0); 2127664f4763Szrj add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0); 212818de8d7fSPeter Avalos } 212918de8d7fSPeter Avalos if (options->escape_char == -1) 213018de8d7fSPeter Avalos options->escape_char = '~'; 21311c188a7fSPeter Avalos if (options->num_system_hostfiles == 0) { 21321c188a7fSPeter Avalos options->system_hostfiles[options->num_system_hostfiles++] = 21331c188a7fSPeter Avalos xstrdup(_PATH_SSH_SYSTEM_HOSTFILE); 21341c188a7fSPeter Avalos options->system_hostfiles[options->num_system_hostfiles++] = 21351c188a7fSPeter Avalos xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2); 21361c188a7fSPeter Avalos } 2137*0cbfa66cSDaniel Fojt if (options->update_hostkeys == -1) 2138*0cbfa66cSDaniel Fojt options->update_hostkeys = SSH_UPDATE_HOSTKEYS_NO; 21391c188a7fSPeter Avalos if (options->num_user_hostfiles == 0) { 21401c188a7fSPeter Avalos options->user_hostfiles[options->num_user_hostfiles++] = 21411c188a7fSPeter Avalos xstrdup(_PATH_SSH_USER_HOSTFILE); 21421c188a7fSPeter Avalos options->user_hostfiles[options->num_user_hostfiles++] = 21431c188a7fSPeter Avalos xstrdup(_PATH_SSH_USER_HOSTFILE2); 21441c188a7fSPeter Avalos } 214518de8d7fSPeter Avalos if (options->log_level == SYSLOG_LEVEL_NOT_SET) 214618de8d7fSPeter Avalos options->log_level = SYSLOG_LEVEL_INFO; 2147ce74bacaSMatthew Dillon if (options->log_facility == SYSLOG_FACILITY_NOT_SET) 2148ce74bacaSMatthew Dillon options->log_facility = SYSLOG_FACILITY_USER; 214918de8d7fSPeter Avalos if (options->no_host_authentication_for_localhost == - 1) 215018de8d7fSPeter Avalos options->no_host_authentication_for_localhost = 0; 215118de8d7fSPeter Avalos if (options->identities_only == -1) 215218de8d7fSPeter Avalos options->identities_only = 0; 215318de8d7fSPeter Avalos if (options->enable_ssh_keysign == -1) 215418de8d7fSPeter Avalos options->enable_ssh_keysign = 0; 215518de8d7fSPeter Avalos if (options->rekey_limit == -1) 215618de8d7fSPeter Avalos options->rekey_limit = 0; 215736e94dc5SPeter Avalos if (options->rekey_interval == -1) 215836e94dc5SPeter Avalos options->rekey_interval = 0; 215918de8d7fSPeter Avalos if (options->verify_host_key_dns == -1) 216018de8d7fSPeter Avalos options->verify_host_key_dns = 0; 216118de8d7fSPeter Avalos if (options->server_alive_interval == -1) 216218de8d7fSPeter Avalos options->server_alive_interval = 0; 216318de8d7fSPeter Avalos if (options->server_alive_count_max == -1) 216418de8d7fSPeter Avalos options->server_alive_count_max = 3; 216518de8d7fSPeter Avalos if (options->control_master == -1) 216618de8d7fSPeter Avalos options->control_master = 0; 2167856ea928SPeter Avalos if (options->control_persist == -1) { 2168856ea928SPeter Avalos options->control_persist = 0; 2169856ea928SPeter Avalos options->control_persist_timeout = 0; 2170856ea928SPeter Avalos } 217118de8d7fSPeter Avalos if (options->hash_known_hosts == -1) 217218de8d7fSPeter Avalos options->hash_known_hosts = 0; 217318de8d7fSPeter Avalos if (options->tun_open == -1) 217418de8d7fSPeter Avalos options->tun_open = SSH_TUNMODE_NO; 217518de8d7fSPeter Avalos if (options->tun_local == -1) 217618de8d7fSPeter Avalos options->tun_local = SSH_TUNID_ANY; 217718de8d7fSPeter Avalos if (options->tun_remote == -1) 217818de8d7fSPeter Avalos options->tun_remote = SSH_TUNID_ANY; 217918de8d7fSPeter Avalos if (options->permit_local_command == -1) 218018de8d7fSPeter Avalos options->permit_local_command = 0; 218118de8d7fSPeter Avalos if (options->visual_host_key == -1) 218218de8d7fSPeter Avalos options->visual_host_key = 0; 21839f304aafSPeter Avalos if (options->ip_qos_interactive == -1) 2184664f4763Szrj options->ip_qos_interactive = IPTOS_DSCP_AF21; 21859f304aafSPeter Avalos if (options->ip_qos_bulk == -1) 2186664f4763Szrj options->ip_qos_bulk = IPTOS_DSCP_CS1; 21871c188a7fSPeter Avalos if (options->request_tty == -1) 21881c188a7fSPeter Avalos options->request_tty = REQUEST_TTY_AUTO; 218936e94dc5SPeter Avalos if (options->proxy_use_fdpass == -1) 219036e94dc5SPeter Avalos options->proxy_use_fdpass = 0; 219136e94dc5SPeter Avalos if (options->canonicalize_max_dots == -1) 219236e94dc5SPeter Avalos options->canonicalize_max_dots = 1; 219336e94dc5SPeter Avalos if (options->canonicalize_fallback_local == -1) 219436e94dc5SPeter Avalos options->canonicalize_fallback_local = 1; 219536e94dc5SPeter Avalos if (options->canonicalize_hostname == -1) 219636e94dc5SPeter Avalos options->canonicalize_hostname = SSH_CANONICALISE_NO; 2197e9778795SPeter Avalos if (options->fingerprint_hash == -1) 2198e9778795SPeter Avalos options->fingerprint_hash = SSH_FP_HASH_DEFAULT; 2199*0cbfa66cSDaniel Fojt #ifdef ENABLE_SK_INTERNAL 2200*0cbfa66cSDaniel Fojt if (options->sk_provider == NULL) 2201*0cbfa66cSDaniel Fojt options->sk_provider = xstrdup("internal"); 2202*0cbfa66cSDaniel Fojt #else 2203*0cbfa66cSDaniel Fojt if (options->sk_provider == NULL) 2204*0cbfa66cSDaniel Fojt options->sk_provider = xstrdup("$SSH_SK_PROVIDER"); 2205*0cbfa66cSDaniel Fojt #endif 2206664f4763Szrj 2207664f4763Szrj /* Expand KEX name lists */ 2208664f4763Szrj all_cipher = cipher_alg_list(',', 0); 2209664f4763Szrj all_mac = mac_alg_list(','); 2210664f4763Szrj all_kex = kex_alg_list(','); 2211664f4763Szrj all_key = sshkey_alg_list(0, 0, 1, ','); 2212664f4763Szrj all_sig = sshkey_alg_list(0, 1, 1, ','); 2213*0cbfa66cSDaniel Fojt /* remove unsupported algos from default lists */ 2214*0cbfa66cSDaniel Fojt def_cipher = match_filter_whitelist(KEX_CLIENT_ENCRYPT, all_cipher); 2215*0cbfa66cSDaniel Fojt def_mac = match_filter_whitelist(KEX_CLIENT_MAC, all_mac); 2216*0cbfa66cSDaniel Fojt def_kex = match_filter_whitelist(KEX_CLIENT_KEX, all_kex); 2217*0cbfa66cSDaniel Fojt def_key = match_filter_whitelist(KEX_DEFAULT_PK_ALG, all_key); 2218*0cbfa66cSDaniel Fojt def_sig = match_filter_whitelist(SSH_ALLOWED_CA_SIGALGS, all_sig); 2219664f4763Szrj #define ASSEMBLE(what, defaults, all) \ 2220664f4763Szrj do { \ 2221664f4763Szrj if ((r = kex_assemble_names(&options->what, \ 2222664f4763Szrj defaults, all)) != 0) \ 2223664f4763Szrj fatal("%s: %s: %s", __func__, #what, ssh_err(r)); \ 2224664f4763Szrj } while (0) 2225*0cbfa66cSDaniel Fojt ASSEMBLE(ciphers, def_cipher, all_cipher); 2226*0cbfa66cSDaniel Fojt ASSEMBLE(macs, def_mac, all_mac); 2227*0cbfa66cSDaniel Fojt ASSEMBLE(kex_algorithms, def_kex, all_kex); 2228*0cbfa66cSDaniel Fojt ASSEMBLE(hostbased_key_types, def_key, all_key); 2229*0cbfa66cSDaniel Fojt ASSEMBLE(pubkey_key_types, def_key, all_key); 2230*0cbfa66cSDaniel Fojt ASSEMBLE(ca_sign_algorithms, def_sig, all_sig); 2231664f4763Szrj #undef ASSEMBLE 2232664f4763Szrj free(all_cipher); 2233664f4763Szrj free(all_mac); 2234664f4763Szrj free(all_kex); 2235664f4763Szrj free(all_key); 2236664f4763Szrj free(all_sig); 2237*0cbfa66cSDaniel Fojt free(def_cipher); 2238*0cbfa66cSDaniel Fojt free(def_mac); 2239*0cbfa66cSDaniel Fojt free(def_kex); 2240*0cbfa66cSDaniel Fojt kex_default_pk_alg_filtered = def_key; /* save for later use */ 2241*0cbfa66cSDaniel Fojt free(def_sig); 2242e9778795SPeter Avalos 224336e94dc5SPeter Avalos #define CLEAR_ON_NONE(v) \ 224436e94dc5SPeter Avalos do { \ 224536e94dc5SPeter Avalos if (option_clear_or_none(v)) { \ 224636e94dc5SPeter Avalos free(v); \ 224736e94dc5SPeter Avalos v = NULL; \ 224836e94dc5SPeter Avalos } \ 224936e94dc5SPeter Avalos } while(0) 225036e94dc5SPeter Avalos CLEAR_ON_NONE(options->local_command); 2251ce74bacaSMatthew Dillon CLEAR_ON_NONE(options->remote_command); 225236e94dc5SPeter Avalos CLEAR_ON_NONE(options->proxy_command); 225336e94dc5SPeter Avalos CLEAR_ON_NONE(options->control_path); 2254e9778795SPeter Avalos CLEAR_ON_NONE(options->revoked_host_keys); 2255664f4763Szrj CLEAR_ON_NONE(options->pkcs11_provider); 2256*0cbfa66cSDaniel Fojt CLEAR_ON_NONE(options->sk_provider); 2257664f4763Szrj if (options->jump_host != NULL && 2258664f4763Szrj strcmp(options->jump_host, "none") == 0 && 2259664f4763Szrj options->jump_port == 0 && options->jump_user == NULL) { 2260664f4763Szrj free(options->jump_host); 2261664f4763Szrj options->jump_host = NULL; 2262664f4763Szrj } 2263e9778795SPeter Avalos /* options->identity_agent distinguishes NULL from 'none' */ 226418de8d7fSPeter Avalos /* options->user will be set in the main program if appropriate */ 226518de8d7fSPeter Avalos /* options->hostname will be set in the main program if appropriate */ 226618de8d7fSPeter Avalos /* options->host_key_alias should not be set by default */ 226718de8d7fSPeter Avalos /* options->preferred_authentications will be set in ssh */ 226818de8d7fSPeter Avalos } 226918de8d7fSPeter Avalos 227036e94dc5SPeter Avalos struct fwdarg { 227136e94dc5SPeter Avalos char *arg; 227236e94dc5SPeter Avalos int ispath; 227336e94dc5SPeter Avalos }; 227436e94dc5SPeter Avalos 227536e94dc5SPeter Avalos /* 227636e94dc5SPeter Avalos * parse_fwd_field 227736e94dc5SPeter Avalos * parses the next field in a port forwarding specification. 227836e94dc5SPeter Avalos * sets fwd to the parsed field and advances p past the colon 227936e94dc5SPeter Avalos * or sets it to NULL at end of string. 228036e94dc5SPeter Avalos * returns 0 on success, else non-zero. 228136e94dc5SPeter Avalos */ 228236e94dc5SPeter Avalos static int 228336e94dc5SPeter Avalos parse_fwd_field(char **p, struct fwdarg *fwd) 228436e94dc5SPeter Avalos { 228536e94dc5SPeter Avalos char *ep, *cp = *p; 228636e94dc5SPeter Avalos int ispath = 0; 228736e94dc5SPeter Avalos 228836e94dc5SPeter Avalos if (*cp == '\0') { 228936e94dc5SPeter Avalos *p = NULL; 229036e94dc5SPeter Avalos return -1; /* end of string */ 229136e94dc5SPeter Avalos } 229236e94dc5SPeter Avalos 229336e94dc5SPeter Avalos /* 229436e94dc5SPeter Avalos * A field escaped with square brackets is used literally. 229536e94dc5SPeter Avalos * XXX - allow ']' to be escaped via backslash? 229636e94dc5SPeter Avalos */ 229736e94dc5SPeter Avalos if (*cp == '[') { 229836e94dc5SPeter Avalos /* find matching ']' */ 229936e94dc5SPeter Avalos for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) { 230036e94dc5SPeter Avalos if (*ep == '/') 230136e94dc5SPeter Avalos ispath = 1; 230236e94dc5SPeter Avalos } 230336e94dc5SPeter Avalos /* no matching ']' or not at end of field. */ 230436e94dc5SPeter Avalos if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0')) 230536e94dc5SPeter Avalos return -1; 230636e94dc5SPeter Avalos /* NUL terminate the field and advance p past the colon */ 230736e94dc5SPeter Avalos *ep++ = '\0'; 230836e94dc5SPeter Avalos if (*ep != '\0') 230936e94dc5SPeter Avalos *ep++ = '\0'; 231036e94dc5SPeter Avalos fwd->arg = cp + 1; 231136e94dc5SPeter Avalos fwd->ispath = ispath; 231236e94dc5SPeter Avalos *p = ep; 231336e94dc5SPeter Avalos return 0; 231436e94dc5SPeter Avalos } 231536e94dc5SPeter Avalos 231636e94dc5SPeter Avalos for (cp = *p; *cp != '\0'; cp++) { 231736e94dc5SPeter Avalos switch (*cp) { 231836e94dc5SPeter Avalos case '\\': 231936e94dc5SPeter Avalos memmove(cp, cp + 1, strlen(cp + 1) + 1); 2320e9778795SPeter Avalos if (*cp == '\0') 2321e9778795SPeter Avalos return -1; 232236e94dc5SPeter Avalos break; 232336e94dc5SPeter Avalos case '/': 232436e94dc5SPeter Avalos ispath = 1; 232536e94dc5SPeter Avalos break; 232636e94dc5SPeter Avalos case ':': 232736e94dc5SPeter Avalos *cp++ = '\0'; 232836e94dc5SPeter Avalos goto done; 232936e94dc5SPeter Avalos } 233036e94dc5SPeter Avalos } 233136e94dc5SPeter Avalos done: 233236e94dc5SPeter Avalos fwd->arg = *p; 233336e94dc5SPeter Avalos fwd->ispath = ispath; 233436e94dc5SPeter Avalos *p = cp; 233536e94dc5SPeter Avalos return 0; 233636e94dc5SPeter Avalos } 233736e94dc5SPeter Avalos 233818de8d7fSPeter Avalos /* 233918de8d7fSPeter Avalos * parse_forward 234018de8d7fSPeter Avalos * parses a string containing a port forwarding specification of the form: 2341cb5eb4f1SPeter Avalos * dynamicfwd == 0 234236e94dc5SPeter Avalos * [listenhost:]listenport|listenpath:connecthost:connectport|connectpath 234336e94dc5SPeter Avalos * listenpath:connectpath 2344cb5eb4f1SPeter Avalos * dynamicfwd == 1 2345cb5eb4f1SPeter Avalos * [listenhost:]listenport 234618de8d7fSPeter Avalos * returns number of arguments parsed or zero on error 234718de8d7fSPeter Avalos */ 234818de8d7fSPeter Avalos int 234936e94dc5SPeter Avalos parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd) 235018de8d7fSPeter Avalos { 235136e94dc5SPeter Avalos struct fwdarg fwdargs[4]; 235236e94dc5SPeter Avalos char *p, *cp; 235318de8d7fSPeter Avalos int i; 235418de8d7fSPeter Avalos 235536e94dc5SPeter Avalos memset(fwd, 0, sizeof(*fwd)); 235636e94dc5SPeter Avalos memset(fwdargs, 0, sizeof(fwdargs)); 235718de8d7fSPeter Avalos 235818de8d7fSPeter Avalos cp = p = xstrdup(fwdspec); 235918de8d7fSPeter Avalos 236018de8d7fSPeter Avalos /* skip leading spaces */ 236136e94dc5SPeter Avalos while (isspace((u_char)*cp)) 236218de8d7fSPeter Avalos cp++; 236318de8d7fSPeter Avalos 236436e94dc5SPeter Avalos for (i = 0; i < 4; ++i) { 236536e94dc5SPeter Avalos if (parse_fwd_field(&cp, &fwdargs[i]) != 0) 236618de8d7fSPeter Avalos break; 236736e94dc5SPeter Avalos } 236818de8d7fSPeter Avalos 2369cb5eb4f1SPeter Avalos /* Check for trailing garbage */ 237036e94dc5SPeter Avalos if (cp != NULL && *cp != '\0') { 237118de8d7fSPeter Avalos i = 0; /* failure */ 237236e94dc5SPeter Avalos } 237318de8d7fSPeter Avalos 237418de8d7fSPeter Avalos switch (i) { 2375cb5eb4f1SPeter Avalos case 1: 237636e94dc5SPeter Avalos if (fwdargs[0].ispath) { 237736e94dc5SPeter Avalos fwd->listen_path = xstrdup(fwdargs[0].arg); 237836e94dc5SPeter Avalos fwd->listen_port = PORT_STREAMLOCAL; 237936e94dc5SPeter Avalos } else { 2380cb5eb4f1SPeter Avalos fwd->listen_host = NULL; 238136e94dc5SPeter Avalos fwd->listen_port = a2port(fwdargs[0].arg); 238236e94dc5SPeter Avalos } 2383cb5eb4f1SPeter Avalos fwd->connect_host = xstrdup("socks"); 2384cb5eb4f1SPeter Avalos break; 2385cb5eb4f1SPeter Avalos 2386cb5eb4f1SPeter Avalos case 2: 238736e94dc5SPeter Avalos if (fwdargs[0].ispath && fwdargs[1].ispath) { 238836e94dc5SPeter Avalos fwd->listen_path = xstrdup(fwdargs[0].arg); 238936e94dc5SPeter Avalos fwd->listen_port = PORT_STREAMLOCAL; 239036e94dc5SPeter Avalos fwd->connect_path = xstrdup(fwdargs[1].arg); 239136e94dc5SPeter Avalos fwd->connect_port = PORT_STREAMLOCAL; 239236e94dc5SPeter Avalos } else if (fwdargs[1].ispath) { 239336e94dc5SPeter Avalos fwd->listen_host = NULL; 239436e94dc5SPeter Avalos fwd->listen_port = a2port(fwdargs[0].arg); 239536e94dc5SPeter Avalos fwd->connect_path = xstrdup(fwdargs[1].arg); 239636e94dc5SPeter Avalos fwd->connect_port = PORT_STREAMLOCAL; 239736e94dc5SPeter Avalos } else { 239836e94dc5SPeter Avalos fwd->listen_host = xstrdup(fwdargs[0].arg); 239936e94dc5SPeter Avalos fwd->listen_port = a2port(fwdargs[1].arg); 2400cb5eb4f1SPeter Avalos fwd->connect_host = xstrdup("socks"); 240136e94dc5SPeter Avalos } 2402cb5eb4f1SPeter Avalos break; 2403cb5eb4f1SPeter Avalos 240418de8d7fSPeter Avalos case 3: 240536e94dc5SPeter Avalos if (fwdargs[0].ispath) { 240636e94dc5SPeter Avalos fwd->listen_path = xstrdup(fwdargs[0].arg); 240736e94dc5SPeter Avalos fwd->listen_port = PORT_STREAMLOCAL; 240836e94dc5SPeter Avalos fwd->connect_host = xstrdup(fwdargs[1].arg); 240936e94dc5SPeter Avalos fwd->connect_port = a2port(fwdargs[2].arg); 241036e94dc5SPeter Avalos } else if (fwdargs[2].ispath) { 241136e94dc5SPeter Avalos fwd->listen_host = xstrdup(fwdargs[0].arg); 241236e94dc5SPeter Avalos fwd->listen_port = a2port(fwdargs[1].arg); 241336e94dc5SPeter Avalos fwd->connect_path = xstrdup(fwdargs[2].arg); 241436e94dc5SPeter Avalos fwd->connect_port = PORT_STREAMLOCAL; 241536e94dc5SPeter Avalos } else { 241618de8d7fSPeter Avalos fwd->listen_host = NULL; 241736e94dc5SPeter Avalos fwd->listen_port = a2port(fwdargs[0].arg); 241836e94dc5SPeter Avalos fwd->connect_host = xstrdup(fwdargs[1].arg); 241936e94dc5SPeter Avalos fwd->connect_port = a2port(fwdargs[2].arg); 242036e94dc5SPeter Avalos } 242118de8d7fSPeter Avalos break; 242218de8d7fSPeter Avalos 242318de8d7fSPeter Avalos case 4: 242436e94dc5SPeter Avalos fwd->listen_host = xstrdup(fwdargs[0].arg); 242536e94dc5SPeter Avalos fwd->listen_port = a2port(fwdargs[1].arg); 242636e94dc5SPeter Avalos fwd->connect_host = xstrdup(fwdargs[2].arg); 242736e94dc5SPeter Avalos fwd->connect_port = a2port(fwdargs[3].arg); 242818de8d7fSPeter Avalos break; 242918de8d7fSPeter Avalos default: 243018de8d7fSPeter Avalos i = 0; /* failure */ 243118de8d7fSPeter Avalos } 243218de8d7fSPeter Avalos 243336e94dc5SPeter Avalos free(p); 243418de8d7fSPeter Avalos 2435cb5eb4f1SPeter Avalos if (dynamicfwd) { 2436cb5eb4f1SPeter Avalos if (!(i == 1 || i == 2)) 2437cb5eb4f1SPeter Avalos goto fail_free; 2438cb5eb4f1SPeter Avalos } else { 243936e94dc5SPeter Avalos if (!(i == 3 || i == 4)) { 244036e94dc5SPeter Avalos if (fwd->connect_path == NULL && 244136e94dc5SPeter Avalos fwd->listen_path == NULL) 2442cb5eb4f1SPeter Avalos goto fail_free; 244336e94dc5SPeter Avalos } 244436e94dc5SPeter Avalos if (fwd->connect_port <= 0 && fwd->connect_path == NULL) 2445cb5eb4f1SPeter Avalos goto fail_free; 2446cb5eb4f1SPeter Avalos } 2447cb5eb4f1SPeter Avalos 244836e94dc5SPeter Avalos if ((fwd->listen_port < 0 && fwd->listen_path == NULL) || 244936e94dc5SPeter Avalos (!remotefwd && fwd->listen_port == 0)) 245018de8d7fSPeter Avalos goto fail_free; 245118de8d7fSPeter Avalos if (fwd->connect_host != NULL && 245218de8d7fSPeter Avalos strlen(fwd->connect_host) >= NI_MAXHOST) 245318de8d7fSPeter Avalos goto fail_free; 245436e94dc5SPeter Avalos /* XXX - if connecting to a remote socket, max sun len may not match this host */ 245536e94dc5SPeter Avalos if (fwd->connect_path != NULL && 245636e94dc5SPeter Avalos strlen(fwd->connect_path) >= PATH_MAX_SUN) 245736e94dc5SPeter Avalos goto fail_free; 2458cb5eb4f1SPeter Avalos if (fwd->listen_host != NULL && 2459cb5eb4f1SPeter Avalos strlen(fwd->listen_host) >= NI_MAXHOST) 2460cb5eb4f1SPeter Avalos goto fail_free; 246136e94dc5SPeter Avalos if (fwd->listen_path != NULL && 246236e94dc5SPeter Avalos strlen(fwd->listen_path) >= PATH_MAX_SUN) 246336e94dc5SPeter Avalos goto fail_free; 246418de8d7fSPeter Avalos 246518de8d7fSPeter Avalos return (i); 246618de8d7fSPeter Avalos 246718de8d7fSPeter Avalos fail_free: 246836e94dc5SPeter Avalos free(fwd->connect_host); 2469cb5eb4f1SPeter Avalos fwd->connect_host = NULL; 247036e94dc5SPeter Avalos free(fwd->connect_path); 247136e94dc5SPeter Avalos fwd->connect_path = NULL; 247236e94dc5SPeter Avalos free(fwd->listen_host); 2473cb5eb4f1SPeter Avalos fwd->listen_host = NULL; 247436e94dc5SPeter Avalos free(fwd->listen_path); 247536e94dc5SPeter Avalos fwd->listen_path = NULL; 247618de8d7fSPeter Avalos return (0); 247718de8d7fSPeter Avalos } 2478e9778795SPeter Avalos 2479e9778795SPeter Avalos int 2480e9778795SPeter Avalos parse_jump(const char *s, Options *o, int active) 2481e9778795SPeter Avalos { 2482e9778795SPeter Avalos char *orig, *sdup, *cp; 2483e9778795SPeter Avalos char *host = NULL, *user = NULL; 2484e9778795SPeter Avalos int ret = -1, port = -1, first; 2485e9778795SPeter Avalos 2486e9778795SPeter Avalos active &= o->proxy_command == NULL && o->jump_host == NULL; 2487e9778795SPeter Avalos 2488e9778795SPeter Avalos orig = sdup = xstrdup(s); 2489e9778795SPeter Avalos first = active; 2490e9778795SPeter Avalos do { 2491664f4763Szrj if (strcasecmp(s, "none") == 0) 2492664f4763Szrj break; 2493e9778795SPeter Avalos if ((cp = strrchr(sdup, ',')) == NULL) 2494e9778795SPeter Avalos cp = sdup; /* last */ 2495e9778795SPeter Avalos else 2496e9778795SPeter Avalos *cp++ = '\0'; 2497e9778795SPeter Avalos 2498e9778795SPeter Avalos if (first) { 2499e9778795SPeter Avalos /* First argument and configuration is active */ 2500664f4763Szrj if (parse_ssh_uri(cp, &user, &host, &port) == -1 || 2501664f4763Szrj parse_user_host_port(cp, &user, &host, &port) != 0) 2502e9778795SPeter Avalos goto out; 2503e9778795SPeter Avalos } else { 2504e9778795SPeter Avalos /* Subsequent argument or inactive configuration */ 2505664f4763Szrj if (parse_ssh_uri(cp, NULL, NULL, NULL) == -1 || 2506664f4763Szrj parse_user_host_port(cp, NULL, NULL, NULL) != 0) 2507e9778795SPeter Avalos goto out; 2508e9778795SPeter Avalos } 2509e9778795SPeter Avalos first = 0; /* only check syntax for subsequent hosts */ 2510e9778795SPeter Avalos } while (cp != sdup); 2511e9778795SPeter Avalos /* success */ 2512e9778795SPeter Avalos if (active) { 2513664f4763Szrj if (strcasecmp(s, "none") == 0) { 2514664f4763Szrj o->jump_host = xstrdup("none"); 2515664f4763Szrj o->jump_port = 0; 2516664f4763Szrj } else { 2517e9778795SPeter Avalos o->jump_user = user; 2518e9778795SPeter Avalos o->jump_host = host; 2519e9778795SPeter Avalos o->jump_port = port; 2520e9778795SPeter Avalos o->proxy_command = xstrdup("none"); 2521e9778795SPeter Avalos user = host = NULL; 2522e9778795SPeter Avalos if ((cp = strrchr(s, ',')) != NULL && cp != s) { 2523e9778795SPeter Avalos o->jump_extra = xstrdup(s); 2524e9778795SPeter Avalos o->jump_extra[cp - s] = '\0'; 2525e9778795SPeter Avalos } 2526e9778795SPeter Avalos } 2527664f4763Szrj } 2528e9778795SPeter Avalos ret = 0; 2529e9778795SPeter Avalos out: 2530e9778795SPeter Avalos free(orig); 2531e9778795SPeter Avalos free(user); 2532e9778795SPeter Avalos free(host); 2533e9778795SPeter Avalos return ret; 2534e9778795SPeter Avalos } 2535e9778795SPeter Avalos 2536664f4763Szrj int 2537664f4763Szrj parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp) 2538664f4763Szrj { 2539664f4763Szrj char *path; 2540664f4763Szrj int r; 2541664f4763Szrj 2542664f4763Szrj r = parse_uri("ssh", uri, userp, hostp, portp, &path); 2543664f4763Szrj if (r == 0 && path != NULL) 2544664f4763Szrj r = -1; /* path not allowed */ 2545664f4763Szrj return r; 2546664f4763Szrj } 2547664f4763Szrj 2548e9778795SPeter Avalos /* XXX the following is a near-vebatim copy from servconf.c; refactor */ 2549e9778795SPeter Avalos static const char * 2550e9778795SPeter Avalos fmt_multistate_int(int val, const struct multistate *m) 2551e9778795SPeter Avalos { 2552e9778795SPeter Avalos u_int i; 2553e9778795SPeter Avalos 2554e9778795SPeter Avalos for (i = 0; m[i].key != NULL; i++) { 2555e9778795SPeter Avalos if (m[i].value == val) 2556e9778795SPeter Avalos return m[i].key; 2557e9778795SPeter Avalos } 2558e9778795SPeter Avalos return "UNKNOWN"; 2559e9778795SPeter Avalos } 2560e9778795SPeter Avalos 2561e9778795SPeter Avalos static const char * 2562e9778795SPeter Avalos fmt_intarg(OpCodes code, int val) 2563e9778795SPeter Avalos { 2564e9778795SPeter Avalos if (val == -1) 2565e9778795SPeter Avalos return "unset"; 2566e9778795SPeter Avalos switch (code) { 2567e9778795SPeter Avalos case oAddressFamily: 2568e9778795SPeter Avalos return fmt_multistate_int(val, multistate_addressfamily); 2569e9778795SPeter Avalos case oVerifyHostKeyDNS: 2570e9778795SPeter Avalos case oUpdateHostkeys: 2571e9778795SPeter Avalos return fmt_multistate_int(val, multistate_yesnoask); 2572ce74bacaSMatthew Dillon case oStrictHostKeyChecking: 2573ce74bacaSMatthew Dillon return fmt_multistate_int(val, multistate_strict_hostkey); 2574e9778795SPeter Avalos case oControlMaster: 2575e9778795SPeter Avalos return fmt_multistate_int(val, multistate_controlmaster); 2576e9778795SPeter Avalos case oTunnel: 2577e9778795SPeter Avalos return fmt_multistate_int(val, multistate_tunnel); 2578e9778795SPeter Avalos case oRequestTTY: 2579e9778795SPeter Avalos return fmt_multistate_int(val, multistate_requesttty); 2580e9778795SPeter Avalos case oCanonicalizeHostname: 2581e9778795SPeter Avalos return fmt_multistate_int(val, multistate_canonicalizehostname); 2582664f4763Szrj case oAddKeysToAgent: 2583664f4763Szrj return fmt_multistate_int(val, multistate_yesnoaskconfirm); 2584e9778795SPeter Avalos case oFingerprintHash: 2585e9778795SPeter Avalos return ssh_digest_alg_name(val); 2586e9778795SPeter Avalos default: 2587e9778795SPeter Avalos switch (val) { 2588e9778795SPeter Avalos case 0: 2589e9778795SPeter Avalos return "no"; 2590e9778795SPeter Avalos case 1: 2591e9778795SPeter Avalos return "yes"; 2592e9778795SPeter Avalos default: 2593e9778795SPeter Avalos return "UNKNOWN"; 2594e9778795SPeter Avalos } 2595e9778795SPeter Avalos } 2596e9778795SPeter Avalos } 2597e9778795SPeter Avalos 2598e9778795SPeter Avalos static const char * 2599e9778795SPeter Avalos lookup_opcode_name(OpCodes code) 2600e9778795SPeter Avalos { 2601e9778795SPeter Avalos u_int i; 2602e9778795SPeter Avalos 2603e9778795SPeter Avalos for (i = 0; keywords[i].name != NULL; i++) 2604e9778795SPeter Avalos if (keywords[i].opcode == code) 2605e9778795SPeter Avalos return(keywords[i].name); 2606e9778795SPeter Avalos return "UNKNOWN"; 2607e9778795SPeter Avalos } 2608e9778795SPeter Avalos 2609e9778795SPeter Avalos static void 2610e9778795SPeter Avalos dump_cfg_int(OpCodes code, int val) 2611e9778795SPeter Avalos { 2612e9778795SPeter Avalos printf("%s %d\n", lookup_opcode_name(code), val); 2613e9778795SPeter Avalos } 2614e9778795SPeter Avalos 2615e9778795SPeter Avalos static void 2616e9778795SPeter Avalos dump_cfg_fmtint(OpCodes code, int val) 2617e9778795SPeter Avalos { 2618e9778795SPeter Avalos printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val)); 2619e9778795SPeter Avalos } 2620e9778795SPeter Avalos 2621e9778795SPeter Avalos static void 2622e9778795SPeter Avalos dump_cfg_string(OpCodes code, const char *val) 2623e9778795SPeter Avalos { 2624e9778795SPeter Avalos if (val == NULL) 2625e9778795SPeter Avalos return; 2626e9778795SPeter Avalos printf("%s %s\n", lookup_opcode_name(code), val); 2627e9778795SPeter Avalos } 2628e9778795SPeter Avalos 2629e9778795SPeter Avalos static void 2630e9778795SPeter Avalos dump_cfg_strarray(OpCodes code, u_int count, char **vals) 2631e9778795SPeter Avalos { 2632e9778795SPeter Avalos u_int i; 2633e9778795SPeter Avalos 2634e9778795SPeter Avalos for (i = 0; i < count; i++) 2635e9778795SPeter Avalos printf("%s %s\n", lookup_opcode_name(code), vals[i]); 2636e9778795SPeter Avalos } 2637e9778795SPeter Avalos 2638e9778795SPeter Avalos static void 2639e9778795SPeter Avalos dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals) 2640e9778795SPeter Avalos { 2641e9778795SPeter Avalos u_int i; 2642e9778795SPeter Avalos 2643e9778795SPeter Avalos printf("%s", lookup_opcode_name(code)); 2644e9778795SPeter Avalos for (i = 0; i < count; i++) 2645e9778795SPeter Avalos printf(" %s", vals[i]); 2646e9778795SPeter Avalos printf("\n"); 2647e9778795SPeter Avalos } 2648e9778795SPeter Avalos 2649e9778795SPeter Avalos static void 2650e9778795SPeter Avalos dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds) 2651e9778795SPeter Avalos { 2652e9778795SPeter Avalos const struct Forward *fwd; 2653e9778795SPeter Avalos u_int i; 2654e9778795SPeter Avalos 2655e9778795SPeter Avalos /* oDynamicForward */ 2656e9778795SPeter Avalos for (i = 0; i < count; i++) { 2657e9778795SPeter Avalos fwd = &fwds[i]; 2658ce74bacaSMatthew Dillon if (code == oDynamicForward && fwd->connect_host != NULL && 2659e9778795SPeter Avalos strcmp(fwd->connect_host, "socks") != 0) 2660e9778795SPeter Avalos continue; 2661ce74bacaSMatthew Dillon if (code == oLocalForward && fwd->connect_host != NULL && 2662e9778795SPeter Avalos strcmp(fwd->connect_host, "socks") == 0) 2663e9778795SPeter Avalos continue; 2664e9778795SPeter Avalos printf("%s", lookup_opcode_name(code)); 2665e9778795SPeter Avalos if (fwd->listen_port == PORT_STREAMLOCAL) 2666e9778795SPeter Avalos printf(" %s", fwd->listen_path); 2667e9778795SPeter Avalos else if (fwd->listen_host == NULL) 2668e9778795SPeter Avalos printf(" %d", fwd->listen_port); 2669e9778795SPeter Avalos else { 2670e9778795SPeter Avalos printf(" [%s]:%d", 2671e9778795SPeter Avalos fwd->listen_host, fwd->listen_port); 2672e9778795SPeter Avalos } 2673e9778795SPeter Avalos if (code != oDynamicForward) { 2674e9778795SPeter Avalos if (fwd->connect_port == PORT_STREAMLOCAL) 2675e9778795SPeter Avalos printf(" %s", fwd->connect_path); 2676e9778795SPeter Avalos else if (fwd->connect_host == NULL) 2677e9778795SPeter Avalos printf(" %d", fwd->connect_port); 2678e9778795SPeter Avalos else { 2679e9778795SPeter Avalos printf(" [%s]:%d", 2680e9778795SPeter Avalos fwd->connect_host, fwd->connect_port); 2681e9778795SPeter Avalos } 2682e9778795SPeter Avalos } 2683e9778795SPeter Avalos printf("\n"); 2684e9778795SPeter Avalos } 2685e9778795SPeter Avalos } 2686e9778795SPeter Avalos 2687e9778795SPeter Avalos void 2688e9778795SPeter Avalos dump_client_config(Options *o, const char *host) 2689e9778795SPeter Avalos { 2690*0cbfa66cSDaniel Fojt int i, r; 2691664f4763Szrj char buf[8], *all_key; 2692e9778795SPeter Avalos 2693*0cbfa66cSDaniel Fojt /* 2694*0cbfa66cSDaniel Fojt * Expand HostKeyAlgorithms name lists. This isn't handled in 2695*0cbfa66cSDaniel Fojt * fill_default_options() like the other algorithm lists because 2696*0cbfa66cSDaniel Fojt * the host key algorithms are by default dynamically chosen based 2697*0cbfa66cSDaniel Fojt * on the host's keys found in known_hosts. 2698*0cbfa66cSDaniel Fojt */ 2699664f4763Szrj all_key = sshkey_alg_list(0, 0, 1, ','); 2700*0cbfa66cSDaniel Fojt if ((r = kex_assemble_names(&o->hostkeyalgorithms, kex_default_pk_alg(), 2701*0cbfa66cSDaniel Fojt all_key)) != 0) 2702*0cbfa66cSDaniel Fojt fatal("%s: expand HostKeyAlgorithms: %s", __func__, ssh_err(r)); 2703664f4763Szrj free(all_key); 2704e9778795SPeter Avalos 2705e9778795SPeter Avalos /* Most interesting options first: user, host, port */ 2706e9778795SPeter Avalos dump_cfg_string(oUser, o->user); 2707*0cbfa66cSDaniel Fojt dump_cfg_string(oHostname, host); 2708e9778795SPeter Avalos dump_cfg_int(oPort, o->port); 2709e9778795SPeter Avalos 2710e9778795SPeter Avalos /* Flag options */ 2711664f4763Szrj dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent); 2712e9778795SPeter Avalos dump_cfg_fmtint(oAddressFamily, o->address_family); 2713e9778795SPeter Avalos dump_cfg_fmtint(oBatchMode, o->batch_mode); 2714e9778795SPeter Avalos dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local); 2715e9778795SPeter Avalos dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname); 2716e9778795SPeter Avalos dump_cfg_fmtint(oChallengeResponseAuthentication, o->challenge_response_authentication); 2717e9778795SPeter Avalos dump_cfg_fmtint(oCheckHostIP, o->check_host_ip); 2718e9778795SPeter Avalos dump_cfg_fmtint(oCompression, o->compression); 2719e9778795SPeter Avalos dump_cfg_fmtint(oControlMaster, o->control_master); 2720e9778795SPeter Avalos dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign); 2721e9778795SPeter Avalos dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings); 2722e9778795SPeter Avalos dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure); 2723e9778795SPeter Avalos dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash); 2724e9778795SPeter Avalos dump_cfg_fmtint(oForwardX11, o->forward_x11); 2725e9778795SPeter Avalos dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted); 2726e9778795SPeter Avalos dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports); 2727e9778795SPeter Avalos #ifdef GSSAPI 2728e9778795SPeter Avalos dump_cfg_fmtint(oGssAuthentication, o->gss_authentication); 2729e9778795SPeter Avalos dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds); 2730e9778795SPeter Avalos #endif /* GSSAPI */ 2731e9778795SPeter Avalos dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts); 2732e9778795SPeter Avalos dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication); 2733e9778795SPeter Avalos dump_cfg_fmtint(oIdentitiesOnly, o->identities_only); 2734e9778795SPeter Avalos dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication); 2735e9778795SPeter Avalos dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost); 2736e9778795SPeter Avalos dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication); 2737e9778795SPeter Avalos dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command); 2738e9778795SPeter Avalos dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass); 2739e9778795SPeter Avalos dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication); 2740e9778795SPeter Avalos dump_cfg_fmtint(oRequestTTY, o->request_tty); 2741e9778795SPeter Avalos dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); 2742e9778795SPeter Avalos dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking); 2743e9778795SPeter Avalos dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive); 2744e9778795SPeter Avalos dump_cfg_fmtint(oTunnel, o->tun_open); 2745e9778795SPeter Avalos dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns); 2746e9778795SPeter Avalos dump_cfg_fmtint(oVisualHostKey, o->visual_host_key); 2747e9778795SPeter Avalos dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys); 2748e9778795SPeter Avalos 2749e9778795SPeter Avalos /* Integer options */ 2750e9778795SPeter Avalos dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots); 2751e9778795SPeter Avalos dump_cfg_int(oConnectionAttempts, o->connection_attempts); 2752e9778795SPeter Avalos dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout); 2753e9778795SPeter Avalos dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts); 2754e9778795SPeter Avalos dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max); 2755e9778795SPeter Avalos dump_cfg_int(oServerAliveInterval, o->server_alive_interval); 2756e9778795SPeter Avalos 2757e9778795SPeter Avalos /* String options */ 2758e9778795SPeter Avalos dump_cfg_string(oBindAddress, o->bind_address); 2759664f4763Szrj dump_cfg_string(oBindInterface, o->bind_interface); 2760*0cbfa66cSDaniel Fojt dump_cfg_string(oCiphers, o->ciphers); 2761e9778795SPeter Avalos dump_cfg_string(oControlPath, o->control_path); 2762e9778795SPeter Avalos dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms); 2763e9778795SPeter Avalos dump_cfg_string(oHostKeyAlias, o->host_key_alias); 2764e9778795SPeter Avalos dump_cfg_string(oHostbasedKeyTypes, o->hostbased_key_types); 2765e9778795SPeter Avalos dump_cfg_string(oIdentityAgent, o->identity_agent); 2766664f4763Szrj dump_cfg_string(oIgnoreUnknown, o->ignored_unknown); 2767e9778795SPeter Avalos dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices); 2768*0cbfa66cSDaniel Fojt dump_cfg_string(oKexAlgorithms, o->kex_algorithms); 2769*0cbfa66cSDaniel Fojt dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms); 2770e9778795SPeter Avalos dump_cfg_string(oLocalCommand, o->local_command); 2771ce74bacaSMatthew Dillon dump_cfg_string(oRemoteCommand, o->remote_command); 2772e9778795SPeter Avalos dump_cfg_string(oLogLevel, log_level_name(o->log_level)); 2773*0cbfa66cSDaniel Fojt dump_cfg_string(oMacs, o->macs); 2774ce74bacaSMatthew Dillon #ifdef ENABLE_PKCS11 2775e9778795SPeter Avalos dump_cfg_string(oPKCS11Provider, o->pkcs11_provider); 2776ce74bacaSMatthew Dillon #endif 2777*0cbfa66cSDaniel Fojt dump_cfg_string(oSecurityKeyProvider, o->sk_provider); 2778e9778795SPeter Avalos dump_cfg_string(oPreferredAuthentications, o->preferred_authentications); 2779e9778795SPeter Avalos dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types); 2780e9778795SPeter Avalos dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys); 2781e9778795SPeter Avalos dump_cfg_string(oXAuthLocation, o->xauth_location); 2782e9778795SPeter Avalos 2783e9778795SPeter Avalos /* Forwards */ 2784e9778795SPeter Avalos dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards); 2785e9778795SPeter Avalos dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards); 2786e9778795SPeter Avalos dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards); 2787e9778795SPeter Avalos 2788e9778795SPeter Avalos /* String array options */ 2789e9778795SPeter Avalos dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files); 2790e9778795SPeter Avalos dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains); 2791664f4763Szrj dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files); 2792e9778795SPeter Avalos dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles); 2793e9778795SPeter Avalos dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles); 2794e9778795SPeter Avalos dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env); 2795664f4763Szrj dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv); 2796e9778795SPeter Avalos 2797e9778795SPeter Avalos /* Special cases */ 2798e9778795SPeter Avalos 2799*0cbfa66cSDaniel Fojt /* oForwardAgent */ 2800*0cbfa66cSDaniel Fojt if (o->forward_agent_sock_path == NULL) 2801*0cbfa66cSDaniel Fojt dump_cfg_fmtint(oForwardAgent, o->forward_agent); 2802*0cbfa66cSDaniel Fojt else 2803*0cbfa66cSDaniel Fojt dump_cfg_string(oForwardAgent, o->forward_agent_sock_path); 2804*0cbfa66cSDaniel Fojt 2805e9778795SPeter Avalos /* oConnectTimeout */ 2806e9778795SPeter Avalos if (o->connection_timeout == -1) 2807e9778795SPeter Avalos printf("connecttimeout none\n"); 2808e9778795SPeter Avalos else 2809e9778795SPeter Avalos dump_cfg_int(oConnectTimeout, o->connection_timeout); 2810e9778795SPeter Avalos 2811e9778795SPeter Avalos /* oTunnelDevice */ 2812e9778795SPeter Avalos printf("tunneldevice"); 2813e9778795SPeter Avalos if (o->tun_local == SSH_TUNID_ANY) 2814e9778795SPeter Avalos printf(" any"); 2815e9778795SPeter Avalos else 2816e9778795SPeter Avalos printf(" %d", o->tun_local); 2817e9778795SPeter Avalos if (o->tun_remote == SSH_TUNID_ANY) 2818e9778795SPeter Avalos printf(":any"); 2819e9778795SPeter Avalos else 2820e9778795SPeter Avalos printf(":%d", o->tun_remote); 2821e9778795SPeter Avalos printf("\n"); 2822e9778795SPeter Avalos 2823e9778795SPeter Avalos /* oCanonicalizePermittedCNAMEs */ 2824e9778795SPeter Avalos if ( o->num_permitted_cnames > 0) { 2825e9778795SPeter Avalos printf("canonicalizePermittedcnames"); 2826e9778795SPeter Avalos for (i = 0; i < o->num_permitted_cnames; i++) { 2827e9778795SPeter Avalos printf(" %s:%s", o->permitted_cnames[i].source_list, 2828e9778795SPeter Avalos o->permitted_cnames[i].target_list); 2829e9778795SPeter Avalos } 2830e9778795SPeter Avalos printf("\n"); 2831e9778795SPeter Avalos } 2832e9778795SPeter Avalos 2833e9778795SPeter Avalos /* oControlPersist */ 2834e9778795SPeter Avalos if (o->control_persist == 0 || o->control_persist_timeout == 0) 2835e9778795SPeter Avalos dump_cfg_fmtint(oControlPersist, o->control_persist); 2836e9778795SPeter Avalos else 2837e9778795SPeter Avalos dump_cfg_int(oControlPersist, o->control_persist_timeout); 2838e9778795SPeter Avalos 2839e9778795SPeter Avalos /* oEscapeChar */ 2840e9778795SPeter Avalos if (o->escape_char == SSH_ESCAPECHAR_NONE) 2841e9778795SPeter Avalos printf("escapechar none\n"); 2842e9778795SPeter Avalos else { 2843e9778795SPeter Avalos vis(buf, o->escape_char, VIS_WHITE, 0); 2844e9778795SPeter Avalos printf("escapechar %s\n", buf); 2845e9778795SPeter Avalos } 2846e9778795SPeter Avalos 2847e9778795SPeter Avalos /* oIPQoS */ 2848e9778795SPeter Avalos printf("ipqos %s ", iptos2str(o->ip_qos_interactive)); 2849e9778795SPeter Avalos printf("%s\n", iptos2str(o->ip_qos_bulk)); 2850e9778795SPeter Avalos 2851e9778795SPeter Avalos /* oRekeyLimit */ 2852e9778795SPeter Avalos printf("rekeylimit %llu %d\n", 2853e9778795SPeter Avalos (unsigned long long)o->rekey_limit, o->rekey_interval); 2854e9778795SPeter Avalos 2855e9778795SPeter Avalos /* oStreamLocalBindMask */ 2856e9778795SPeter Avalos printf("streamlocalbindmask 0%o\n", 2857e9778795SPeter Avalos o->fwd_opts.streamlocal_bind_mask); 2858e9778795SPeter Avalos 2859664f4763Szrj /* oLogFacility */ 2860664f4763Szrj printf("syslogfacility %s\n", log_facility_name(o->log_facility)); 2861664f4763Szrj 2862e9778795SPeter Avalos /* oProxyCommand / oProxyJump */ 2863e9778795SPeter Avalos if (o->jump_host == NULL) 2864e9778795SPeter Avalos dump_cfg_string(oProxyCommand, o->proxy_command); 2865e9778795SPeter Avalos else { 2866e9778795SPeter Avalos /* Check for numeric addresses */ 2867e9778795SPeter Avalos i = strchr(o->jump_host, ':') != NULL || 2868e9778795SPeter Avalos strspn(o->jump_host, "1234567890.") == strlen(o->jump_host); 2869e9778795SPeter Avalos snprintf(buf, sizeof(buf), "%d", o->jump_port); 2870e9778795SPeter Avalos printf("proxyjump %s%s%s%s%s%s%s%s%s\n", 2871e9778795SPeter Avalos /* optional additional jump spec */ 2872e9778795SPeter Avalos o->jump_extra == NULL ? "" : o->jump_extra, 2873e9778795SPeter Avalos o->jump_extra == NULL ? "" : ",", 2874e9778795SPeter Avalos /* optional user */ 2875e9778795SPeter Avalos o->jump_user == NULL ? "" : o->jump_user, 2876e9778795SPeter Avalos o->jump_user == NULL ? "" : "@", 2877e9778795SPeter Avalos /* opening [ if hostname is numeric */ 2878e9778795SPeter Avalos i ? "[" : "", 2879e9778795SPeter Avalos /* mandatory hostname */ 2880e9778795SPeter Avalos o->jump_host, 2881e9778795SPeter Avalos /* closing ] if hostname is numeric */ 2882e9778795SPeter Avalos i ? "]" : "", 2883e9778795SPeter Avalos /* optional port number */ 2884e9778795SPeter Avalos o->jump_port <= 0 ? "" : ":", 2885e9778795SPeter Avalos o->jump_port <= 0 ? "" : buf); 2886e9778795SPeter Avalos } 2887e9778795SPeter Avalos } 2888