readconf.c revision 224638
1221420Sdes/* $OpenBSD: readconf.c,v 1.190 2010/11/13 23:27:50 djm Exp $ */ 2224638Sbrooks/* $FreeBSD: head/crypto/openssh/readconf.c 224638 2011-08-03 19:14:22Z brooks $ */ 357429Smarkm/* 457429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 557429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 657429Smarkm * All rights reserved 757429Smarkm * Functions for reading the configuration files. 860576Skris * 965674Skris * As far as I am concerned, the code I have written for this software 1065674Skris * can be used freely for any purpose. Any derived versions of this 1165674Skris * software must be clearly marked as such, and if the derived work is 1265674Skris * incompatible with the protocol description in the RFC file, it must be 1365674Skris * called by a name other than "ssh" or "Secure Shell". 1457429Smarkm */ 1557429Smarkm 1657429Smarkm#include "includes.h" 17162856Sdes__RCSID("$FreeBSD: head/crypto/openssh/readconf.c 224638 2011-08-03 19:14:22Z brooks $"); 1857429Smarkm 19162856Sdes#include <sys/types.h> 20162856Sdes#include <sys/stat.h> 21162856Sdes#include <sys/socket.h> 22181918Sdes#include <sys/sysctl.h> 23162856Sdes 24162856Sdes#include <netinet/in.h> 25221420Sdes#include <netinet/in_systm.h> 26221420Sdes#include <netinet/ip.h> 27162856Sdes 28162856Sdes#include <ctype.h> 29162856Sdes#include <errno.h> 30162856Sdes#include <netdb.h> 31162856Sdes#include <signal.h> 32162856Sdes#include <stdarg.h> 33162856Sdes#include <stdio.h> 34162856Sdes#include <string.h> 35162856Sdes#include <unistd.h> 36162856Sdes 37162856Sdes#include "xmalloc.h" 3857429Smarkm#include "ssh.h" 3976262Sgreen#include "compat.h" 4076262Sgreen#include "cipher.h" 4176262Sgreen#include "pathnames.h" 4276262Sgreen#include "log.h" 43162856Sdes#include "key.h" 4457429Smarkm#include "readconf.h" 4560576Skris#include "match.h" 4676262Sgreen#include "misc.h" 47162856Sdes#include "buffer.h" 4876262Sgreen#include "kex.h" 4976262Sgreen#include "mac.h" 50192595Sdes#include "version.h" 5157429Smarkm 5257429Smarkm/* Format of the configuration file: 5357429Smarkm 5457429Smarkm # Configuration data is parsed as follows: 5557429Smarkm # 1. command line options 5657429Smarkm # 2. user-specific file 5757429Smarkm # 3. system-wide file 5857429Smarkm # Any configuration value is only changed the first time it is set. 5957429Smarkm # Thus, host-specific definitions should be at the beginning of the 6057429Smarkm # configuration file, and defaults at the end. 6157429Smarkm 6257429Smarkm # Host-specific declarations. These may override anything above. A single 6357429Smarkm # host may match multiple declarations; these are processed in the order 6457429Smarkm # that they are given in. 6557429Smarkm 6657429Smarkm Host *.ngs.fi ngs.fi 6798684Sdes User foo 6857429Smarkm 6957429Smarkm Host fake.com 7057429Smarkm HostName another.host.name.real.org 7157429Smarkm User blaah 7257429Smarkm Port 34289 7357429Smarkm ForwardX11 no 7457429Smarkm ForwardAgent no 7557429Smarkm 7657429Smarkm Host books.com 7757429Smarkm RemoteForward 9999 shadows.cs.hut.fi:9999 7857429Smarkm Cipher 3des 7957429Smarkm 8057429Smarkm Host fascist.blob.com 8157429Smarkm Port 23123 8257429Smarkm User tylonen 8357429Smarkm PasswordAuthentication no 8457429Smarkm 8557429Smarkm Host puukko.hut.fi 8657429Smarkm User t35124p 8757429Smarkm ProxyCommand ssh-proxy %h %p 8857429Smarkm 8957429Smarkm Host *.fr 9098684Sdes PublicKeyAuthentication no 9157429Smarkm 9257429Smarkm Host *.su 9357429Smarkm Cipher none 9457429Smarkm PasswordAuthentication no 9557429Smarkm 96157019Sdes Host vpn.fake.com 97157019Sdes Tunnel yes 98157019Sdes TunnelDevice 3 99157019Sdes 10057429Smarkm # Defaults for various options 10157429Smarkm Host * 10257429Smarkm ForwardAgent no 10376262Sgreen ForwardX11 no 10457429Smarkm PasswordAuthentication yes 10557429Smarkm RSAAuthentication yes 10657429Smarkm RhostsRSAAuthentication yes 10757429Smarkm StrictHostKeyChecking yes 108126277Sdes TcpKeepAlive no 10957429Smarkm IdentityFile ~/.ssh/identity 11057429Smarkm Port 22 11157429Smarkm EscapeChar ~ 11257429Smarkm 11357429Smarkm*/ 11457429Smarkm 11557429Smarkm/* Keyword tokens. */ 11657429Smarkm 11757429Smarkmtypedef enum { 11857429Smarkm oBadOption, 119215116Sdes oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout, 120215116Sdes oGatewayPorts, oExitOnForwardFailure, 12198684Sdes oPasswordAuthentication, oRSAAuthentication, 12276262Sgreen oChallengeResponseAuthentication, oXAuthLocation, 12357429Smarkm oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, 12457429Smarkm oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, 12557429Smarkm oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, 12657429Smarkm oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, 127126277Sdes oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts, 12876262Sgreen oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs, 12976262Sgreen oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, 13076262Sgreen oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, 13176262Sgreen oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, 132204917Sdes oHostKeyAlgorithms, oBindAddress, oPKCS11Provider, 13393698Sdes oClearAllForwardings, oNoHostAuthenticationForLocalhost, 134124211Sdes oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, 135124211Sdes oAddressFamily, oGssAuthentication, oGssDelegateCreds, 136128461Sdes oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, 137215116Sdes oSendEnv, oControlPath, oControlMaster, oControlPersist, 138215116Sdes oHashKnownHosts, 139157019Sdes oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, 140197679Sdes oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication, 141221420Sdes oKexAlgorithms, oIPQoS, 142224638Sbrooks oHPNDisabled, oHPNBufferSize, oTcpRcvBufPoll, oTcpRcvBuf, 143224638Sbrooks#ifdef NONE_CIPHER_ENABLED 144224638Sbrooks oNoneEnabled, oNoneSwitch, 145224638Sbrooks#endif 14699048Sdes oVersionAddendum, 147124211Sdes oDeprecated, oUnsupported 14857429Smarkm} OpCodes; 14957429Smarkm 15057429Smarkm/* Textual representations of the tokens. */ 15157429Smarkm 15257429Smarkmstatic struct { 15357429Smarkm const char *name; 15457429Smarkm OpCodes opcode; 15557429Smarkm} keywords[] = { 15657429Smarkm { "forwardagent", oForwardAgent }, 15757429Smarkm { "forwardx11", oForwardX11 }, 158126277Sdes { "forwardx11trusted", oForwardX11Trusted }, 159215116Sdes { "forwardx11timeout", oForwardX11Timeout }, 160162856Sdes { "exitonforwardfailure", oExitOnForwardFailure }, 16165674Skris { "xauthlocation", oXAuthLocation }, 16257429Smarkm { "gatewayports", oGatewayPorts }, 16357429Smarkm { "useprivilegedport", oUsePrivilegedPort }, 164124211Sdes { "rhostsauthentication", oDeprecated }, 16557429Smarkm { "passwordauthentication", oPasswordAuthentication }, 16669591Sgreen { "kbdinteractiveauthentication", oKbdInteractiveAuthentication }, 16769591Sgreen { "kbdinteractivedevices", oKbdInteractiveDevices }, 16857429Smarkm { "rsaauthentication", oRSAAuthentication }, 16976262Sgreen { "pubkeyauthentication", oPubkeyAuthentication }, 17076262Sgreen { "dsaauthentication", oPubkeyAuthentication }, /* alias */ 17176262Sgreen { "rhostsrsaauthentication", oRhostsRSAAuthentication }, 17276262Sgreen { "hostbasedauthentication", oHostbasedAuthentication }, 17376262Sgreen { "challengeresponseauthentication", oChallengeResponseAuthentication }, 17476262Sgreen { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */ 17576262Sgreen { "tisauthentication", oChallengeResponseAuthentication }, /* alias */ 176124211Sdes { "kerberosauthentication", oUnsupported }, 177124211Sdes { "kerberostgtpassing", oUnsupported }, 178124211Sdes { "afstokenpassing", oUnsupported }, 179124211Sdes#if defined(GSSAPI) 180124211Sdes { "gssapiauthentication", oGssAuthentication }, 181124211Sdes { "gssapidelegatecredentials", oGssDelegateCreds }, 182124211Sdes#else 183124211Sdes { "gssapiauthentication", oUnsupported }, 184124211Sdes { "gssapidelegatecredentials", oUnsupported }, 18592559Sdes#endif 18698684Sdes { "fallbacktorsh", oDeprecated }, 18798684Sdes { "usersh", oDeprecated }, 18857429Smarkm { "identityfile", oIdentityFile }, 189192595Sdes { "identityfile2", oIdentityFile }, /* obsolete */ 190128460Sdes { "identitiesonly", oIdentitiesOnly }, 19157429Smarkm { "hostname", oHostName }, 19276262Sgreen { "hostkeyalias", oHostKeyAlias }, 19357429Smarkm { "proxycommand", oProxyCommand }, 19457429Smarkm { "port", oPort }, 19557429Smarkm { "cipher", oCipher }, 19660576Skris { "ciphers", oCiphers }, 19776262Sgreen { "macs", oMacs }, 19860576Skris { "protocol", oProtocol }, 19957429Smarkm { "remoteforward", oRemoteForward }, 20057429Smarkm { "localforward", oLocalForward }, 20157429Smarkm { "user", oUser }, 20257429Smarkm { "host", oHost }, 20357429Smarkm { "escapechar", oEscapeChar }, 20457429Smarkm { "globalknownhostsfile", oGlobalKnownHostsFile }, 205192595Sdes { "globalknownhostsfile2", oGlobalKnownHostsFile2 }, /* obsolete */ 206192595Sdes { "userknownhostsfile", oUserKnownHostsFile }, 20792559Sdes { "userknownhostsfile2", oUserKnownHostsFile2 }, /* obsolete */ 20857429Smarkm { "connectionattempts", oConnectionAttempts }, 20957429Smarkm { "batchmode", oBatchMode }, 21057429Smarkm { "checkhostip", oCheckHostIP }, 21157429Smarkm { "stricthostkeychecking", oStrictHostKeyChecking }, 21257429Smarkm { "compression", oCompression }, 21357429Smarkm { "compressionlevel", oCompressionLevel }, 214126277Sdes { "tcpkeepalive", oTCPKeepAlive }, 215126277Sdes { "keepalive", oTCPKeepAlive }, /* obsolete */ 21657429Smarkm { "numberofpasswordprompts", oNumberOfPasswordPrompts }, 21757429Smarkm { "loglevel", oLogLevel }, 21876262Sgreen { "dynamicforward", oDynamicForward }, 21976262Sgreen { "preferredauthentications", oPreferredAuthentications }, 22076262Sgreen { "hostkeyalgorithms", oHostKeyAlgorithms }, 22192559Sdes { "bindaddress", oBindAddress }, 222204917Sdes#ifdef ENABLE_PKCS11 223204917Sdes { "smartcarddevice", oPKCS11Provider }, 224204917Sdes { "pkcs11provider", oPKCS11Provider }, 225124211Sdes#else 226124211Sdes { "smartcarddevice", oUnsupported }, 227204917Sdes { "pkcs11provider", oUnsupported }, 228124211Sdes#endif 22992559Sdes { "clearallforwardings", oClearAllForwardings }, 230113911Sdes { "enablesshkeysign", oEnableSSHKeysign }, 231124211Sdes { "verifyhostkeydns", oVerifyHostKeyDNS }, 23292559Sdes { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost }, 233124211Sdes { "rekeylimit", oRekeyLimit }, 234124211Sdes { "connecttimeout", oConnectTimeout }, 235124211Sdes { "addressfamily", oAddressFamily }, 236126277Sdes { "serveraliveinterval", oServerAliveInterval }, 237126277Sdes { "serveralivecountmax", oServerAliveCountMax }, 238137019Sdes { "sendenv", oSendEnv }, 239137019Sdes { "controlpath", oControlPath }, 240137019Sdes { "controlmaster", oControlMaster }, 241215116Sdes { "controlpersist", oControlPersist }, 242147005Sdes { "hashknownhosts", oHashKnownHosts }, 243157019Sdes { "tunnel", oTunnel }, 244157019Sdes { "tunneldevice", oTunnelDevice }, 245157019Sdes { "localcommand", oLocalCommand }, 246157019Sdes { "permitlocalcommand", oPermitLocalCommand }, 247181111Sdes { "visualhostkey", oVisualHostKey }, 248197679Sdes { "useroaming", oUseRoaming }, 249192595Sdes#ifdef JPAKE 250192595Sdes { "zeroknowledgepasswordauthentication", 251192595Sdes oZeroKnowledgePasswordAuthentication }, 252192595Sdes#else 253192595Sdes { "zeroknowledgepasswordauthentication", oUnsupported }, 254192595Sdes#endif 255221420Sdes { "kexalgorithms", oKexAlgorithms }, 256221420Sdes { "ipqos", oIPQoS }, 257224638Sbrooks { "hpndisabled", oHPNDisabled }, 258224638Sbrooks { "hpnbuffersize", oHPNBufferSize }, 259224638Sbrooks { "tcprcvbufpoll", oTcpRcvBufPoll }, 260224638Sbrooks { "tcprcvbuf", oTcpRcvBuf }, 261224638Sbrooks#ifdef NONE_CIPHER_ENABLED 262224638Sbrooks { "noneenabled", oNoneEnabled }, 263224638Sbrooks { "noneswitch", oNoneSwitch }, 264224638Sbrooks#endif 265192595Sdes 26699048Sdes { "versionaddendum", oVersionAddendum }, 26792559Sdes { NULL, oBadOption } 26857429Smarkm}; 26957429Smarkm 27057429Smarkm/* 27157429Smarkm * Adds a local TCP/IP port forward to options. Never returns if there is an 27257429Smarkm * error. 27357429Smarkm */ 27457429Smarkm 27560576Skrisvoid 276147005Sdesadd_local_forward(Options *options, const Forward *newfwd) 27757429Smarkm{ 27857429Smarkm Forward *fwd; 279106130Sdes#ifndef NO_IPPORT_RESERVED_CONCEPT 28057429Smarkm extern uid_t original_real_uid; 281181918Sdes int ipport_reserved; 282181918Sdes#ifdef __FreeBSD__ 283181918Sdes size_t len_ipport_reserved = sizeof(ipport_reserved); 284181918Sdes 285181918Sdes if (sysctlbyname("net.inet.ip.portrange.reservedhigh", 286181918Sdes &ipport_reserved, &len_ipport_reserved, NULL, 0) != 0) 287181918Sdes ipport_reserved = IPPORT_RESERVED; 288181918Sdes else 289181918Sdes ipport_reserved++; 290181918Sdes#else 291181918Sdes ipport_reserved = IPPORT_RESERVED; 292181918Sdes#endif 293181918Sdes if (newfwd->listen_port < ipport_reserved && original_real_uid != 0) 29476262Sgreen fatal("Privileged ports can only be forwarded by root."); 29598941Sdes#endif 296215116Sdes options->local_forwards = xrealloc(options->local_forwards, 297215116Sdes options->num_local_forwards + 1, 298215116Sdes sizeof(*options->local_forwards)); 29957429Smarkm fwd = &options->local_forwards[options->num_local_forwards++]; 300147005Sdes 301192595Sdes fwd->listen_host = newfwd->listen_host; 302147005Sdes fwd->listen_port = newfwd->listen_port; 303192595Sdes fwd->connect_host = newfwd->connect_host; 304147005Sdes fwd->connect_port = newfwd->connect_port; 30557429Smarkm} 30657429Smarkm 30757429Smarkm/* 30857429Smarkm * Adds a remote TCP/IP port forward to options. Never returns if there is 30957429Smarkm * an error. 31057429Smarkm */ 31157429Smarkm 31260576Skrisvoid 313147005Sdesadd_remote_forward(Options *options, const Forward *newfwd) 31457429Smarkm{ 31557429Smarkm Forward *fwd; 316215116Sdes 317215116Sdes options->remote_forwards = xrealloc(options->remote_forwards, 318215116Sdes options->num_remote_forwards + 1, 319215116Sdes sizeof(*options->remote_forwards)); 32057429Smarkm fwd = &options->remote_forwards[options->num_remote_forwards++]; 321147005Sdes 322192595Sdes fwd->listen_host = newfwd->listen_host; 323147005Sdes fwd->listen_port = newfwd->listen_port; 324192595Sdes fwd->connect_host = newfwd->connect_host; 325147005Sdes fwd->connect_port = newfwd->connect_port; 326215116Sdes fwd->allocated_port = 0; 32757429Smarkm} 32857429Smarkm 32992559Sdesstatic void 33092559Sdesclear_forwardings(Options *options) 33192559Sdes{ 33292559Sdes int i; 33392559Sdes 334147005Sdes for (i = 0; i < options->num_local_forwards; i++) { 335147005Sdes if (options->local_forwards[i].listen_host != NULL) 336147005Sdes xfree(options->local_forwards[i].listen_host); 337147005Sdes xfree(options->local_forwards[i].connect_host); 338147005Sdes } 339215116Sdes if (options->num_local_forwards > 0) { 340215116Sdes xfree(options->local_forwards); 341215116Sdes options->local_forwards = NULL; 342215116Sdes } 34392559Sdes options->num_local_forwards = 0; 344147005Sdes for (i = 0; i < options->num_remote_forwards; i++) { 345147005Sdes if (options->remote_forwards[i].listen_host != NULL) 346147005Sdes xfree(options->remote_forwards[i].listen_host); 347147005Sdes xfree(options->remote_forwards[i].connect_host); 348147005Sdes } 349215116Sdes if (options->num_remote_forwards > 0) { 350215116Sdes xfree(options->remote_forwards); 351215116Sdes options->remote_forwards = NULL; 352215116Sdes } 35392559Sdes options->num_remote_forwards = 0; 354157019Sdes options->tun_open = SSH_TUNMODE_NO; 35592559Sdes} 35692559Sdes 35757429Smarkm/* 35876262Sgreen * Returns the number of the token pointed to by cp or oBadOption. 35957429Smarkm */ 36057429Smarkm 36160576Skrisstatic OpCodes 36257429Smarkmparse_token(const char *cp, const char *filename, int linenum) 36357429Smarkm{ 36476262Sgreen u_int i; 36557429Smarkm 36657429Smarkm for (i = 0; keywords[i].name; i++) 36757429Smarkm if (strcasecmp(cp, keywords[i].name) == 0) 36857429Smarkm return keywords[i].opcode; 36957429Smarkm 37076262Sgreen error("%s: line %d: Bad configuration option: %s", 37176262Sgreen filename, linenum, cp); 37257429Smarkm return oBadOption; 37357429Smarkm} 37457429Smarkm 37557429Smarkm/* 37657429Smarkm * Processes a single option line as used in the configuration files. This 37757429Smarkm * only sets those values that have not already been set. 37857429Smarkm */ 379113911Sdes#define WHITESPACE " \t\r\n" 38057429Smarkm 38157429Smarkmint 38257429Smarkmprocess_config_line(Options *options, const char *host, 38357429Smarkm char *line, const char *filename, int linenum, 38457429Smarkm int *activep) 38557429Smarkm{ 386147005Sdes char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256]; 387162856Sdes int opcode, *intptr, value, value2, scale; 388181111Sdes LogLevel *log_level_ptr; 389162856Sdes long long orig, val64; 390113911Sdes size_t len; 391147005Sdes Forward fwd; 39257429Smarkm 393124211Sdes /* Strip trailing whitespace */ 394147005Sdes for (len = strlen(line) - 1; len > 0; len--) { 395124211Sdes if (strchr(WHITESPACE, line[len]) == NULL) 396124211Sdes break; 397124211Sdes line[len] = '\0'; 398124211Sdes } 399124211Sdes 40065674Skris s = line; 40165674Skris /* Get the keyword. (Each line is supposed to begin with a keyword). */ 402162856Sdes if ((keyword = strdelim(&s)) == NULL) 403162856Sdes return 0; 40465674Skris /* Ignore leading whitespace. */ 40565674Skris if (*keyword == '\0') 40665674Skris keyword = strdelim(&s); 40776262Sgreen if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#') 40857429Smarkm return 0; 40957429Smarkm 41065674Skris opcode = parse_token(keyword, filename, linenum); 41157429Smarkm 41257429Smarkm switch (opcode) { 41357429Smarkm case oBadOption: 41457429Smarkm /* don't panic, but count bad options */ 41557429Smarkm return -1; 41657429Smarkm /* NOTREACHED */ 417124211Sdes case oConnectTimeout: 418124211Sdes intptr = &options->connection_timeout; 419126277Sdesparse_time: 420124211Sdes arg = strdelim(&s); 421124211Sdes if (!arg || *arg == '\0') 422124211Sdes fatal("%s line %d: missing time value.", 423124211Sdes filename, linenum); 424124211Sdes if ((value = convtime(arg)) == -1) 425124211Sdes fatal("%s line %d: invalid time value.", 426124211Sdes filename, linenum); 427181111Sdes if (*activep && *intptr == -1) 428124211Sdes *intptr = value; 429124211Sdes break; 430124211Sdes 43157429Smarkm case oForwardAgent: 43257429Smarkm intptr = &options->forward_agent; 43357429Smarkmparse_flag: 43465674Skris arg = strdelim(&s); 43565674Skris if (!arg || *arg == '\0') 43657429Smarkm fatal("%.200s line %d: Missing yes/no argument.", filename, linenum); 43757429Smarkm value = 0; /* To avoid compiler warning... */ 43865674Skris if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 43957429Smarkm value = 1; 44065674Skris else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 44157429Smarkm value = 0; 44257429Smarkm else 44357429Smarkm fatal("%.200s line %d: Bad yes/no argument.", filename, linenum); 44457429Smarkm if (*activep && *intptr == -1) 44557429Smarkm *intptr = value; 44657429Smarkm break; 44757429Smarkm 44857429Smarkm case oForwardX11: 44957429Smarkm intptr = &options->forward_x11; 45057429Smarkm goto parse_flag; 45157429Smarkm 452126277Sdes case oForwardX11Trusted: 453126277Sdes intptr = &options->forward_x11_trusted; 454126277Sdes goto parse_flag; 455215116Sdes 456215116Sdes case oForwardX11Timeout: 457215116Sdes intptr = &options->forward_x11_timeout; 458215116Sdes goto parse_time; 459126277Sdes 46057429Smarkm case oGatewayPorts: 46157429Smarkm intptr = &options->gateway_ports; 46257429Smarkm goto parse_flag; 46357429Smarkm 464162856Sdes case oExitOnForwardFailure: 465162856Sdes intptr = &options->exit_on_forward_failure; 466162856Sdes goto parse_flag; 467162856Sdes 46857429Smarkm case oUsePrivilegedPort: 46957429Smarkm intptr = &options->use_privileged_port; 47057429Smarkm goto parse_flag; 47157429Smarkm 47257429Smarkm case oPasswordAuthentication: 47357429Smarkm intptr = &options->password_authentication; 47457429Smarkm goto parse_flag; 47557429Smarkm 476192595Sdes case oZeroKnowledgePasswordAuthentication: 477192595Sdes intptr = &options->zero_knowledge_password_authentication; 478192595Sdes goto parse_flag; 479192595Sdes 48069591Sgreen case oKbdInteractiveAuthentication: 48169591Sgreen intptr = &options->kbd_interactive_authentication; 48269591Sgreen goto parse_flag; 48369591Sgreen 48469591Sgreen case oKbdInteractiveDevices: 48569591Sgreen charptr = &options->kbd_interactive_devices; 48669591Sgreen goto parse_string; 48769591Sgreen 48876262Sgreen case oPubkeyAuthentication: 48976262Sgreen intptr = &options->pubkey_authentication; 49060576Skris goto parse_flag; 49160576Skris 49257429Smarkm case oRSAAuthentication: 49357429Smarkm intptr = &options->rsa_authentication; 49457429Smarkm goto parse_flag; 49557429Smarkm 49657429Smarkm case oRhostsRSAAuthentication: 49757429Smarkm intptr = &options->rhosts_rsa_authentication; 49857429Smarkm goto parse_flag; 49957429Smarkm 50076262Sgreen case oHostbasedAuthentication: 50176262Sgreen intptr = &options->hostbased_authentication; 50257429Smarkm goto parse_flag; 50357429Smarkm 50492559Sdes case oChallengeResponseAuthentication: 50592559Sdes intptr = &options->challenge_response_authentication; 50692559Sdes goto parse_flag; 507124211Sdes 508124211Sdes case oGssAuthentication: 509124211Sdes intptr = &options->gss_authentication; 51057429Smarkm goto parse_flag; 511124211Sdes 512124211Sdes case oGssDelegateCreds: 513124211Sdes intptr = &options->gss_deleg_creds; 51476262Sgreen goto parse_flag; 515124211Sdes 51657429Smarkm case oBatchMode: 51757429Smarkm intptr = &options->batch_mode; 51857429Smarkm goto parse_flag; 51957429Smarkm 52057429Smarkm case oCheckHostIP: 52157429Smarkm intptr = &options->check_host_ip; 52257429Smarkm goto parse_flag; 52357429Smarkm 524124211Sdes case oVerifyHostKeyDNS: 525124211Sdes intptr = &options->verify_host_key_dns; 526126277Sdes goto parse_yesnoask; 527124211Sdes 52857429Smarkm case oStrictHostKeyChecking: 52957429Smarkm intptr = &options->strict_host_key_checking; 530126277Sdesparse_yesnoask: 53165674Skris arg = strdelim(&s); 53265674Skris if (!arg || *arg == '\0') 53376262Sgreen fatal("%.200s line %d: Missing yes/no/ask argument.", 53492559Sdes filename, linenum); 53557429Smarkm value = 0; /* To avoid compiler warning... */ 53665674Skris if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 53757429Smarkm value = 1; 53865674Skris else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 53957429Smarkm value = 0; 54065674Skris else if (strcmp(arg, "ask") == 0) 54157429Smarkm value = 2; 54257429Smarkm else 54357429Smarkm fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum); 54457429Smarkm if (*activep && *intptr == -1) 54557429Smarkm *intptr = value; 54657429Smarkm break; 54757429Smarkm 54857429Smarkm case oCompression: 54957429Smarkm intptr = &options->compression; 55057429Smarkm goto parse_flag; 55157429Smarkm 552126277Sdes case oTCPKeepAlive: 553126277Sdes intptr = &options->tcp_keep_alive; 55457429Smarkm goto parse_flag; 55557429Smarkm 55692559Sdes case oNoHostAuthenticationForLocalhost: 55792559Sdes intptr = &options->no_host_authentication_for_localhost; 55892559Sdes goto parse_flag; 55992559Sdes 56057429Smarkm case oNumberOfPasswordPrompts: 56157429Smarkm intptr = &options->number_of_password_prompts; 56257429Smarkm goto parse_int; 56357429Smarkm 56457429Smarkm case oCompressionLevel: 56557429Smarkm intptr = &options->compression_level; 56657429Smarkm goto parse_int; 56757429Smarkm 568124211Sdes case oRekeyLimit: 569124211Sdes arg = strdelim(&s); 570124211Sdes if (!arg || *arg == '\0') 571124211Sdes fatal("%.200s line %d: Missing argument.", filename, linenum); 572124211Sdes if (arg[0] < '0' || arg[0] > '9') 573124211Sdes fatal("%.200s line %d: Bad number.", filename, linenum); 574162856Sdes orig = val64 = strtoll(arg, &endofnumber, 10); 575124211Sdes if (arg == endofnumber) 576124211Sdes fatal("%.200s line %d: Bad number.", filename, linenum); 577124211Sdes switch (toupper(*endofnumber)) { 578162856Sdes case '\0': 579162856Sdes scale = 1; 580162856Sdes break; 581124211Sdes case 'K': 582162856Sdes scale = 1<<10; 583124211Sdes break; 584124211Sdes case 'M': 585162856Sdes scale = 1<<20; 586124211Sdes break; 587124211Sdes case 'G': 588162856Sdes scale = 1<<30; 589124211Sdes break; 590162856Sdes default: 591162856Sdes fatal("%.200s line %d: Invalid RekeyLimit suffix", 592162856Sdes filename, linenum); 593124211Sdes } 594162856Sdes val64 *= scale; 595162856Sdes /* detect integer wrap and too-large limits */ 596181111Sdes if ((val64 / scale) != orig || val64 > UINT_MAX) 597162856Sdes fatal("%.200s line %d: RekeyLimit too large", 598162856Sdes filename, linenum); 599162856Sdes if (val64 < 16) 600162856Sdes fatal("%.200s line %d: RekeyLimit too small", 601162856Sdes filename, linenum); 602181111Sdes if (*activep && options->rekey_limit == -1) 603181111Sdes options->rekey_limit = (u_int32_t)val64; 604124211Sdes break; 605124211Sdes 60657429Smarkm case oIdentityFile: 60765674Skris arg = strdelim(&s); 60865674Skris if (!arg || *arg == '\0') 60957429Smarkm fatal("%.200s line %d: Missing argument.", filename, linenum); 61057429Smarkm if (*activep) { 61176262Sgreen intptr = &options->num_identity_files; 61260576Skris if (*intptr >= SSH_MAX_IDENTITY_FILES) 61357429Smarkm fatal("%.200s line %d: Too many identity files specified (max %d).", 61492559Sdes filename, linenum, SSH_MAX_IDENTITY_FILES); 615181111Sdes charptr = &options->identity_files[*intptr]; 61665674Skris *charptr = xstrdup(arg); 61760576Skris *intptr = *intptr + 1; 61857429Smarkm } 61957429Smarkm break; 62057429Smarkm 62165674Skris case oXAuthLocation: 62265674Skris charptr=&options->xauth_location; 62365674Skris goto parse_string; 62465674Skris 62557429Smarkm case oUser: 62657429Smarkm charptr = &options->user; 62757429Smarkmparse_string: 62865674Skris arg = strdelim(&s); 62965674Skris if (!arg || *arg == '\0') 63057429Smarkm fatal("%.200s line %d: Missing argument.", filename, linenum); 63157429Smarkm if (*activep && *charptr == NULL) 63265674Skris *charptr = xstrdup(arg); 63357429Smarkm break; 63457429Smarkm 63557429Smarkm case oGlobalKnownHostsFile: 63657429Smarkm charptr = &options->system_hostfile; 63757429Smarkm goto parse_string; 63857429Smarkm 63957429Smarkm case oUserKnownHostsFile: 64057429Smarkm charptr = &options->user_hostfile; 64157429Smarkm goto parse_string; 64257429Smarkm 64360576Skris case oGlobalKnownHostsFile2: 64460576Skris charptr = &options->system_hostfile2; 64560576Skris goto parse_string; 64660576Skris 64760576Skris case oUserKnownHostsFile2: 64860576Skris charptr = &options->user_hostfile2; 64960576Skris goto parse_string; 65060576Skris 65157429Smarkm case oHostName: 65257429Smarkm charptr = &options->hostname; 65357429Smarkm goto parse_string; 65457429Smarkm 65576262Sgreen case oHostKeyAlias: 65676262Sgreen charptr = &options->host_key_alias; 65776262Sgreen goto parse_string; 65876262Sgreen 65976262Sgreen case oPreferredAuthentications: 66076262Sgreen charptr = &options->preferred_authentications; 66176262Sgreen goto parse_string; 66276262Sgreen 66392559Sdes case oBindAddress: 66492559Sdes charptr = &options->bind_address; 66592559Sdes goto parse_string; 66692559Sdes 667204917Sdes case oPKCS11Provider: 668204917Sdes charptr = &options->pkcs11_provider; 66992559Sdes goto parse_string; 67092559Sdes 67157429Smarkm case oProxyCommand: 672157019Sdes charptr = &options->proxy_command; 673157019Sdesparse_command: 674124211Sdes if (s == NULL) 675124211Sdes fatal("%.200s line %d: Missing argument.", filename, linenum); 676113911Sdes len = strspn(s, WHITESPACE "="); 67757429Smarkm if (*activep && *charptr == NULL) 678113911Sdes *charptr = xstrdup(s + len); 67957429Smarkm return 0; 68057429Smarkm 68157429Smarkm case oPort: 68257429Smarkm intptr = &options->port; 68357429Smarkmparse_int: 68465674Skris arg = strdelim(&s); 68565674Skris if (!arg || *arg == '\0') 68657429Smarkm fatal("%.200s line %d: Missing argument.", filename, linenum); 68765674Skris if (arg[0] < '0' || arg[0] > '9') 68857429Smarkm fatal("%.200s line %d: Bad number.", filename, linenum); 68957429Smarkm 69057429Smarkm /* Octal, decimal, or hex format? */ 69165674Skris value = strtol(arg, &endofnumber, 0); 69265674Skris if (arg == endofnumber) 69357429Smarkm fatal("%.200s line %d: Bad number.", filename, linenum); 69457429Smarkm if (*activep && *intptr == -1) 69557429Smarkm *intptr = value; 69657429Smarkm break; 69757429Smarkm 69857429Smarkm case oConnectionAttempts: 69957429Smarkm intptr = &options->connection_attempts; 70057429Smarkm goto parse_int; 70157429Smarkm 70257429Smarkm case oCipher: 70357429Smarkm intptr = &options->cipher; 70465674Skris arg = strdelim(&s); 70565674Skris if (!arg || *arg == '\0') 70661203Skris fatal("%.200s line %d: Missing argument.", filename, linenum); 70765674Skris value = cipher_number(arg); 70857429Smarkm if (value == -1) 70957429Smarkm fatal("%.200s line %d: Bad cipher '%s'.", 71092559Sdes filename, linenum, arg ? arg : "<NONE>"); 71157429Smarkm if (*activep && *intptr == -1) 71257429Smarkm *intptr = value; 71357429Smarkm break; 71457429Smarkm 71560576Skris case oCiphers: 71665674Skris arg = strdelim(&s); 71765674Skris if (!arg || *arg == '\0') 71861203Skris fatal("%.200s line %d: Missing argument.", filename, linenum); 71965674Skris if (!ciphers_valid(arg)) 72060576Skris fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.", 72192559Sdes filename, linenum, arg ? arg : "<NONE>"); 72260576Skris if (*activep && options->ciphers == NULL) 72365674Skris options->ciphers = xstrdup(arg); 72460576Skris break; 72560576Skris 72676262Sgreen case oMacs: 72776262Sgreen arg = strdelim(&s); 72876262Sgreen if (!arg || *arg == '\0') 72976262Sgreen fatal("%.200s line %d: Missing argument.", filename, linenum); 73076262Sgreen if (!mac_valid(arg)) 73176262Sgreen fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.", 73292559Sdes filename, linenum, arg ? arg : "<NONE>"); 73376262Sgreen if (*activep && options->macs == NULL) 73476262Sgreen options->macs = xstrdup(arg); 73576262Sgreen break; 73676262Sgreen 737221420Sdes case oKexAlgorithms: 738221420Sdes arg = strdelim(&s); 739221420Sdes if (!arg || *arg == '\0') 740221420Sdes fatal("%.200s line %d: Missing argument.", 741221420Sdes filename, linenum); 742221420Sdes if (!kex_names_valid(arg)) 743221420Sdes fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.", 744221420Sdes filename, linenum, arg ? arg : "<NONE>"); 745221420Sdes if (*activep && options->kex_algorithms == NULL) 746221420Sdes options->kex_algorithms = xstrdup(arg); 747221420Sdes break; 748221420Sdes 74976262Sgreen case oHostKeyAlgorithms: 75076262Sgreen arg = strdelim(&s); 75176262Sgreen if (!arg || *arg == '\0') 75276262Sgreen fatal("%.200s line %d: Missing argument.", filename, linenum); 75376262Sgreen if (!key_names_valid2(arg)) 75476262Sgreen fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.", 75592559Sdes filename, linenum, arg ? arg : "<NONE>"); 75676262Sgreen if (*activep && options->hostkeyalgorithms == NULL) 75776262Sgreen options->hostkeyalgorithms = xstrdup(arg); 75876262Sgreen break; 75976262Sgreen 76060576Skris case oProtocol: 76160576Skris intptr = &options->protocol; 76265674Skris arg = strdelim(&s); 76365674Skris if (!arg || *arg == '\0') 76461203Skris fatal("%.200s line %d: Missing argument.", filename, linenum); 76565674Skris value = proto_spec(arg); 76660576Skris if (value == SSH_PROTO_UNKNOWN) 76760576Skris fatal("%.200s line %d: Bad protocol spec '%s'.", 76892559Sdes filename, linenum, arg ? arg : "<NONE>"); 76960576Skris if (*activep && *intptr == SSH_PROTO_UNKNOWN) 77060576Skris *intptr = value; 77160576Skris break; 77260576Skris 77357429Smarkm case oLogLevel: 774181111Sdes log_level_ptr = &options->log_level; 77565674Skris arg = strdelim(&s); 77665674Skris value = log_level_number(arg); 77792559Sdes if (value == SYSLOG_LEVEL_NOT_SET) 77876262Sgreen fatal("%.200s line %d: unsupported log level '%s'", 77992559Sdes filename, linenum, arg ? arg : "<NONE>"); 780181111Sdes if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET) 781181111Sdes *log_level_ptr = (LogLevel) value; 78257429Smarkm break; 78357429Smarkm 78492559Sdes case oLocalForward: 78557429Smarkm case oRemoteForward: 786192595Sdes case oDynamicForward: 78765674Skris arg = strdelim(&s); 788147005Sdes if (arg == NULL || *arg == '\0') 78992559Sdes fatal("%.200s line %d: Missing port argument.", 79092559Sdes filename, linenum); 791147005Sdes 792192595Sdes if (opcode == oLocalForward || 793192595Sdes opcode == oRemoteForward) { 794192595Sdes arg2 = strdelim(&s); 795192595Sdes if (arg2 == NULL || *arg2 == '\0') 796192595Sdes fatal("%.200s line %d: Missing target argument.", 797192595Sdes filename, linenum); 798147005Sdes 799192595Sdes /* construct a string for parse_forward */ 800192595Sdes snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2); 801192595Sdes } else if (opcode == oDynamicForward) { 802192595Sdes strlcpy(fwdarg, arg, sizeof(fwdarg)); 803192595Sdes } 804192595Sdes 805192595Sdes if (parse_forward(&fwd, fwdarg, 806192595Sdes opcode == oDynamicForward ? 1 : 0, 807192595Sdes opcode == oRemoteForward ? 1 : 0) == 0) 80892559Sdes fatal("%.200s line %d: Bad forwarding specification.", 80992559Sdes filename, linenum); 810147005Sdes 81192559Sdes if (*activep) { 812192595Sdes if (opcode == oLocalForward || 813192595Sdes opcode == oDynamicForward) 814147005Sdes add_local_forward(options, &fwd); 81592559Sdes else if (opcode == oRemoteForward) 816147005Sdes add_remote_forward(options, &fwd); 81792559Sdes } 81857429Smarkm break; 81957429Smarkm 82092559Sdes case oClearAllForwardings: 82192559Sdes intptr = &options->clear_forwardings; 82292559Sdes goto parse_flag; 82392559Sdes 82457429Smarkm case oHost: 82557429Smarkm *activep = 0; 82665674Skris while ((arg = strdelim(&s)) != NULL && *arg != '\0') 82765674Skris if (match_pattern(host, arg)) { 82865674Skris debug("Applying options for %.100s", arg); 82957429Smarkm *activep = 1; 83057429Smarkm break; 83157429Smarkm } 83265674Skris /* Avoid garbage check below, as strdelim is done. */ 83357429Smarkm return 0; 83457429Smarkm 83557429Smarkm case oEscapeChar: 83657429Smarkm intptr = &options->escape_char; 83765674Skris arg = strdelim(&s); 83865674Skris if (!arg || *arg == '\0') 83957429Smarkm fatal("%.200s line %d: Missing argument.", filename, linenum); 84065674Skris if (arg[0] == '^' && arg[2] == 0 && 84176262Sgreen (u_char) arg[1] >= 64 && (u_char) arg[1] < 128) 84276262Sgreen value = (u_char) arg[1] & 31; 84365674Skris else if (strlen(arg) == 1) 84476262Sgreen value = (u_char) arg[0]; 84565674Skris else if (strcmp(arg, "none") == 0) 84692559Sdes value = SSH_ESCAPECHAR_NONE; 84757429Smarkm else { 84857429Smarkm fatal("%.200s line %d: Bad escape character.", 84992559Sdes filename, linenum); 85057429Smarkm /* NOTREACHED */ 85157429Smarkm value = 0; /* Avoid compiler warning. */ 85257429Smarkm } 85357429Smarkm if (*activep && *intptr == -1) 85457429Smarkm *intptr = value; 85557429Smarkm break; 85657429Smarkm 857124211Sdes case oAddressFamily: 858124211Sdes arg = strdelim(&s); 859149753Sdes if (!arg || *arg == '\0') 860149753Sdes fatal("%s line %d: missing address family.", 861149753Sdes filename, linenum); 862124211Sdes intptr = &options->address_family; 863124211Sdes if (strcasecmp(arg, "inet") == 0) 864124211Sdes value = AF_INET; 865124211Sdes else if (strcasecmp(arg, "inet6") == 0) 866124211Sdes value = AF_INET6; 867124211Sdes else if (strcasecmp(arg, "any") == 0) 868124211Sdes value = AF_UNSPEC; 869124211Sdes else 870124211Sdes fatal("Unsupported AddressFamily \"%s\"", arg); 871124211Sdes if (*activep && *intptr == -1) 872124211Sdes *intptr = value; 873124211Sdes break; 874124211Sdes 875113911Sdes case oEnableSSHKeysign: 876113911Sdes intptr = &options->enable_ssh_keysign; 877113911Sdes goto parse_flag; 878113911Sdes 879128460Sdes case oIdentitiesOnly: 880128460Sdes intptr = &options->identities_only; 881128460Sdes goto parse_flag; 882128460Sdes 883126277Sdes case oServerAliveInterval: 884126277Sdes intptr = &options->server_alive_interval; 885126277Sdes goto parse_time; 886126277Sdes 887126277Sdes case oServerAliveCountMax: 888126277Sdes intptr = &options->server_alive_count_max; 889126277Sdes goto parse_int; 890126277Sdes 891137019Sdes case oSendEnv: 892137019Sdes while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 893137019Sdes if (strchr(arg, '=') != NULL) 894137019Sdes fatal("%s line %d: Invalid environment name.", 895137019Sdes filename, linenum); 896147005Sdes if (!*activep) 897147005Sdes continue; 898137019Sdes if (options->num_send_env >= MAX_SEND_ENV) 899137019Sdes fatal("%s line %d: too many send env.", 900137019Sdes filename, linenum); 901137019Sdes options->send_env[options->num_send_env++] = 902137019Sdes xstrdup(arg); 903137019Sdes } 904137019Sdes break; 905137019Sdes 906137019Sdes case oControlPath: 907137019Sdes charptr = &options->control_path; 908137019Sdes goto parse_string; 909137019Sdes 910137019Sdes case oControlMaster: 911137019Sdes intptr = &options->control_master; 912149753Sdes arg = strdelim(&s); 913149753Sdes if (!arg || *arg == '\0') 914149753Sdes fatal("%.200s line %d: Missing ControlMaster argument.", 915149753Sdes filename, linenum); 916149753Sdes value = 0; /* To avoid compiler warning... */ 917149753Sdes if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 918149753Sdes value = SSHCTL_MASTER_YES; 919149753Sdes else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 920149753Sdes value = SSHCTL_MASTER_NO; 921149753Sdes else if (strcmp(arg, "auto") == 0) 922149753Sdes value = SSHCTL_MASTER_AUTO; 923149753Sdes else if (strcmp(arg, "ask") == 0) 924149753Sdes value = SSHCTL_MASTER_ASK; 925149753Sdes else if (strcmp(arg, "autoask") == 0) 926149753Sdes value = SSHCTL_MASTER_AUTO_ASK; 927149753Sdes else 928149753Sdes fatal("%.200s line %d: Bad ControlMaster argument.", 929149753Sdes filename, linenum); 930149753Sdes if (*activep && *intptr == -1) 931149753Sdes *intptr = value; 932149753Sdes break; 933137019Sdes 934215116Sdes case oControlPersist: 935215116Sdes /* no/false/yes/true, or a time spec */ 936215116Sdes intptr = &options->control_persist; 937215116Sdes arg = strdelim(&s); 938215116Sdes if (!arg || *arg == '\0') 939215116Sdes fatal("%.200s line %d: Missing ControlPersist" 940215116Sdes " argument.", filename, linenum); 941215116Sdes value = 0; 942215116Sdes value2 = 0; /* timeout */ 943215116Sdes if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 944215116Sdes value = 0; 945215116Sdes else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 946215116Sdes value = 1; 947215116Sdes else if ((value2 = convtime(arg)) >= 0) 948215116Sdes value = 1; 949215116Sdes else 950215116Sdes fatal("%.200s line %d: Bad ControlPersist argument.", 951215116Sdes filename, linenum); 952215116Sdes if (*activep && *intptr == -1) { 953215116Sdes *intptr = value; 954215116Sdes options->control_persist_timeout = value2; 955215116Sdes } 956215116Sdes break; 957215116Sdes 958147005Sdes case oHashKnownHosts: 959147005Sdes intptr = &options->hash_known_hosts; 960147005Sdes goto parse_flag; 961147005Sdes 962157019Sdes case oTunnel: 963157019Sdes intptr = &options->tun_open; 964157019Sdes arg = strdelim(&s); 965157019Sdes if (!arg || *arg == '\0') 966157019Sdes fatal("%s line %d: Missing yes/point-to-point/" 967157019Sdes "ethernet/no argument.", filename, linenum); 968157019Sdes value = 0; /* silence compiler */ 969157019Sdes if (strcasecmp(arg, "ethernet") == 0) 970157019Sdes value = SSH_TUNMODE_ETHERNET; 971157019Sdes else if (strcasecmp(arg, "point-to-point") == 0) 972157019Sdes value = SSH_TUNMODE_POINTOPOINT; 973157019Sdes else if (strcasecmp(arg, "yes") == 0) 974157019Sdes value = SSH_TUNMODE_DEFAULT; 975157019Sdes else if (strcasecmp(arg, "no") == 0) 976157019Sdes value = SSH_TUNMODE_NO; 977157019Sdes else 978157019Sdes fatal("%s line %d: Bad yes/point-to-point/ethernet/" 979157019Sdes "no argument: %s", filename, linenum, arg); 980157019Sdes if (*activep) 981157019Sdes *intptr = value; 982157019Sdes break; 983157019Sdes 984157019Sdes case oTunnelDevice: 985157019Sdes arg = strdelim(&s); 986157019Sdes if (!arg || *arg == '\0') 987157019Sdes fatal("%.200s line %d: Missing argument.", filename, linenum); 988157019Sdes value = a2tun(arg, &value2); 989157019Sdes if (value == SSH_TUNID_ERR) 990157019Sdes fatal("%.200s line %d: Bad tun device.", filename, linenum); 991157019Sdes if (*activep) { 992157019Sdes options->tun_local = value; 993157019Sdes options->tun_remote = value2; 994157019Sdes } 995157019Sdes break; 996157019Sdes 997157019Sdes case oLocalCommand: 998157019Sdes charptr = &options->local_command; 999157019Sdes goto parse_command; 1000157019Sdes 1001157019Sdes case oPermitLocalCommand: 1002157019Sdes intptr = &options->permit_local_command; 1003157019Sdes goto parse_flag; 1004157019Sdes 1005181111Sdes case oVisualHostKey: 1006181111Sdes intptr = &options->visual_host_key; 1007181111Sdes goto parse_flag; 1008181111Sdes 1009221420Sdes case oIPQoS: 1010221420Sdes arg = strdelim(&s); 1011221420Sdes if ((value = parse_ipqos(arg)) == -1) 1012221420Sdes fatal("%s line %d: Bad IPQoS value: %s", 1013221420Sdes filename, linenum, arg); 1014221420Sdes arg = strdelim(&s); 1015221420Sdes if (arg == NULL) 1016221420Sdes value2 = value; 1017221420Sdes else if ((value2 = parse_ipqos(arg)) == -1) 1018221420Sdes fatal("%s line %d: Bad IPQoS value: %s", 1019221420Sdes filename, linenum, arg); 1020221420Sdes if (*activep) { 1021221420Sdes options->ip_qos_interactive = value; 1022221420Sdes options->ip_qos_bulk = value2; 1023221420Sdes } 1024221420Sdes break; 1025221420Sdes 1026197679Sdes case oUseRoaming: 1027197679Sdes intptr = &options->use_roaming; 1028197679Sdes goto parse_flag; 1029197679Sdes 103099048Sdes case oVersionAddendum: 103199048Sdes ssh_version_set_addendum(strtok(s, "\n")); 103299048Sdes do { 103399048Sdes arg = strdelim(&s); 103499048Sdes } while (arg != NULL && *arg != '\0'); 103599048Sdes break; 103699048Sdes 1037224638Sbrooks case oHPNDisabled: 1038224638Sbrooks intptr = &options->hpn_disabled; 1039224638Sbrooks goto parse_flag; 1040224638Sbrooks 1041224638Sbrooks case oHPNBufferSize: 1042224638Sbrooks intptr = &options->hpn_buffer_size; 1043224638Sbrooks goto parse_int; 1044224638Sbrooks 1045224638Sbrooks case oTcpRcvBufPoll: 1046224638Sbrooks intptr = &options->tcp_rcv_buf_poll; 1047224638Sbrooks goto parse_flag; 1048224638Sbrooks 1049224638Sbrooks case oTcpRcvBuf: 1050224638Sbrooks intptr = &options->tcp_rcv_buf; 1051224638Sbrooks goto parse_int; 1052224638Sbrooks 1053224638Sbrooks#ifdef NONE_CIPHER_ENABLED 1054224638Sbrooks case oNoneEnabled: 1055224638Sbrooks intptr = &options->none_enabled; 1056224638Sbrooks goto parse_flag; 1057224638Sbrooks 1058224638Sbrooks /* 1059224638Sbrooks * We check to see if the command comes from the command line or not. 1060224638Sbrooks * If it does then enable it otherwise fail. NONE must never be a 1061224638Sbrooks * default configuration. 1062224638Sbrooks */ 1063224638Sbrooks case oNoneSwitch: 1064224638Sbrooks if (strcmp(filename,"command-line") == 0) { 1065224638Sbrooks intptr = &options->none_switch; 1066224638Sbrooks goto parse_flag; 1067224638Sbrooks } else { 1068224638Sbrooks debug("NoneSwitch directive found in %.200s.", 1069224638Sbrooks filename); 1070224638Sbrooks error("NoneSwitch is found in %.200s.\n" 1071224638Sbrooks "You may only use this configuration option " 1072224638Sbrooks "from the command line", filename); 1073224638Sbrooks error("Continuing..."); 1074224638Sbrooks return 0; 1075224638Sbrooks } 1076224638Sbrooks#endif 1077224638Sbrooks 107898684Sdes case oDeprecated: 107998684Sdes debug("%s line %d: Deprecated option \"%s\"", 108098684Sdes filename, linenum, keyword); 108198684Sdes return 0; 108298684Sdes 1083124211Sdes case oUnsupported: 1084124211Sdes error("%s line %d: Unsupported option \"%s\"", 1085124211Sdes filename, linenum, keyword); 1086124211Sdes return 0; 1087124211Sdes 108857429Smarkm default: 108957429Smarkm fatal("process_config_line: Unimplemented opcode %d", opcode); 109057429Smarkm } 109157429Smarkm 109257429Smarkm /* Check that there is no garbage at end of line. */ 109376262Sgreen if ((arg = strdelim(&s)) != NULL && *arg != '\0') { 109465674Skris fatal("%.200s line %d: garbage at end of line; \"%.200s\".", 1095149753Sdes filename, linenum, arg); 109665674Skris } 109757429Smarkm return 0; 109857429Smarkm} 109957429Smarkm 110057429Smarkm 110157429Smarkm/* 110257429Smarkm * Reads the config file and modifies the options accordingly. Options 110357429Smarkm * should already be initialized before this call. This never returns if 110492559Sdes * there is an error. If the file does not exist, this returns 0. 110557429Smarkm */ 110657429Smarkm 110792559Sdesint 1108137019Sdesread_config_file(const char *filename, const char *host, Options *options, 1109137019Sdes int checkperm) 111057429Smarkm{ 111157429Smarkm FILE *f; 111257429Smarkm char line[1024]; 111357429Smarkm int active, linenum; 111457429Smarkm int bad_options = 0; 111557429Smarkm 1116137019Sdes if ((f = fopen(filename, "r")) == NULL) 111792559Sdes return 0; 111857429Smarkm 1119137019Sdes if (checkperm) { 1120137019Sdes struct stat sb; 1121137019Sdes 1122137019Sdes if (fstat(fileno(f), &sb) == -1) 1123137019Sdes fatal("fstat %s: %s", filename, strerror(errno)); 1124137019Sdes if (((sb.st_uid != 0 && sb.st_uid != getuid()) || 1125137019Sdes (sb.st_mode & 022) != 0)) 1126137019Sdes fatal("Bad owner or permissions on %s", filename); 1127137019Sdes } 1128137019Sdes 112957429Smarkm debug("Reading configuration data %.200s", filename); 113057429Smarkm 113157429Smarkm /* 113257429Smarkm * Mark that we are now processing the options. This flag is turned 113357429Smarkm * on/off by Host specifications. 113457429Smarkm */ 113557429Smarkm active = 1; 113657429Smarkm linenum = 0; 113757429Smarkm while (fgets(line, sizeof(line), f)) { 113857429Smarkm /* Update line number counter. */ 113957429Smarkm linenum++; 114057429Smarkm if (process_config_line(options, host, line, filename, linenum, &active) != 0) 114157429Smarkm bad_options++; 114257429Smarkm } 114357429Smarkm fclose(f); 114457429Smarkm if (bad_options > 0) 114576262Sgreen fatal("%s: terminating, %d bad configuration options", 114692559Sdes filename, bad_options); 114792559Sdes return 1; 114857429Smarkm} 114957429Smarkm 115057429Smarkm/* 115157429Smarkm * Initializes options to special values that indicate that they have not yet 115257429Smarkm * been set. Read_config_file will only set options with this value. Options 115357429Smarkm * are processed in the following order: command line, user config file, 115457429Smarkm * system config file. Last, fill_default_options is called. 115557429Smarkm */ 115657429Smarkm 115760576Skrisvoid 115857429Smarkminitialize_options(Options * options) 115957429Smarkm{ 116057429Smarkm memset(options, 'X', sizeof(*options)); 116157429Smarkm options->forward_agent = -1; 116257429Smarkm options->forward_x11 = -1; 1163126277Sdes options->forward_x11_trusted = -1; 1164215116Sdes options->forward_x11_timeout = -1; 1165162856Sdes options->exit_on_forward_failure = -1; 116665674Skris options->xauth_location = NULL; 116757429Smarkm options->gateway_ports = -1; 116857429Smarkm options->use_privileged_port = -1; 116957429Smarkm options->rsa_authentication = -1; 117076262Sgreen options->pubkey_authentication = -1; 117192559Sdes options->challenge_response_authentication = -1; 1172124211Sdes options->gss_authentication = -1; 1173124211Sdes options->gss_deleg_creds = -1; 117457429Smarkm options->password_authentication = -1; 117569591Sgreen options->kbd_interactive_authentication = -1; 117669591Sgreen options->kbd_interactive_devices = NULL; 117757429Smarkm options->rhosts_rsa_authentication = -1; 117876262Sgreen options->hostbased_authentication = -1; 117957429Smarkm options->batch_mode = -1; 118057429Smarkm options->check_host_ip = -1; 118157429Smarkm options->strict_host_key_checking = -1; 118257429Smarkm options->compression = -1; 1183126277Sdes options->tcp_keep_alive = -1; 118457429Smarkm options->compression_level = -1; 118557429Smarkm options->port = -1; 1186124211Sdes options->address_family = -1; 118757429Smarkm options->connection_attempts = -1; 1188124211Sdes options->connection_timeout = -1; 118957429Smarkm options->number_of_password_prompts = -1; 119057429Smarkm options->cipher = -1; 119160576Skris options->ciphers = NULL; 119276262Sgreen options->macs = NULL; 1193221420Sdes options->kex_algorithms = NULL; 119476262Sgreen options->hostkeyalgorithms = NULL; 119560576Skris options->protocol = SSH_PROTO_UNKNOWN; 119657429Smarkm options->num_identity_files = 0; 119757429Smarkm options->hostname = NULL; 119876262Sgreen options->host_key_alias = NULL; 119957429Smarkm options->proxy_command = NULL; 120057429Smarkm options->user = NULL; 120157429Smarkm options->escape_char = -1; 120257429Smarkm options->system_hostfile = NULL; 120357429Smarkm options->user_hostfile = NULL; 120460576Skris options->system_hostfile2 = NULL; 120560576Skris options->user_hostfile2 = NULL; 1206215116Sdes options->local_forwards = NULL; 120757429Smarkm options->num_local_forwards = 0; 1208215116Sdes options->remote_forwards = NULL; 120957429Smarkm options->num_remote_forwards = 0; 121092559Sdes options->clear_forwardings = -1; 121192559Sdes options->log_level = SYSLOG_LEVEL_NOT_SET; 121276262Sgreen options->preferred_authentications = NULL; 121392559Sdes options->bind_address = NULL; 1214204917Sdes options->pkcs11_provider = NULL; 1215113911Sdes options->enable_ssh_keysign = - 1; 121692559Sdes options->no_host_authentication_for_localhost = - 1; 1217128460Sdes options->identities_only = - 1; 1218124211Sdes options->rekey_limit = - 1; 1219124211Sdes options->verify_host_key_dns = -1; 1220126277Sdes options->server_alive_interval = -1; 1221126277Sdes options->server_alive_count_max = -1; 1222137019Sdes options->num_send_env = 0; 1223137019Sdes options->control_path = NULL; 1224137019Sdes options->control_master = -1; 1225215116Sdes options->control_persist = -1; 1226215116Sdes options->control_persist_timeout = 0; 1227147005Sdes options->hash_known_hosts = -1; 1228157019Sdes options->tun_open = -1; 1229157019Sdes options->tun_local = -1; 1230157019Sdes options->tun_remote = -1; 1231157019Sdes options->local_command = NULL; 1232157019Sdes options->permit_local_command = -1; 1233197679Sdes options->use_roaming = -1; 1234181111Sdes options->visual_host_key = -1; 1235192595Sdes options->zero_knowledge_password_authentication = -1; 1236221420Sdes options->ip_qos_interactive = -1; 1237221420Sdes options->ip_qos_bulk = -1; 1238224638Sbrooks options->hpn_disabled = -1; 1239224638Sbrooks options->hpn_buffer_size = -1; 1240224638Sbrooks options->tcp_rcv_buf_poll = -1; 1241224638Sbrooks options->tcp_rcv_buf = -1; 1242224638Sbrooks#ifdef NONE_CIPHER_ENABLED 1243224638Sbrooks options->none_enabled = -1; 1244224638Sbrooks options->none_switch = -1; 1245224638Sbrooks#endif 124657429Smarkm} 124757429Smarkm 124857429Smarkm/* 124957429Smarkm * Called after processing other sources of option data, this fills those 125057429Smarkm * options for which no value has been specified with their default values. 125157429Smarkm */ 125257429Smarkm 125360576Skrisvoid 125457429Smarkmfill_default_options(Options * options) 125557429Smarkm{ 125676262Sgreen int len; 125776262Sgreen 125857429Smarkm if (options->forward_agent == -1) 125961203Skris options->forward_agent = 0; 126057429Smarkm if (options->forward_x11 == -1) 126157708Sgreen options->forward_x11 = 0; 1262126277Sdes if (options->forward_x11_trusted == -1) 1263126277Sdes options->forward_x11_trusted = 0; 1264215116Sdes if (options->forward_x11_timeout == -1) 1265215116Sdes options->forward_x11_timeout = 1200; 1266162856Sdes if (options->exit_on_forward_failure == -1) 1267162856Sdes options->exit_on_forward_failure = 0; 126865674Skris if (options->xauth_location == NULL) 126992559Sdes options->xauth_location = _PATH_XAUTH; 127057429Smarkm if (options->gateway_ports == -1) 127157429Smarkm options->gateway_ports = 0; 127257429Smarkm if (options->use_privileged_port == -1) 127376262Sgreen options->use_privileged_port = 0; 127457429Smarkm if (options->rsa_authentication == -1) 127557429Smarkm options->rsa_authentication = 1; 127676262Sgreen if (options->pubkey_authentication == -1) 127776262Sgreen options->pubkey_authentication = 1; 127892559Sdes if (options->challenge_response_authentication == -1) 127992559Sdes options->challenge_response_authentication = 1; 1280124211Sdes if (options->gss_authentication == -1) 1281126277Sdes options->gss_authentication = 0; 1282124211Sdes if (options->gss_deleg_creds == -1) 1283124211Sdes options->gss_deleg_creds = 0; 128457429Smarkm if (options->password_authentication == -1) 128557429Smarkm options->password_authentication = 1; 128669591Sgreen if (options->kbd_interactive_authentication == -1) 128776262Sgreen options->kbd_interactive_authentication = 1; 128857429Smarkm if (options->rhosts_rsa_authentication == -1) 128998684Sdes options->rhosts_rsa_authentication = 0; 129076262Sgreen if (options->hostbased_authentication == -1) 129176262Sgreen options->hostbased_authentication = 0; 129257429Smarkm if (options->batch_mode == -1) 129357429Smarkm options->batch_mode = 0; 129457429Smarkm if (options->check_host_ip == -1) 129599048Sdes options->check_host_ip = 0; 129657429Smarkm if (options->strict_host_key_checking == -1) 129757429Smarkm options->strict_host_key_checking = 2; /* 2 is default */ 129857429Smarkm if (options->compression == -1) 129957429Smarkm options->compression = 0; 1300126277Sdes if (options->tcp_keep_alive == -1) 1301126277Sdes options->tcp_keep_alive = 1; 130257429Smarkm if (options->compression_level == -1) 130357429Smarkm options->compression_level = 6; 130457429Smarkm if (options->port == -1) 130557429Smarkm options->port = 0; /* Filled in ssh_connect. */ 1306124211Sdes if (options->address_family == -1) 1307124211Sdes options->address_family = AF_UNSPEC; 130857429Smarkm if (options->connection_attempts == -1) 130992559Sdes options->connection_attempts = 1; 131057429Smarkm if (options->number_of_password_prompts == -1) 131157429Smarkm options->number_of_password_prompts = 3; 131257429Smarkm /* Selected in ssh_login(). */ 131357429Smarkm if (options->cipher == -1) 131457429Smarkm options->cipher = SSH_CIPHER_NOT_SET; 131560576Skris /* options->ciphers, default set in myproposals.h */ 131676262Sgreen /* options->macs, default set in myproposals.h */ 1317221420Sdes /* options->kex_algorithms, default set in myproposals.h */ 131876262Sgreen /* options->hostkeyalgorithms, default set in myproposals.h */ 131960576Skris if (options->protocol == SSH_PROTO_UNKNOWN) 1320204917Sdes options->protocol = SSH_PROTO_2; 132157429Smarkm if (options->num_identity_files == 0) { 132276262Sgreen if (options->protocol & SSH_PROTO_1) { 132376262Sgreen len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1; 132476262Sgreen options->identity_files[options->num_identity_files] = 132576262Sgreen xmalloc(len); 132676262Sgreen snprintf(options->identity_files[options->num_identity_files++], 132776262Sgreen len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY); 132876262Sgreen } 132976262Sgreen if (options->protocol & SSH_PROTO_2) { 133076262Sgreen len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1; 133176262Sgreen options->identity_files[options->num_identity_files] = 133276262Sgreen xmalloc(len); 133376262Sgreen snprintf(options->identity_files[options->num_identity_files++], 133476262Sgreen len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA); 133576262Sgreen 133676262Sgreen len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1; 133776262Sgreen options->identity_files[options->num_identity_files] = 133876262Sgreen xmalloc(len); 133976262Sgreen snprintf(options->identity_files[options->num_identity_files++], 134076262Sgreen len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA); 1341221420Sdes#ifdef OPENSSL_HAS_ECC 1342221420Sdes len = 2 + strlen(_PATH_SSH_CLIENT_ID_ECDSA) + 1; 1343221420Sdes options->identity_files[options->num_identity_files] = 1344221420Sdes xmalloc(len); 1345221420Sdes snprintf(options->identity_files[options->num_identity_files++], 1346221420Sdes len, "~/%.100s", _PATH_SSH_CLIENT_ID_ECDSA); 1347221420Sdes#endif 134876262Sgreen } 134957429Smarkm } 135057429Smarkm if (options->escape_char == -1) 135157429Smarkm options->escape_char = '~'; 135257429Smarkm if (options->system_hostfile == NULL) 135376262Sgreen options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE; 135457429Smarkm if (options->user_hostfile == NULL) 135576262Sgreen options->user_hostfile = _PATH_SSH_USER_HOSTFILE; 135660576Skris if (options->system_hostfile2 == NULL) 135776262Sgreen options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2; 135860576Skris if (options->user_hostfile2 == NULL) 135976262Sgreen options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2; 136092559Sdes if (options->log_level == SYSLOG_LEVEL_NOT_SET) 136157429Smarkm options->log_level = SYSLOG_LEVEL_INFO; 136292559Sdes if (options->clear_forwardings == 1) 136392559Sdes clear_forwardings(options); 136492559Sdes if (options->no_host_authentication_for_localhost == - 1) 136592559Sdes options->no_host_authentication_for_localhost = 0; 1366128460Sdes if (options->identities_only == -1) 1367128460Sdes options->identities_only = 0; 1368113911Sdes if (options->enable_ssh_keysign == -1) 1369113911Sdes options->enable_ssh_keysign = 0; 1370124211Sdes if (options->rekey_limit == -1) 1371124211Sdes options->rekey_limit = 0; 1372124211Sdes if (options->verify_host_key_dns == -1) 1373124211Sdes options->verify_host_key_dns = 0; 1374126277Sdes if (options->server_alive_interval == -1) 1375126277Sdes options->server_alive_interval = 0; 1376126277Sdes if (options->server_alive_count_max == -1) 1377126277Sdes options->server_alive_count_max = 3; 1378137019Sdes if (options->control_master == -1) 1379137019Sdes options->control_master = 0; 1380215116Sdes if (options->control_persist == -1) { 1381215116Sdes options->control_persist = 0; 1382215116Sdes options->control_persist_timeout = 0; 1383215116Sdes } 1384147005Sdes if (options->hash_known_hosts == -1) 1385147005Sdes options->hash_known_hosts = 0; 1386157019Sdes if (options->tun_open == -1) 1387157019Sdes options->tun_open = SSH_TUNMODE_NO; 1388157019Sdes if (options->tun_local == -1) 1389157019Sdes options->tun_local = SSH_TUNID_ANY; 1390157019Sdes if (options->tun_remote == -1) 1391157019Sdes options->tun_remote = SSH_TUNID_ANY; 1392157019Sdes if (options->permit_local_command == -1) 1393157019Sdes options->permit_local_command = 0; 1394197679Sdes if (options->use_roaming == -1) 1395197679Sdes options->use_roaming = 1; 1396181111Sdes if (options->visual_host_key == -1) 1397181111Sdes options->visual_host_key = 0; 1398192595Sdes if (options->zero_knowledge_password_authentication == -1) 1399192595Sdes options->zero_knowledge_password_authentication = 0; 1400221420Sdes if (options->ip_qos_interactive == -1) 1401221420Sdes options->ip_qos_interactive = IPTOS_LOWDELAY; 1402221420Sdes if (options->ip_qos_bulk == -1) 1403221420Sdes options->ip_qos_bulk = IPTOS_THROUGHPUT; 1404157019Sdes /* options->local_command should not be set by default */ 140557429Smarkm /* options->proxy_command should not be set by default */ 140657429Smarkm /* options->user will be set in the main program if appropriate */ 140757429Smarkm /* options->hostname will be set in the main program if appropriate */ 140876262Sgreen /* options->host_key_alias should not be set by default */ 140976262Sgreen /* options->preferred_authentications will be set in ssh */ 1410224638Sbrooks if (options->hpn_disabled == -1) 1411224638Sbrooks options->hpn_disabled = 0; 1412224638Sbrooks if (options->hpn_buffer_size > -1) 1413224638Sbrooks { 1414224638Sbrooks u_int maxlen; 1415224638Sbrooks 1416224638Sbrooks /* If a user tries to set the size to 0 set it to 1KB. */ 1417224638Sbrooks if (options->hpn_buffer_size == 0) 1418224638Sbrooks options->hpn_buffer_size = 1024; 1419224638Sbrooks /* Limit the buffer to BUFFER_MAX_LEN. */ 1420224638Sbrooks maxlen = buffer_get_max_len(); 1421224638Sbrooks if (options->hpn_buffer_size > (maxlen / 1024)) { 1422224638Sbrooks debug("User requested buffer larger than %ub: %ub. " 1423224638Sbrooks "Request reverted to %ub", maxlen, 1424224638Sbrooks options->hpn_buffer_size * 1024, maxlen); 1425224638Sbrooks options->hpn_buffer_size = maxlen; 1426224638Sbrooks } 1427224638Sbrooks debug("hpn_buffer_size set to %d", options->hpn_buffer_size); 1428224638Sbrooks } 1429224638Sbrooks if (options->tcp_rcv_buf == 0) 1430224638Sbrooks options->tcp_rcv_buf = 1; 1431224638Sbrooks if (options->tcp_rcv_buf > -1) 1432224638Sbrooks options->tcp_rcv_buf *= 1024; 1433224638Sbrooks if (options->tcp_rcv_buf_poll == -1) 1434224638Sbrooks options->tcp_rcv_buf_poll = 1; 1435224638Sbrooks#ifdef NONE_CIPHER_ENABLED 1436224638Sbrooks /* options->none_enabled must not be set by default */ 1437224638Sbrooks if (options->none_switch == -1) 1438224638Sbrooks options->none_switch = 0; 1439224638Sbrooks#endif 144057429Smarkm} 1441147005Sdes 1442147005Sdes/* 1443147005Sdes * parse_forward 1444147005Sdes * parses a string containing a port forwarding specification of the form: 1445192595Sdes * dynamicfwd == 0 1446147005Sdes * [listenhost:]listenport:connecthost:connectport 1447192595Sdes * dynamicfwd == 1 1448192595Sdes * [listenhost:]listenport 1449147005Sdes * returns number of arguments parsed or zero on error 1450147005Sdes */ 1451147005Sdesint 1452192595Sdesparse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd) 1453147005Sdes{ 1454147005Sdes int i; 1455147005Sdes char *p, *cp, *fwdarg[4]; 1456147005Sdes 1457147005Sdes memset(fwd, '\0', sizeof(*fwd)); 1458147005Sdes 1459147005Sdes cp = p = xstrdup(fwdspec); 1460147005Sdes 1461147005Sdes /* skip leading spaces */ 1462181111Sdes while (isspace(*cp)) 1463147005Sdes cp++; 1464147005Sdes 1465147005Sdes for (i = 0; i < 4; ++i) 1466147005Sdes if ((fwdarg[i] = hpdelim(&cp)) == NULL) 1467147005Sdes break; 1468147005Sdes 1469192595Sdes /* Check for trailing garbage */ 1470147005Sdes if (cp != NULL) 1471147005Sdes i = 0; /* failure */ 1472147005Sdes 1473147005Sdes switch (i) { 1474192595Sdes case 1: 1475192595Sdes fwd->listen_host = NULL; 1476192595Sdes fwd->listen_port = a2port(fwdarg[0]); 1477192595Sdes fwd->connect_host = xstrdup("socks"); 1478192595Sdes break; 1479192595Sdes 1480192595Sdes case 2: 1481192595Sdes fwd->listen_host = xstrdup(cleanhostname(fwdarg[0])); 1482192595Sdes fwd->listen_port = a2port(fwdarg[1]); 1483192595Sdes fwd->connect_host = xstrdup("socks"); 1484192595Sdes break; 1485192595Sdes 1486147005Sdes case 3: 1487147005Sdes fwd->listen_host = NULL; 1488147005Sdes fwd->listen_port = a2port(fwdarg[0]); 1489147005Sdes fwd->connect_host = xstrdup(cleanhostname(fwdarg[1])); 1490147005Sdes fwd->connect_port = a2port(fwdarg[2]); 1491147005Sdes break; 1492147005Sdes 1493147005Sdes case 4: 1494147005Sdes fwd->listen_host = xstrdup(cleanhostname(fwdarg[0])); 1495147005Sdes fwd->listen_port = a2port(fwdarg[1]); 1496147005Sdes fwd->connect_host = xstrdup(cleanhostname(fwdarg[2])); 1497147005Sdes fwd->connect_port = a2port(fwdarg[3]); 1498147005Sdes break; 1499147005Sdes default: 1500147005Sdes i = 0; /* failure */ 1501147005Sdes } 1502147005Sdes 1503147005Sdes xfree(p); 1504147005Sdes 1505192595Sdes if (dynamicfwd) { 1506192595Sdes if (!(i == 1 || i == 2)) 1507192595Sdes goto fail_free; 1508192595Sdes } else { 1509192595Sdes if (!(i == 3 || i == 4)) 1510192595Sdes goto fail_free; 1511192595Sdes if (fwd->connect_port <= 0) 1512192595Sdes goto fail_free; 1513192595Sdes } 1514192595Sdes 1515192595Sdes if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0)) 1516147005Sdes goto fail_free; 1517147005Sdes 1518147005Sdes if (fwd->connect_host != NULL && 1519147005Sdes strlen(fwd->connect_host) >= NI_MAXHOST) 1520147005Sdes goto fail_free; 1521192595Sdes if (fwd->listen_host != NULL && 1522192595Sdes strlen(fwd->listen_host) >= NI_MAXHOST) 1523192595Sdes goto fail_free; 1524147005Sdes 1525192595Sdes 1526147005Sdes return (i); 1527147005Sdes 1528147005Sdes fail_free: 1529192595Sdes if (fwd->connect_host != NULL) { 1530147005Sdes xfree(fwd->connect_host); 1531192595Sdes fwd->connect_host = NULL; 1532192595Sdes } 1533192595Sdes if (fwd->listen_host != NULL) { 1534147005Sdes xfree(fwd->listen_host); 1535192595Sdes fwd->listen_host = NULL; 1536192595Sdes } 1537147005Sdes return (0); 1538147005Sdes} 1539