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