1511b41d2SMark Murray /* 2511b41d2SMark Murray * 3511b41d2SMark Murray * readconf.c 4511b41d2SMark Murray * 5511b41d2SMark Murray * Author: Tatu Ylonen <ylo@cs.hut.fi> 6511b41d2SMark Murray * 7511b41d2SMark Murray * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 8511b41d2SMark Murray * All rights reserved 9511b41d2SMark Murray * 10511b41d2SMark Murray * Created: Sat Apr 22 00:03:10 1995 ylo 11511b41d2SMark Murray * 12511b41d2SMark Murray * Functions for reading the configuration files. 13511b41d2SMark Murray * 14a95c1225SBrian Feldman * $FreeBSD$ 15511b41d2SMark Murray */ 16511b41d2SMark Murray 17511b41d2SMark Murray #include "includes.h" 185dc73ebeSBrian Feldman RCSID("$Id: readconf.c,v 1.23 2000/02/28 19:51:58 markus Exp $"); 19511b41d2SMark Murray 20511b41d2SMark Murray #include "ssh.h" 21511b41d2SMark Murray #include "cipher.h" 22511b41d2SMark Murray #include "readconf.h" 23511b41d2SMark Murray #include "xmalloc.h" 24511b41d2SMark Murray 25511b41d2SMark Murray /* Format of the configuration file: 26511b41d2SMark Murray 27511b41d2SMark Murray # Configuration data is parsed as follows: 28511b41d2SMark Murray # 1. command line options 29511b41d2SMark Murray # 2. user-specific file 30511b41d2SMark Murray # 3. system-wide file 31511b41d2SMark Murray # Any configuration value is only changed the first time it is set. 32511b41d2SMark Murray # Thus, host-specific definitions should be at the beginning of the 33511b41d2SMark Murray # configuration file, and defaults at the end. 34511b41d2SMark Murray 35511b41d2SMark Murray # Host-specific declarations. These may override anything above. A single 36511b41d2SMark Murray # host may match multiple declarations; these are processed in the order 37511b41d2SMark Murray # that they are given in. 38511b41d2SMark Murray 39511b41d2SMark Murray Host *.ngs.fi ngs.fi 40511b41d2SMark Murray FallBackToRsh no 41511b41d2SMark Murray 42511b41d2SMark Murray Host fake.com 43511b41d2SMark Murray HostName another.host.name.real.org 44511b41d2SMark Murray User blaah 45511b41d2SMark Murray Port 34289 46511b41d2SMark Murray ForwardX11 no 47511b41d2SMark Murray ForwardAgent no 48511b41d2SMark Murray 49511b41d2SMark Murray Host books.com 50511b41d2SMark Murray RemoteForward 9999 shadows.cs.hut.fi:9999 51511b41d2SMark Murray Cipher 3des 52511b41d2SMark Murray 53511b41d2SMark Murray Host fascist.blob.com 54511b41d2SMark Murray Port 23123 55511b41d2SMark Murray User tylonen 56511b41d2SMark Murray RhostsAuthentication no 57511b41d2SMark Murray PasswordAuthentication no 58511b41d2SMark Murray 59511b41d2SMark Murray Host puukko.hut.fi 60511b41d2SMark Murray User t35124p 61511b41d2SMark Murray ProxyCommand ssh-proxy %h %p 62511b41d2SMark Murray 63511b41d2SMark Murray Host *.fr 64511b41d2SMark Murray UseRsh yes 65511b41d2SMark Murray 66511b41d2SMark Murray Host *.su 67511b41d2SMark Murray Cipher none 68511b41d2SMark Murray PasswordAuthentication no 69511b41d2SMark Murray 70511b41d2SMark Murray # Defaults for various options 71511b41d2SMark Murray Host * 72511b41d2SMark Murray ForwardAgent no 73511b41d2SMark Murray ForwardX11 yes 74511b41d2SMark Murray RhostsAuthentication yes 75511b41d2SMark Murray PasswordAuthentication yes 76511b41d2SMark Murray RSAAuthentication yes 77511b41d2SMark Murray RhostsRSAAuthentication yes 78511b41d2SMark Murray FallBackToRsh no 79511b41d2SMark Murray UseRsh no 80511b41d2SMark Murray StrictHostKeyChecking yes 81511b41d2SMark Murray KeepAlives no 82511b41d2SMark Murray IdentityFile ~/.ssh/identity 83511b41d2SMark Murray Port 22 84511b41d2SMark Murray EscapeChar ~ 85511b41d2SMark Murray 86511b41d2SMark Murray */ 87511b41d2SMark Murray 88511b41d2SMark Murray /* Keyword tokens. */ 89511b41d2SMark Murray 90511b41d2SMark Murray typedef enum { 91511b41d2SMark Murray oBadOption, 92511b41d2SMark Murray oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication, 93511b41d2SMark Murray oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh, 94511b41d2SMark Murray oSkeyAuthentication, 95511b41d2SMark Murray #ifdef KRB4 96fe5fd017SMark Murray oKrb4Authentication, 97511b41d2SMark Murray #endif /* KRB4 */ 98fe5fd017SMark Murray #ifdef KRB5 99fe5fd017SMark Murray oKrb5Authentication, oKrb5TgtPassing, 100fe5fd017SMark Murray #endif /* KRB5 */ 101511b41d2SMark Murray #ifdef AFS 102fe5fd017SMark Murray oKrb4TgtPassing, oAFSTokenPassing, 103511b41d2SMark Murray #endif 104511b41d2SMark Murray oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, 105511b41d2SMark Murray oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, 106511b41d2SMark Murray oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, 107511b41d2SMark Murray oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, 108511b41d2SMark Murray oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication, 109511b41d2SMark Murray oUsePrivilegedPort, oLogLevel 110511b41d2SMark Murray } OpCodes; 111511b41d2SMark Murray 112511b41d2SMark Murray /* Textual representations of the tokens. */ 113511b41d2SMark Murray 114511b41d2SMark Murray static struct { 115511b41d2SMark Murray const char *name; 116511b41d2SMark Murray OpCodes opcode; 117511b41d2SMark Murray } keywords[] = { 118511b41d2SMark Murray { "forwardagent", oForwardAgent }, 119511b41d2SMark Murray { "forwardx11", oForwardX11 }, 120511b41d2SMark Murray { "gatewayports", oGatewayPorts }, 121511b41d2SMark Murray { "useprivilegedport", oUsePrivilegedPort }, 122511b41d2SMark Murray { "rhostsauthentication", oRhostsAuthentication }, 123511b41d2SMark Murray { "passwordauthentication", oPasswordAuthentication }, 124511b41d2SMark Murray { "rsaauthentication", oRSAAuthentication }, 125511b41d2SMark Murray { "skeyauthentication", oSkeyAuthentication }, 126511b41d2SMark Murray #ifdef KRB4 127fe5fd017SMark Murray { "kerberos4authentication", oKrb4Authentication }, 128511b41d2SMark Murray #endif /* KRB4 */ 129fe5fd017SMark Murray #ifdef KRB5 130fe5fd017SMark Murray { "kerberos5authentication", oKrb5Authentication }, 131fe5fd017SMark Murray { "kerberos5tgtpassing", oKrb5TgtPassing }, 132fe5fd017SMark Murray #endif /* KRB5 */ 133511b41d2SMark Murray #ifdef AFS 134fe5fd017SMark Murray { "kerberos4tgtpassing", oKrb4TgtPassing }, 135511b41d2SMark Murray { "afstokenpassing", oAFSTokenPassing }, 136511b41d2SMark Murray #endif 137511b41d2SMark Murray { "fallbacktorsh", oFallBackToRsh }, 138511b41d2SMark Murray { "usersh", oUseRsh }, 139511b41d2SMark Murray { "identityfile", oIdentityFile }, 140511b41d2SMark Murray { "hostname", oHostName }, 141511b41d2SMark Murray { "proxycommand", oProxyCommand }, 142511b41d2SMark Murray { "port", oPort }, 143511b41d2SMark Murray { "cipher", oCipher }, 144511b41d2SMark Murray { "remoteforward", oRemoteForward }, 145511b41d2SMark Murray { "localforward", oLocalForward }, 146511b41d2SMark Murray { "user", oUser }, 147511b41d2SMark Murray { "host", oHost }, 148511b41d2SMark Murray { "escapechar", oEscapeChar }, 149511b41d2SMark Murray { "rhostsrsaauthentication", oRhostsRSAAuthentication }, 150511b41d2SMark Murray { "globalknownhostsfile", oGlobalKnownHostsFile }, 151511b41d2SMark Murray { "userknownhostsfile", oUserKnownHostsFile }, 152511b41d2SMark Murray { "connectionattempts", oConnectionAttempts }, 153511b41d2SMark Murray { "batchmode", oBatchMode }, 154511b41d2SMark Murray { "checkhostip", oCheckHostIP }, 155511b41d2SMark Murray { "stricthostkeychecking", oStrictHostKeyChecking }, 156511b41d2SMark Murray { "compression", oCompression }, 157511b41d2SMark Murray { "compressionlevel", oCompressionLevel }, 158511b41d2SMark Murray { "keepalive", oKeepAlives }, 159511b41d2SMark Murray { "numberofpasswordprompts", oNumberOfPasswordPrompts }, 160511b41d2SMark Murray { "tisauthentication", oTISAuthentication }, 161511b41d2SMark Murray { "loglevel", oLogLevel }, 162511b41d2SMark Murray { NULL, 0 } 163511b41d2SMark Murray }; 164511b41d2SMark Murray 165511b41d2SMark Murray /* Characters considered whitespace in strtok calls. */ 166511b41d2SMark Murray #define WHITESPACE " \t\r\n" 167511b41d2SMark Murray 168511b41d2SMark Murray 169511b41d2SMark Murray /* 170511b41d2SMark Murray * Adds a local TCP/IP port forward to options. Never returns if there is an 171511b41d2SMark Murray * error. 172511b41d2SMark Murray */ 173511b41d2SMark Murray 174511b41d2SMark Murray void 175511b41d2SMark Murray add_local_forward(Options *options, u_short port, const char *host, 176511b41d2SMark Murray u_short host_port) 177511b41d2SMark Murray { 178511b41d2SMark Murray Forward *fwd; 179511b41d2SMark Murray extern uid_t original_real_uid; 180511b41d2SMark Murray if (port < IPPORT_RESERVED && original_real_uid != 0) 181511b41d2SMark Murray fatal("Privileged ports can only be forwarded by root.\n"); 182511b41d2SMark Murray if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION) 183511b41d2SMark Murray fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION); 184511b41d2SMark Murray fwd = &options->local_forwards[options->num_local_forwards++]; 185511b41d2SMark Murray fwd->port = port; 186511b41d2SMark Murray fwd->host = xstrdup(host); 187511b41d2SMark Murray fwd->host_port = host_port; 188511b41d2SMark Murray } 189511b41d2SMark Murray 190511b41d2SMark Murray /* 191511b41d2SMark Murray * Adds a remote TCP/IP port forward to options. Never returns if there is 192511b41d2SMark Murray * an error. 193511b41d2SMark Murray */ 194511b41d2SMark Murray 195511b41d2SMark Murray void 196511b41d2SMark Murray add_remote_forward(Options *options, u_short port, const char *host, 197511b41d2SMark Murray u_short host_port) 198511b41d2SMark Murray { 199511b41d2SMark Murray Forward *fwd; 200511b41d2SMark Murray if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION) 201511b41d2SMark Murray fatal("Too many remote forwards (max %d).", 202511b41d2SMark Murray SSH_MAX_FORWARDS_PER_DIRECTION); 203511b41d2SMark Murray fwd = &options->remote_forwards[options->num_remote_forwards++]; 204511b41d2SMark Murray fwd->port = port; 205511b41d2SMark Murray fwd->host = xstrdup(host); 206511b41d2SMark Murray fwd->host_port = host_port; 207511b41d2SMark Murray } 208511b41d2SMark Murray 209511b41d2SMark Murray /* 210511b41d2SMark Murray * Returns the number of the token pointed to by cp of length len. Never 211511b41d2SMark Murray * returns if the token is not known. 212511b41d2SMark Murray */ 213511b41d2SMark Murray 214511b41d2SMark Murray static OpCodes 215511b41d2SMark Murray parse_token(const char *cp, const char *filename, int linenum) 216511b41d2SMark Murray { 217511b41d2SMark Murray unsigned int i; 218511b41d2SMark Murray 219511b41d2SMark Murray for (i = 0; keywords[i].name; i++) 220511b41d2SMark Murray if (strcasecmp(cp, keywords[i].name) == 0) 221511b41d2SMark Murray return keywords[i].opcode; 222511b41d2SMark Murray 223511b41d2SMark Murray fprintf(stderr, "%s: line %d: Bad configuration option: %s\n", 224511b41d2SMark Murray filename, linenum, cp); 225511b41d2SMark Murray return oBadOption; 226511b41d2SMark Murray } 227511b41d2SMark Murray 228511b41d2SMark Murray /* 229511b41d2SMark Murray * Processes a single option line as used in the configuration files. This 230511b41d2SMark Murray * only sets those values that have not already been set. 231511b41d2SMark Murray */ 232511b41d2SMark Murray 233511b41d2SMark Murray int 234511b41d2SMark Murray process_config_line(Options *options, const char *host, 235511b41d2SMark Murray char *line, const char *filename, int linenum, 236511b41d2SMark Murray int *activep) 237511b41d2SMark Murray { 238511b41d2SMark Murray char buf[256], *cp, *string, **charptr, *cp2; 239511b41d2SMark Murray int opcode, *intptr, value; 240511b41d2SMark Murray u_short fwd_port, fwd_host_port; 241511b41d2SMark Murray 242511b41d2SMark Murray /* Skip leading whitespace. */ 243511b41d2SMark Murray cp = line + strspn(line, WHITESPACE); 244511b41d2SMark Murray if (!*cp || *cp == '\n' || *cp == '#') 245511b41d2SMark Murray return 0; 246511b41d2SMark Murray 247511b41d2SMark Murray /* Get the keyword. (Each line is supposed to begin with a keyword). */ 248511b41d2SMark Murray cp = strtok(cp, WHITESPACE); 249511b41d2SMark Murray opcode = parse_token(cp, filename, linenum); 250511b41d2SMark Murray 251511b41d2SMark Murray switch (opcode) { 252511b41d2SMark Murray case oBadOption: 253511b41d2SMark Murray /* don't panic, but count bad options */ 254511b41d2SMark Murray return -1; 255511b41d2SMark Murray /* NOTREACHED */ 256511b41d2SMark Murray case oForwardAgent: 257511b41d2SMark Murray intptr = &options->forward_agent; 258511b41d2SMark Murray parse_flag: 259511b41d2SMark Murray cp = strtok(NULL, WHITESPACE); 260511b41d2SMark Murray if (!cp) 261511b41d2SMark Murray fatal("%.200s line %d: Missing yes/no argument.", filename, linenum); 262511b41d2SMark Murray value = 0; /* To avoid compiler warning... */ 263511b41d2SMark Murray if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0) 264511b41d2SMark Murray value = 1; 265511b41d2SMark Murray else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0) 266511b41d2SMark Murray value = 0; 267511b41d2SMark Murray else 268511b41d2SMark Murray fatal("%.200s line %d: Bad yes/no argument.", filename, linenum); 269511b41d2SMark Murray if (*activep && *intptr == -1) 270511b41d2SMark Murray *intptr = value; 271511b41d2SMark Murray break; 272511b41d2SMark Murray 273511b41d2SMark Murray case oForwardX11: 274511b41d2SMark Murray intptr = &options->forward_x11; 275511b41d2SMark Murray goto parse_flag; 276511b41d2SMark Murray 277511b41d2SMark Murray case oGatewayPorts: 278511b41d2SMark Murray intptr = &options->gateway_ports; 279511b41d2SMark Murray goto parse_flag; 280511b41d2SMark Murray 281511b41d2SMark Murray case oUsePrivilegedPort: 282511b41d2SMark Murray intptr = &options->use_privileged_port; 283511b41d2SMark Murray goto parse_flag; 284511b41d2SMark Murray 285511b41d2SMark Murray case oRhostsAuthentication: 286511b41d2SMark Murray intptr = &options->rhosts_authentication; 287511b41d2SMark Murray goto parse_flag; 288511b41d2SMark Murray 289511b41d2SMark Murray case oPasswordAuthentication: 290511b41d2SMark Murray intptr = &options->password_authentication; 291511b41d2SMark Murray goto parse_flag; 292511b41d2SMark Murray 293511b41d2SMark Murray case oRSAAuthentication: 294511b41d2SMark Murray intptr = &options->rsa_authentication; 295511b41d2SMark Murray goto parse_flag; 296511b41d2SMark Murray 297511b41d2SMark Murray case oRhostsRSAAuthentication: 298511b41d2SMark Murray intptr = &options->rhosts_rsa_authentication; 299511b41d2SMark Murray goto parse_flag; 300511b41d2SMark Murray 301511b41d2SMark Murray case oTISAuthentication: 302511b41d2SMark Murray /* fallthrough, there is no difference on the client side */ 303511b41d2SMark Murray case oSkeyAuthentication: 304511b41d2SMark Murray intptr = &options->skey_authentication; 305511b41d2SMark Murray goto parse_flag; 306511b41d2SMark Murray 307511b41d2SMark Murray #ifdef KRB4 308fe5fd017SMark Murray case oKrb4Authentication: 309fe5fd017SMark Murray intptr = &options->krb4_authentication; 310511b41d2SMark Murray goto parse_flag; 311511b41d2SMark Murray #endif /* KRB4 */ 312511b41d2SMark Murray 313fe5fd017SMark Murray #ifdef KRB5 314fe5fd017SMark Murray case oKrb5Authentication: 315fe5fd017SMark Murray intptr = &options->krb5_authentication; 316fe5fd017SMark Murray goto parse_flag; 317fe5fd017SMark Murray 318fe5fd017SMark Murray case oKrb5TgtPassing: 319fe5fd017SMark Murray intptr = &options->krb5_tgt_passing; 320fe5fd017SMark Murray goto parse_flag; 321fe5fd017SMark Murray #endif /* KRB5 */ 322fe5fd017SMark Murray 323511b41d2SMark Murray #ifdef AFS 324fe5fd017SMark Murray case oKrb4TgtPassing: 325fe5fd017SMark Murray intptr = &options->krb4_tgt_passing; 326511b41d2SMark Murray goto parse_flag; 327511b41d2SMark Murray 328511b41d2SMark Murray case oAFSTokenPassing: 329511b41d2SMark Murray intptr = &options->afs_token_passing; 330511b41d2SMark Murray goto parse_flag; 331511b41d2SMark Murray #endif 332511b41d2SMark Murray 333511b41d2SMark Murray case oFallBackToRsh: 334511b41d2SMark Murray intptr = &options->fallback_to_rsh; 335511b41d2SMark Murray goto parse_flag; 336511b41d2SMark Murray 337511b41d2SMark Murray case oUseRsh: 338511b41d2SMark Murray intptr = &options->use_rsh; 339511b41d2SMark Murray goto parse_flag; 340511b41d2SMark Murray 341511b41d2SMark Murray case oBatchMode: 342511b41d2SMark Murray intptr = &options->batch_mode; 343511b41d2SMark Murray goto parse_flag; 344511b41d2SMark Murray 345511b41d2SMark Murray case oCheckHostIP: 346511b41d2SMark Murray intptr = &options->check_host_ip; 347511b41d2SMark Murray goto parse_flag; 348511b41d2SMark Murray 349511b41d2SMark Murray case oStrictHostKeyChecking: 350511b41d2SMark Murray intptr = &options->strict_host_key_checking; 351511b41d2SMark Murray cp = strtok(NULL, WHITESPACE); 352511b41d2SMark Murray if (!cp) 353511b41d2SMark Murray fatal("%.200s line %d: Missing yes/no argument.", 354511b41d2SMark Murray filename, linenum); 355511b41d2SMark Murray value = 0; /* To avoid compiler warning... */ 356511b41d2SMark Murray if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0) 357511b41d2SMark Murray value = 1; 358511b41d2SMark Murray else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0) 359511b41d2SMark Murray value = 0; 360511b41d2SMark Murray else if (strcmp(cp, "ask") == 0) 361511b41d2SMark Murray value = 2; 362511b41d2SMark Murray else 363511b41d2SMark Murray fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum); 364511b41d2SMark Murray if (*activep && *intptr == -1) 365511b41d2SMark Murray *intptr = value; 366511b41d2SMark Murray break; 367511b41d2SMark Murray 368511b41d2SMark Murray case oCompression: 369511b41d2SMark Murray intptr = &options->compression; 370511b41d2SMark Murray goto parse_flag; 371511b41d2SMark Murray 372511b41d2SMark Murray case oKeepAlives: 373511b41d2SMark Murray intptr = &options->keepalives; 374511b41d2SMark Murray goto parse_flag; 375511b41d2SMark Murray 376511b41d2SMark Murray case oNumberOfPasswordPrompts: 377511b41d2SMark Murray intptr = &options->number_of_password_prompts; 378511b41d2SMark Murray goto parse_int; 379511b41d2SMark Murray 380511b41d2SMark Murray case oCompressionLevel: 381511b41d2SMark Murray intptr = &options->compression_level; 382511b41d2SMark Murray goto parse_int; 383511b41d2SMark Murray 384511b41d2SMark Murray case oIdentityFile: 385511b41d2SMark Murray cp = strtok(NULL, WHITESPACE); 386511b41d2SMark Murray if (!cp) 387511b41d2SMark Murray fatal("%.200s line %d: Missing argument.", filename, linenum); 388511b41d2SMark Murray if (*activep) { 389511b41d2SMark Murray if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES) 390511b41d2SMark Murray fatal("%.200s line %d: Too many identity files specified (max %d).", 391511b41d2SMark Murray filename, linenum, SSH_MAX_IDENTITY_FILES); 392511b41d2SMark Murray options->identity_files[options->num_identity_files++] = xstrdup(cp); 393511b41d2SMark Murray } 394511b41d2SMark Murray break; 395511b41d2SMark Murray 396511b41d2SMark Murray case oUser: 397511b41d2SMark Murray charptr = &options->user; 398511b41d2SMark Murray parse_string: 399511b41d2SMark Murray cp = strtok(NULL, WHITESPACE); 400511b41d2SMark Murray if (!cp) 401511b41d2SMark Murray fatal("%.200s line %d: Missing argument.", filename, linenum); 402511b41d2SMark Murray if (*activep && *charptr == NULL) 403511b41d2SMark Murray *charptr = xstrdup(cp); 404511b41d2SMark Murray break; 405511b41d2SMark Murray 406511b41d2SMark Murray case oGlobalKnownHostsFile: 407511b41d2SMark Murray charptr = &options->system_hostfile; 408511b41d2SMark Murray goto parse_string; 409511b41d2SMark Murray 410511b41d2SMark Murray case oUserKnownHostsFile: 411511b41d2SMark Murray charptr = &options->user_hostfile; 412511b41d2SMark Murray goto parse_string; 413511b41d2SMark Murray 414511b41d2SMark Murray case oHostName: 415511b41d2SMark Murray charptr = &options->hostname; 416511b41d2SMark Murray goto parse_string; 417511b41d2SMark Murray 418511b41d2SMark Murray case oProxyCommand: 419511b41d2SMark Murray charptr = &options->proxy_command; 420511b41d2SMark Murray string = xstrdup(""); 421511b41d2SMark Murray while ((cp = strtok(NULL, WHITESPACE)) != NULL) { 422511b41d2SMark Murray string = xrealloc(string, strlen(string) + strlen(cp) + 2); 423511b41d2SMark Murray strcat(string, " "); 424511b41d2SMark Murray strcat(string, cp); 425511b41d2SMark Murray } 426511b41d2SMark Murray if (*activep && *charptr == NULL) 427511b41d2SMark Murray *charptr = string; 428511b41d2SMark Murray else 429511b41d2SMark Murray xfree(string); 430511b41d2SMark Murray return 0; 431511b41d2SMark Murray 432511b41d2SMark Murray case oPort: 433511b41d2SMark Murray intptr = &options->port; 434511b41d2SMark Murray parse_int: 435511b41d2SMark Murray cp = strtok(NULL, WHITESPACE); 436511b41d2SMark Murray if (!cp) 437511b41d2SMark Murray fatal("%.200s line %d: Missing argument.", filename, linenum); 438511b41d2SMark Murray if (cp[0] < '0' || cp[0] > '9') 439511b41d2SMark Murray fatal("%.200s line %d: Bad number.", filename, linenum); 440511b41d2SMark Murray 441511b41d2SMark Murray /* Octal, decimal, or hex format? */ 442511b41d2SMark Murray value = strtol(cp, &cp2, 0); 443511b41d2SMark Murray if (cp == cp2) 444511b41d2SMark Murray fatal("%.200s line %d: Bad number.", filename, linenum); 445511b41d2SMark Murray if (*activep && *intptr == -1) 446511b41d2SMark Murray *intptr = value; 447511b41d2SMark Murray break; 448511b41d2SMark Murray 449511b41d2SMark Murray case oConnectionAttempts: 450511b41d2SMark Murray intptr = &options->connection_attempts; 451511b41d2SMark Murray goto parse_int; 452511b41d2SMark Murray 453511b41d2SMark Murray case oCipher: 454511b41d2SMark Murray intptr = &options->cipher; 455511b41d2SMark Murray cp = strtok(NULL, WHITESPACE); 456511b41d2SMark Murray value = cipher_number(cp); 457511b41d2SMark Murray if (value == -1) 458511b41d2SMark Murray fatal("%.200s line %d: Bad cipher '%s'.", 459511b41d2SMark Murray filename, linenum, cp ? cp : "<NONE>"); 460511b41d2SMark Murray if (*activep && *intptr == -1) 461511b41d2SMark Murray *intptr = value; 462511b41d2SMark Murray break; 463511b41d2SMark Murray 464511b41d2SMark Murray case oLogLevel: 465511b41d2SMark Murray intptr = (int *) &options->log_level; 466511b41d2SMark Murray cp = strtok(NULL, WHITESPACE); 467511b41d2SMark Murray value = log_level_number(cp); 468511b41d2SMark Murray if (value == (LogLevel) - 1) 469511b41d2SMark Murray fatal("%.200s line %d: unsupported log level '%s'\n", 470511b41d2SMark Murray filename, linenum, cp ? cp : "<NONE>"); 471511b41d2SMark Murray if (*activep && (LogLevel) * intptr == -1) 472511b41d2SMark Murray *intptr = (LogLevel) value; 473511b41d2SMark Murray break; 474511b41d2SMark Murray 475511b41d2SMark Murray case oRemoteForward: 476511b41d2SMark Murray cp = strtok(NULL, WHITESPACE); 477511b41d2SMark Murray if (!cp) 478511b41d2SMark Murray fatal("%.200s line %d: Missing argument.", filename, linenum); 479511b41d2SMark Murray if (cp[0] < '0' || cp[0] > '9') 480511b41d2SMark Murray fatal("%.200s line %d: Badly formatted port number.", 481511b41d2SMark Murray filename, linenum); 482511b41d2SMark Murray fwd_port = atoi(cp); 483511b41d2SMark Murray cp = strtok(NULL, WHITESPACE); 484511b41d2SMark Murray if (!cp) 485511b41d2SMark Murray fatal("%.200s line %d: Missing second argument.", 486511b41d2SMark Murray filename, linenum); 487511b41d2SMark Murray if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2) 488511b41d2SMark Murray fatal("%.200s line %d: Badly formatted host:port.", 489511b41d2SMark Murray filename, linenum); 490511b41d2SMark Murray if (*activep) 491511b41d2SMark Murray add_remote_forward(options, fwd_port, buf, fwd_host_port); 492511b41d2SMark Murray break; 493511b41d2SMark Murray 494511b41d2SMark Murray case oLocalForward: 495511b41d2SMark Murray cp = strtok(NULL, WHITESPACE); 496511b41d2SMark Murray if (!cp) 497511b41d2SMark Murray fatal("%.200s line %d: Missing argument.", filename, linenum); 498511b41d2SMark Murray if (cp[0] < '0' || cp[0] > '9') 499511b41d2SMark Murray fatal("%.200s line %d: Badly formatted port number.", 500511b41d2SMark Murray filename, linenum); 501511b41d2SMark Murray fwd_port = atoi(cp); 502511b41d2SMark Murray cp = strtok(NULL, WHITESPACE); 503511b41d2SMark Murray if (!cp) 504511b41d2SMark Murray fatal("%.200s line %d: Missing second argument.", 505511b41d2SMark Murray filename, linenum); 506511b41d2SMark Murray if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2) 507511b41d2SMark Murray fatal("%.200s line %d: Badly formatted host:port.", 508511b41d2SMark Murray filename, linenum); 509511b41d2SMark Murray if (*activep) 510511b41d2SMark Murray add_local_forward(options, fwd_port, buf, fwd_host_port); 511511b41d2SMark Murray break; 512511b41d2SMark Murray 513511b41d2SMark Murray case oHost: 514511b41d2SMark Murray *activep = 0; 515511b41d2SMark Murray while ((cp = strtok(NULL, WHITESPACE)) != NULL) 516511b41d2SMark Murray if (match_pattern(host, cp)) { 517511b41d2SMark Murray debug("Applying options for %.100s", cp); 518511b41d2SMark Murray *activep = 1; 519511b41d2SMark Murray break; 520511b41d2SMark Murray } 521511b41d2SMark Murray /* Avoid garbage check below, as strtok already returned NULL. */ 522511b41d2SMark Murray return 0; 523511b41d2SMark Murray 524511b41d2SMark Murray case oEscapeChar: 525511b41d2SMark Murray intptr = &options->escape_char; 526511b41d2SMark Murray cp = strtok(NULL, WHITESPACE); 527511b41d2SMark Murray if (!cp) 528511b41d2SMark Murray fatal("%.200s line %d: Missing argument.", filename, linenum); 529511b41d2SMark Murray if (cp[0] == '^' && cp[2] == 0 && 530511b41d2SMark Murray (unsigned char) cp[1] >= 64 && (unsigned char) cp[1] < 128) 531511b41d2SMark Murray value = (unsigned char) cp[1] & 31; 532511b41d2SMark Murray else if (strlen(cp) == 1) 533511b41d2SMark Murray value = (unsigned char) cp[0]; 534511b41d2SMark Murray else if (strcmp(cp, "none") == 0) 535511b41d2SMark Murray value = -2; 536511b41d2SMark Murray else { 537511b41d2SMark Murray fatal("%.200s line %d: Bad escape character.", 538511b41d2SMark Murray filename, linenum); 539511b41d2SMark Murray /* NOTREACHED */ 540511b41d2SMark Murray value = 0; /* Avoid compiler warning. */ 541511b41d2SMark Murray } 542511b41d2SMark Murray if (*activep && *intptr == -1) 543511b41d2SMark Murray *intptr = value; 544511b41d2SMark Murray break; 545511b41d2SMark Murray 546511b41d2SMark Murray default: 547511b41d2SMark Murray fatal("process_config_line: Unimplemented opcode %d", opcode); 548511b41d2SMark Murray } 549511b41d2SMark Murray 550511b41d2SMark Murray /* Check that there is no garbage at end of line. */ 551511b41d2SMark Murray if (strtok(NULL, WHITESPACE) != NULL) 552511b41d2SMark Murray fatal("%.200s line %d: garbage at end of line.", 553511b41d2SMark Murray filename, linenum); 554511b41d2SMark Murray return 0; 555511b41d2SMark Murray } 556511b41d2SMark Murray 557511b41d2SMark Murray 558511b41d2SMark Murray /* 559511b41d2SMark Murray * Reads the config file and modifies the options accordingly. Options 560511b41d2SMark Murray * should already be initialized before this call. This never returns if 561511b41d2SMark Murray * there is an error. If the file does not exist, this returns immediately. 562511b41d2SMark Murray */ 563511b41d2SMark Murray 564511b41d2SMark Murray void 565511b41d2SMark Murray read_config_file(const char *filename, const char *host, Options *options) 566511b41d2SMark Murray { 567511b41d2SMark Murray FILE *f; 568511b41d2SMark Murray char line[1024]; 569511b41d2SMark Murray int active, linenum; 570511b41d2SMark Murray int bad_options = 0; 571511b41d2SMark Murray 572511b41d2SMark Murray /* Open the file. */ 573511b41d2SMark Murray f = fopen(filename, "r"); 574511b41d2SMark Murray if (!f) 575511b41d2SMark Murray return; 576511b41d2SMark Murray 577511b41d2SMark Murray debug("Reading configuration data %.200s", filename); 578511b41d2SMark Murray 579511b41d2SMark Murray /* 580511b41d2SMark Murray * Mark that we are now processing the options. This flag is turned 581511b41d2SMark Murray * on/off by Host specifications. 582511b41d2SMark Murray */ 583511b41d2SMark Murray active = 1; 584511b41d2SMark Murray linenum = 0; 585511b41d2SMark Murray while (fgets(line, sizeof(line), f)) { 586511b41d2SMark Murray /* Update line number counter. */ 587511b41d2SMark Murray linenum++; 588511b41d2SMark Murray if (process_config_line(options, host, line, filename, linenum, &active) != 0) 589511b41d2SMark Murray bad_options++; 590511b41d2SMark Murray } 591511b41d2SMark Murray fclose(f); 592511b41d2SMark Murray if (bad_options > 0) 593511b41d2SMark Murray fatal("%s: terminating, %d bad configuration options\n", 594511b41d2SMark Murray filename, bad_options); 595511b41d2SMark Murray } 596511b41d2SMark Murray 597511b41d2SMark Murray /* 598511b41d2SMark Murray * Initializes options to special values that indicate that they have not yet 599511b41d2SMark Murray * been set. Read_config_file will only set options with this value. Options 600511b41d2SMark Murray * are processed in the following order: command line, user config file, 601511b41d2SMark Murray * system config file. Last, fill_default_options is called. 602511b41d2SMark Murray */ 603511b41d2SMark Murray 604511b41d2SMark Murray void 605511b41d2SMark Murray initialize_options(Options * options) 606511b41d2SMark Murray { 607511b41d2SMark Murray memset(options, 'X', sizeof(*options)); 608511b41d2SMark Murray options->forward_agent = -1; 609511b41d2SMark Murray options->forward_x11 = -1; 610511b41d2SMark Murray options->gateway_ports = -1; 611511b41d2SMark Murray options->use_privileged_port = -1; 612511b41d2SMark Murray options->rhosts_authentication = -1; 613511b41d2SMark Murray options->rsa_authentication = -1; 614511b41d2SMark Murray options->skey_authentication = -1; 615511b41d2SMark Murray #ifdef KRB4 616fe5fd017SMark Murray options->krb4_authentication = -1; 617511b41d2SMark Murray #endif 618fe5fd017SMark Murray #ifdef KRB5 619fe5fd017SMark Murray options->krb5_authentication = -1; 620fe5fd017SMark Murray options->krb5_tgt_passing = -1; 621fe5fd017SMark Murray #endif /* KRB5 */ 622511b41d2SMark Murray #ifdef AFS 623fe5fd017SMark Murray options->krb4_tgt_passing = -1; 624511b41d2SMark Murray options->afs_token_passing = -1; 625511b41d2SMark Murray #endif 626511b41d2SMark Murray options->password_authentication = -1; 627511b41d2SMark Murray options->rhosts_rsa_authentication = -1; 628511b41d2SMark Murray options->fallback_to_rsh = -1; 629511b41d2SMark Murray options->use_rsh = -1; 630511b41d2SMark Murray options->batch_mode = -1; 631511b41d2SMark Murray options->check_host_ip = -1; 632511b41d2SMark Murray options->strict_host_key_checking = -1; 633511b41d2SMark Murray options->compression = -1; 634511b41d2SMark Murray options->keepalives = -1; 635511b41d2SMark Murray options->compression_level = -1; 636511b41d2SMark Murray options->port = -1; 637511b41d2SMark Murray options->connection_attempts = -1; 638511b41d2SMark Murray options->number_of_password_prompts = -1; 639511b41d2SMark Murray options->cipher = -1; 640511b41d2SMark Murray options->num_identity_files = 0; 641511b41d2SMark Murray options->hostname = NULL; 642511b41d2SMark Murray options->proxy_command = NULL; 643511b41d2SMark Murray options->user = NULL; 644511b41d2SMark Murray options->escape_char = -1; 645511b41d2SMark Murray options->system_hostfile = NULL; 646511b41d2SMark Murray options->user_hostfile = NULL; 647511b41d2SMark Murray options->num_local_forwards = 0; 648511b41d2SMark Murray options->num_remote_forwards = 0; 649511b41d2SMark Murray options->log_level = (LogLevel) - 1; 650511b41d2SMark Murray } 651511b41d2SMark Murray 652511b41d2SMark Murray /* 653511b41d2SMark Murray * Called after processing other sources of option data, this fills those 654511b41d2SMark Murray * options for which no value has been specified with their default values. 655511b41d2SMark Murray */ 656511b41d2SMark Murray 657511b41d2SMark Murray void 658511b41d2SMark Murray fill_default_options(Options * options) 659511b41d2SMark Murray { 660511b41d2SMark Murray if (options->forward_agent == -1) 661511b41d2SMark Murray options->forward_agent = 1; 662511b41d2SMark Murray if (options->forward_x11 == -1) 6635dc73ebeSBrian Feldman options->forward_x11 = 0; 664511b41d2SMark Murray if (options->gateway_ports == -1) 665511b41d2SMark Murray options->gateway_ports = 0; 666511b41d2SMark Murray if (options->use_privileged_port == -1) 667511b41d2SMark Murray options->use_privileged_port = 1; 668511b41d2SMark Murray if (options->rhosts_authentication == -1) 669511b41d2SMark Murray options->rhosts_authentication = 1; 670511b41d2SMark Murray if (options->rsa_authentication == -1) 671511b41d2SMark Murray options->rsa_authentication = 1; 672511b41d2SMark Murray if (options->skey_authentication == -1) 673511b41d2SMark Murray options->skey_authentication = 0; 674511b41d2SMark Murray #ifdef KRB4 675fe5fd017SMark Murray if (options->krb4_authentication == -1) 676fe5fd017SMark Murray options->krb4_authentication = 1; 677511b41d2SMark Murray #endif /* KRB4 */ 678fe5fd017SMark Murray #ifdef KRB5 679fe5fd017SMark Murray if (options->krb5_authentication == -1) 680fe5fd017SMark Murray options->krb5_authentication = 1; 681fe5fd017SMark Murray if (options->krb5_tgt_passing == -1) 682fe5fd017SMark Murray options->krb5_tgt_passing = 1; 683fe5fd017SMark Murray #endif /* KRB5 */ 684511b41d2SMark Murray #ifdef AFS 685fe5fd017SMark Murray if (options->krb4_tgt_passing == -1) 686fe5fd017SMark Murray options->krb4_tgt_passing = 1; 687511b41d2SMark Murray if (options->afs_token_passing == -1) 688511b41d2SMark Murray options->afs_token_passing = 1; 689511b41d2SMark Murray #endif /* AFS */ 690511b41d2SMark Murray if (options->password_authentication == -1) 691511b41d2SMark Murray options->password_authentication = 1; 692511b41d2SMark Murray if (options->rhosts_rsa_authentication == -1) 693511b41d2SMark Murray options->rhosts_rsa_authentication = 1; 694511b41d2SMark Murray if (options->fallback_to_rsh == -1) 695511b41d2SMark Murray options->fallback_to_rsh = 1; 696511b41d2SMark Murray if (options->use_rsh == -1) 697511b41d2SMark Murray options->use_rsh = 0; 698511b41d2SMark Murray if (options->batch_mode == -1) 699511b41d2SMark Murray options->batch_mode = 0; 700511b41d2SMark Murray if (options->check_host_ip == -1) 701a95c1225SBrian Feldman options->check_host_ip = 0; 702511b41d2SMark Murray if (options->strict_host_key_checking == -1) 703511b41d2SMark Murray options->strict_host_key_checking = 2; /* 2 is default */ 704511b41d2SMark Murray if (options->compression == -1) 705511b41d2SMark Murray options->compression = 0; 706511b41d2SMark Murray if (options->keepalives == -1) 707511b41d2SMark Murray options->keepalives = 1; 708511b41d2SMark Murray if (options->compression_level == -1) 709511b41d2SMark Murray options->compression_level = 6; 710511b41d2SMark Murray if (options->port == -1) 711511b41d2SMark Murray options->port = 0; /* Filled in ssh_connect. */ 712511b41d2SMark Murray if (options->connection_attempts == -1) 713511b41d2SMark Murray options->connection_attempts = 4; 714511b41d2SMark Murray if (options->number_of_password_prompts == -1) 715511b41d2SMark Murray options->number_of_password_prompts = 3; 716511b41d2SMark Murray /* Selected in ssh_login(). */ 717511b41d2SMark Murray if (options->cipher == -1) 718511b41d2SMark Murray options->cipher = SSH_CIPHER_NOT_SET; 719511b41d2SMark Murray if (options->num_identity_files == 0) { 720511b41d2SMark Murray options->identity_files[0] = 721511b41d2SMark Murray xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1); 722511b41d2SMark Murray sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY); 723511b41d2SMark Murray options->num_identity_files = 1; 724511b41d2SMark Murray } 725511b41d2SMark Murray if (options->escape_char == -1) 726511b41d2SMark Murray options->escape_char = '~'; 727511b41d2SMark Murray if (options->system_hostfile == NULL) 728511b41d2SMark Murray options->system_hostfile = SSH_SYSTEM_HOSTFILE; 729511b41d2SMark Murray if (options->user_hostfile == NULL) 730511b41d2SMark Murray options->user_hostfile = SSH_USER_HOSTFILE; 731511b41d2SMark Murray if (options->log_level == (LogLevel) - 1) 732511b41d2SMark Murray options->log_level = SYSLOG_LEVEL_INFO; 733511b41d2SMark Murray /* options->proxy_command should not be set by default */ 734511b41d2SMark Murray /* options->user will be set in the main program if appropriate */ 735511b41d2SMark Murray /* options->hostname will be set in the main program if appropriate */ 736511b41d2SMark Murray } 737