blob: 3b75290f395029ee98ddf1f02ab2508547a3805d [file] [log] [blame]
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001/*
Damien Miller4af51302000-04-16 11:18:38 +10002 *
Damien Miller95def091999-11-25 00:26:21 +11003 * readconf.c
Damien Miller4af51302000-04-16 11:18:38 +10004 *
Damien Miller95def091999-11-25 00:26:21 +11005 * Author: Tatu Ylonen <ylo@cs.hut.fi>
Damien Miller4af51302000-04-16 11:18:38 +10006 *
Damien Miller95def091999-11-25 00:26:21 +11007 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 * All rights reserved
Damien Miller4af51302000-04-16 11:18:38 +10009 *
Damien Miller95def091999-11-25 00:26:21 +110010 * Created: Sat Apr 22 00:03:10 1995 ylo
Damien Miller4af51302000-04-16 11:18:38 +100011 *
Damien Miller95def091999-11-25 00:26:21 +110012 * Functions for reading the configuration files.
Damien Miller4af51302000-04-16 11:18:38 +100013 *
Damien Miller95def091999-11-25 00:26:21 +110014 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100015
16#include "includes.h"
Damien Miller4af51302000-04-16 11:18:38 +100017RCSID("$Id: readconf.c,v 1.11 2000/04/16 01:18:44 damien Exp $");
Damien Millerd4a8b7e1999-10-27 13:42:43 +100018
19#include "ssh.h"
20#include "cipher.h"
21#include "readconf.h"
Damien Millerb38eff82000-04-01 11:09:21 +100022#include "match.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100023#include "xmalloc.h"
Damien Miller78928792000-04-12 20:17:38 +100024#include "compat.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100025
26/* Format of the configuration file:
27
28 # Configuration data is parsed as follows:
29 # 1. command line options
30 # 2. user-specific file
31 # 3. system-wide file
32 # Any configuration value is only changed the first time it is set.
33 # Thus, host-specific definitions should be at the beginning of the
34 # configuration file, and defaults at the end.
35
36 # Host-specific declarations. These may override anything above. A single
37 # host may match multiple declarations; these are processed in the order
38 # that they are given in.
39
40 Host *.ngs.fi ngs.fi
41 FallBackToRsh no
42
43 Host fake.com
44 HostName another.host.name.real.org
45 User blaah
46 Port 34289
47 ForwardX11 no
48 ForwardAgent no
49
50 Host books.com
51 RemoteForward 9999 shadows.cs.hut.fi:9999
52 Cipher 3des
53
54 Host fascist.blob.com
55 Port 23123
56 User tylonen
57 RhostsAuthentication no
58 PasswordAuthentication no
59
60 Host puukko.hut.fi
61 User t35124p
62 ProxyCommand ssh-proxy %h %p
63
64 Host *.fr
65 UseRsh yes
66
67 Host *.su
68 Cipher none
69 PasswordAuthentication no
70
71 # Defaults for various options
72 Host *
73 ForwardAgent no
74 ForwardX11 yes
75 RhostsAuthentication yes
76 PasswordAuthentication yes
77 RSAAuthentication yes
78 RhostsRSAAuthentication yes
79 FallBackToRsh no
80 UseRsh no
81 StrictHostKeyChecking yes
82 KeepAlives no
83 IdentityFile ~/.ssh/identity
84 Port 22
85 EscapeChar ~
86
87*/
88
89/* Keyword tokens. */
90
Damien Miller95def091999-11-25 00:26:21 +110091typedef enum {
92 oBadOption,
93 oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
94 oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh,
95 oSkeyAuthentication,
Damien Millerd4a8b7e1999-10-27 13:42:43 +100096#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +110097 oKerberosAuthentication,
Damien Millerd4a8b7e1999-10-27 13:42:43 +100098#endif /* KRB4 */
99#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100100 oKerberosTgtPassing, oAFSTokenPassing,
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000101#endif
Damien Miller95def091999-11-25 00:26:21 +1100102 oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
103 oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
104 oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
105 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
106 oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
Damien Miller78928792000-04-12 20:17:38 +1000107 oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000108} OpCodes;
109
110/* Textual representations of the tokens. */
111
Damien Miller95def091999-11-25 00:26:21 +1100112static struct {
113 const char *name;
114 OpCodes opcode;
115} keywords[] = {
116 { "forwardagent", oForwardAgent },
117 { "forwardx11", oForwardX11 },
118 { "gatewayports", oGatewayPorts },
119 { "useprivilegedport", oUsePrivilegedPort },
120 { "rhostsauthentication", oRhostsAuthentication },
121 { "passwordauthentication", oPasswordAuthentication },
122 { "rsaauthentication", oRSAAuthentication },
123 { "skeyauthentication", oSkeyAuthentication },
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000124#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100125 { "kerberosauthentication", oKerberosAuthentication },
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000126#endif /* KRB4 */
127#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100128 { "kerberostgtpassing", oKerberosTgtPassing },
129 { "afstokenpassing", oAFSTokenPassing },
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000130#endif
Damien Miller95def091999-11-25 00:26:21 +1100131 { "fallbacktorsh", oFallBackToRsh },
132 { "usersh", oUseRsh },
133 { "identityfile", oIdentityFile },
134 { "hostname", oHostName },
135 { "proxycommand", oProxyCommand },
136 { "port", oPort },
137 { "cipher", oCipher },
Damien Miller78928792000-04-12 20:17:38 +1000138 { "ciphers", oCiphers },
139 { "protocol", oProtocol },
Damien Miller95def091999-11-25 00:26:21 +1100140 { "remoteforward", oRemoteForward },
141 { "localforward", oLocalForward },
142 { "user", oUser },
143 { "host", oHost },
144 { "escapechar", oEscapeChar },
145 { "rhostsrsaauthentication", oRhostsRSAAuthentication },
146 { "globalknownhostsfile", oGlobalKnownHostsFile },
147 { "userknownhostsfile", oUserKnownHostsFile },
148 { "connectionattempts", oConnectionAttempts },
149 { "batchmode", oBatchMode },
150 { "checkhostip", oCheckHostIP },
151 { "stricthostkeychecking", oStrictHostKeyChecking },
152 { "compression", oCompression },
153 { "compressionlevel", oCompressionLevel },
154 { "keepalive", oKeepAlives },
155 { "numberofpasswordprompts", oNumberOfPasswordPrompts },
156 { "tisauthentication", oTISAuthentication },
157 { "loglevel", oLogLevel },
158 { NULL, 0 }
Damien Miller5ce662a1999-11-11 17:57:39 +1100159};
160
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000161/* Characters considered whitespace in strtok calls. */
162#define WHITESPACE " \t\r\n"
163
164
Damien Miller5428f641999-11-25 11:54:57 +1100165/*
166 * Adds a local TCP/IP port forward to options. Never returns if there is an
167 * error.
168 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000169
Damien Miller4af51302000-04-16 11:18:38 +1000170void
Damien Milleraae6c611999-12-06 11:47:28 +1100171add_local_forward(Options *options, u_short port, const char *host,
172 u_short host_port)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000173{
Damien Miller95def091999-11-25 00:26:21 +1100174 Forward *fwd;
175 extern uid_t original_real_uid;
Damien Miller95def091999-11-25 00:26:21 +1100176 if (port < IPPORT_RESERVED && original_real_uid != 0)
177 fatal("Privileged ports can only be forwarded by root.\n");
178 if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
179 fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
180 fwd = &options->local_forwards[options->num_local_forwards++];
181 fwd->port = port;
182 fwd->host = xstrdup(host);
183 fwd->host_port = host_port;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000184}
185
Damien Miller5428f641999-11-25 11:54:57 +1100186/*
187 * Adds a remote TCP/IP port forward to options. Never returns if there is
188 * an error.
189 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000190
Damien Miller4af51302000-04-16 11:18:38 +1000191void
Damien Milleraae6c611999-12-06 11:47:28 +1100192add_remote_forward(Options *options, u_short port, const char *host,
193 u_short host_port)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000194{
Damien Miller95def091999-11-25 00:26:21 +1100195 Forward *fwd;
196 if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
197 fatal("Too many remote forwards (max %d).",
198 SSH_MAX_FORWARDS_PER_DIRECTION);
199 fwd = &options->remote_forwards[options->num_remote_forwards++];
200 fwd->port = port;
201 fwd->host = xstrdup(host);
202 fwd->host_port = host_port;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000203}
204
Damien Miller5428f641999-11-25 11:54:57 +1100205/*
206 * Returns the number of the token pointed to by cp of length len. Never
207 * returns if the token is not known.
208 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000209
Damien Miller4af51302000-04-16 11:18:38 +1000210static OpCodes
Damien Miller95def091999-11-25 00:26:21 +1100211parse_token(const char *cp, const char *filename, int linenum)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000212{
Damien Miller95def091999-11-25 00:26:21 +1100213 unsigned int i;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000214
Damien Miller95def091999-11-25 00:26:21 +1100215 for (i = 0; keywords[i].name; i++)
Damien Miller5428f641999-11-25 11:54:57 +1100216 if (strcasecmp(cp, keywords[i].name) == 0)
Damien Miller95def091999-11-25 00:26:21 +1100217 return keywords[i].opcode;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000218
Damien Miller95def091999-11-25 00:26:21 +1100219 fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
220 filename, linenum, cp);
221 return oBadOption;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000222}
223
Damien Miller5428f641999-11-25 11:54:57 +1100224/*
225 * Processes a single option line as used in the configuration files. This
226 * only sets those values that have not already been set.
227 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000228
Damien Miller2ccf6611999-11-15 15:25:10 +1100229int
230process_config_line(Options *options, const char *host,
Damien Miller95def091999-11-25 00:26:21 +1100231 char *line, const char *filename, int linenum,
232 int *activep)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000233{
Damien Miller5428f641999-11-25 11:54:57 +1100234 char buf[256], *cp, *string, **charptr, *cp2;
Damien Milleraae6c611999-12-06 11:47:28 +1100235 int opcode, *intptr, value;
236 u_short fwd_port, fwd_host_port;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000237
Damien Miller95def091999-11-25 00:26:21 +1100238 /* Skip leading whitespace. */
239 cp = line + strspn(line, WHITESPACE);
240 if (!*cp || *cp == '\n' || *cp == '#')
241 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000242
Damien Miller5428f641999-11-25 11:54:57 +1100243 /* Get the keyword. (Each line is supposed to begin with a keyword). */
Damien Miller95def091999-11-25 00:26:21 +1100244 cp = strtok(cp, WHITESPACE);
Damien Miller95def091999-11-25 00:26:21 +1100245 opcode = parse_token(cp, filename, linenum);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000246
Damien Miller95def091999-11-25 00:26:21 +1100247 switch (opcode) {
248 case oBadOption:
Damien Miller5428f641999-11-25 11:54:57 +1100249 /* don't panic, but count bad options */
250 return -1;
Damien Miller95def091999-11-25 00:26:21 +1100251 /* NOTREACHED */
252 case oForwardAgent:
253 intptr = &options->forward_agent;
254parse_flag:
255 cp = strtok(NULL, WHITESPACE);
256 if (!cp)
257 fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
258 value = 0; /* To avoid compiler warning... */
259 if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0)
260 value = 1;
261 else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0)
262 value = 0;
263 else
264 fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
265 if (*activep && *intptr == -1)
266 *intptr = value;
267 break;
268
269 case oForwardX11:
270 intptr = &options->forward_x11;
271 goto parse_flag;
272
273 case oGatewayPorts:
274 intptr = &options->gateway_ports;
275 goto parse_flag;
276
277 case oUsePrivilegedPort:
278 intptr = &options->use_privileged_port;
279 goto parse_flag;
280
281 case oRhostsAuthentication:
282 intptr = &options->rhosts_authentication;
283 goto parse_flag;
284
285 case oPasswordAuthentication:
286 intptr = &options->password_authentication;
287 goto parse_flag;
288
289 case oRSAAuthentication:
290 intptr = &options->rsa_authentication;
291 goto parse_flag;
292
293 case oRhostsRSAAuthentication:
294 intptr = &options->rhosts_rsa_authentication;
295 goto parse_flag;
296
297 case oTISAuthentication:
298 /* fallthrough, there is no difference on the client side */
299 case oSkeyAuthentication:
300 intptr = &options->skey_authentication;
301 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000302
303#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100304 case oKerberosAuthentication:
305 intptr = &options->kerberos_authentication;
306 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000307#endif /* KRB4 */
308
309#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100310 case oKerberosTgtPassing:
311 intptr = &options->kerberos_tgt_passing;
312 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000313
Damien Miller95def091999-11-25 00:26:21 +1100314 case oAFSTokenPassing:
315 intptr = &options->afs_token_passing;
316 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000317#endif
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000318
Damien Miller95def091999-11-25 00:26:21 +1100319 case oFallBackToRsh:
320 intptr = &options->fallback_to_rsh;
321 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000322
Damien Miller95def091999-11-25 00:26:21 +1100323 case oUseRsh:
324 intptr = &options->use_rsh;
325 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000326
Damien Miller95def091999-11-25 00:26:21 +1100327 case oBatchMode:
328 intptr = &options->batch_mode;
329 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000330
Damien Miller95def091999-11-25 00:26:21 +1100331 case oCheckHostIP:
332 intptr = &options->check_host_ip;
333 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000334
Damien Miller95def091999-11-25 00:26:21 +1100335 case oStrictHostKeyChecking:
336 intptr = &options->strict_host_key_checking;
337 cp = strtok(NULL, WHITESPACE);
338 if (!cp)
339 fatal("%.200s line %d: Missing yes/no argument.",
340 filename, linenum);
341 value = 0; /* To avoid compiler warning... */
342 if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0)
343 value = 1;
344 else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0)
345 value = 0;
346 else if (strcmp(cp, "ask") == 0)
347 value = 2;
348 else
349 fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
350 if (*activep && *intptr == -1)
351 *intptr = value;
352 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000353
Damien Miller95def091999-11-25 00:26:21 +1100354 case oCompression:
355 intptr = &options->compression;
356 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000357
Damien Miller95def091999-11-25 00:26:21 +1100358 case oKeepAlives:
359 intptr = &options->keepalives;
360 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000361
Damien Miller95def091999-11-25 00:26:21 +1100362 case oNumberOfPasswordPrompts:
363 intptr = &options->number_of_password_prompts;
364 goto parse_int;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000365
Damien Miller95def091999-11-25 00:26:21 +1100366 case oCompressionLevel:
367 intptr = &options->compression_level;
368 goto parse_int;
369
370 case oIdentityFile:
371 cp = strtok(NULL, WHITESPACE);
372 if (!cp)
373 fatal("%.200s line %d: Missing argument.", filename, linenum);
374 if (*activep) {
375 if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
376 fatal("%.200s line %d: Too many identity files specified (max %d).",
377 filename, linenum, SSH_MAX_IDENTITY_FILES);
378 options->identity_files[options->num_identity_files++] = xstrdup(cp);
379 }
380 break;
381
382 case oUser:
383 charptr = &options->user;
384parse_string:
385 cp = strtok(NULL, WHITESPACE);
386 if (!cp)
387 fatal("%.200s line %d: Missing argument.", filename, linenum);
388 if (*activep && *charptr == NULL)
389 *charptr = xstrdup(cp);
390 break;
391
392 case oGlobalKnownHostsFile:
393 charptr = &options->system_hostfile;
394 goto parse_string;
395
396 case oUserKnownHostsFile:
397 charptr = &options->user_hostfile;
398 goto parse_string;
399
400 case oHostName:
401 charptr = &options->hostname;
402 goto parse_string;
403
404 case oProxyCommand:
405 charptr = &options->proxy_command;
406 string = xstrdup("");
407 while ((cp = strtok(NULL, WHITESPACE)) != NULL) {
408 string = xrealloc(string, strlen(string) + strlen(cp) + 2);
409 strcat(string, " ");
410 strcat(string, cp);
411 }
412 if (*activep && *charptr == NULL)
413 *charptr = string;
414 else
415 xfree(string);
416 return 0;
417
418 case oPort:
419 intptr = &options->port;
420parse_int:
421 cp = strtok(NULL, WHITESPACE);
422 if (!cp)
423 fatal("%.200s line %d: Missing argument.", filename, linenum);
424 if (cp[0] < '0' || cp[0] > '9')
425 fatal("%.200s line %d: Bad number.", filename, linenum);
Damien Miller5428f641999-11-25 11:54:57 +1100426
427 /* Octal, decimal, or hex format? */
428 value = strtol(cp, &cp2, 0);
429 if (cp == cp2)
430 fatal("%.200s line %d: Bad number.", filename, linenum);
Damien Miller95def091999-11-25 00:26:21 +1100431 if (*activep && *intptr == -1)
432 *intptr = value;
433 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000434
Damien Miller95def091999-11-25 00:26:21 +1100435 case oConnectionAttempts:
436 intptr = &options->connection_attempts;
437 goto parse_int;
Damien Miller5ce662a1999-11-11 17:57:39 +1100438
Damien Miller95def091999-11-25 00:26:21 +1100439 case oCipher:
440 intptr = &options->cipher;
441 cp = strtok(NULL, WHITESPACE);
442 value = cipher_number(cp);
443 if (value == -1)
444 fatal("%.200s line %d: Bad cipher '%s'.",
445 filename, linenum, cp ? cp : "<NONE>");
446 if (*activep && *intptr == -1)
447 *intptr = value;
448 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000449
Damien Miller78928792000-04-12 20:17:38 +1000450 case oCiphers:
451 cp = strtok(NULL, WHITESPACE);
452 if (!ciphers_valid(cp))
453 fatal("%.200s line %d: Bad cipher spec '%s'.",
454 filename, linenum, cp ? cp : "<NONE>");
455 if (*activep && options->ciphers == NULL)
456 options->ciphers = xstrdup(cp);
457 break;
458
459 case oProtocol:
460 intptr = &options->protocol;
461 cp = strtok(NULL, WHITESPACE);
462 value = proto_spec(cp);
463 if (value == SSH_PROTO_UNKNOWN)
464 fatal("%.200s line %d: Bad protocol spec '%s'.",
465 filename, linenum, cp ? cp : "<NONE>");
466 if (*activep && *intptr == SSH_PROTO_UNKNOWN)
467 *intptr = value;
468 break;
469
Damien Miller95def091999-11-25 00:26:21 +1100470 case oLogLevel:
471 intptr = (int *) &options->log_level;
472 cp = strtok(NULL, WHITESPACE);
473 value = log_level_number(cp);
474 if (value == (LogLevel) - 1)
475 fatal("%.200s line %d: unsupported log level '%s'\n",
476 filename, linenum, cp ? cp : "<NONE>");
477 if (*activep && (LogLevel) * intptr == -1)
478 *intptr = (LogLevel) value;
479 break;
480
481 case oRemoteForward:
482 cp = strtok(NULL, WHITESPACE);
483 if (!cp)
484 fatal("%.200s line %d: Missing argument.", filename, linenum);
485 if (cp[0] < '0' || cp[0] > '9')
486 fatal("%.200s line %d: Badly formatted port number.",
487 filename, linenum);
488 fwd_port = atoi(cp);
489 cp = strtok(NULL, WHITESPACE);
490 if (!cp)
491 fatal("%.200s line %d: Missing second argument.",
492 filename, linenum);
Damien Milleraae6c611999-12-06 11:47:28 +1100493 if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
Damien Miller95def091999-11-25 00:26:21 +1100494 fatal("%.200s line %d: Badly formatted host:port.",
495 filename, linenum);
496 if (*activep)
497 add_remote_forward(options, fwd_port, buf, fwd_host_port);
498 break;
499
500 case oLocalForward:
501 cp = strtok(NULL, WHITESPACE);
502 if (!cp)
503 fatal("%.200s line %d: Missing argument.", filename, linenum);
504 if (cp[0] < '0' || cp[0] > '9')
505 fatal("%.200s line %d: Badly formatted port number.",
506 filename, linenum);
507 fwd_port = atoi(cp);
508 cp = strtok(NULL, WHITESPACE);
509 if (!cp)
510 fatal("%.200s line %d: Missing second argument.",
511 filename, linenum);
Damien Milleraae6c611999-12-06 11:47:28 +1100512 if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
Damien Miller95def091999-11-25 00:26:21 +1100513 fatal("%.200s line %d: Badly formatted host:port.",
514 filename, linenum);
515 if (*activep)
516 add_local_forward(options, fwd_port, buf, fwd_host_port);
517 break;
518
519 case oHost:
520 *activep = 0;
521 while ((cp = strtok(NULL, WHITESPACE)) != NULL)
522 if (match_pattern(host, cp)) {
523 debug("Applying options for %.100s", cp);
524 *activep = 1;
525 break;
526 }
Damien Miller5428f641999-11-25 11:54:57 +1100527 /* Avoid garbage check below, as strtok already returned NULL. */
Damien Miller95def091999-11-25 00:26:21 +1100528 return 0;
529
530 case oEscapeChar:
531 intptr = &options->escape_char;
532 cp = strtok(NULL, WHITESPACE);
533 if (!cp)
534 fatal("%.200s line %d: Missing argument.", filename, linenum);
535 if (cp[0] == '^' && cp[2] == 0 &&
536 (unsigned char) cp[1] >= 64 && (unsigned char) cp[1] < 128)
537 value = (unsigned char) cp[1] & 31;
538 else if (strlen(cp) == 1)
539 value = (unsigned char) cp[0];
540 else if (strcmp(cp, "none") == 0)
541 value = -2;
542 else {
543 fatal("%.200s line %d: Bad escape character.",
544 filename, linenum);
545 /* NOTREACHED */
546 value = 0; /* Avoid compiler warning. */
547 }
548 if (*activep && *intptr == -1)
549 *intptr = value;
550 break;
551
552 default:
553 fatal("process_config_line: Unimplemented opcode %d", opcode);
554 }
555
556 /* Check that there is no garbage at end of line. */
557 if (strtok(NULL, WHITESPACE) != NULL)
558 fatal("%.200s line %d: garbage at end of line.",
559 filename, linenum);
560 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000561}
562
563
Damien Miller5428f641999-11-25 11:54:57 +1100564/*
565 * Reads the config file and modifies the options accordingly. Options
566 * should already be initialized before this call. This never returns if
567 * there is an error. If the file does not exist, this returns immediately.
568 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000569
Damien Miller4af51302000-04-16 11:18:38 +1000570void
Damien Miller95def091999-11-25 00:26:21 +1100571read_config_file(const char *filename, const char *host, Options *options)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000572{
Damien Miller95def091999-11-25 00:26:21 +1100573 FILE *f;
574 char line[1024];
575 int active, linenum;
576 int bad_options = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000577
Damien Miller95def091999-11-25 00:26:21 +1100578 /* Open the file. */
579 f = fopen(filename, "r");
580 if (!f)
581 return;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000582
Damien Miller95def091999-11-25 00:26:21 +1100583 debug("Reading configuration data %.200s", filename);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000584
Damien Miller5428f641999-11-25 11:54:57 +1100585 /*
586 * Mark that we are now processing the options. This flag is turned
587 * on/off by Host specifications.
588 */
Damien Miller95def091999-11-25 00:26:21 +1100589 active = 1;
590 linenum = 0;
591 while (fgets(line, sizeof(line), f)) {
592 /* Update line number counter. */
593 linenum++;
594 if (process_config_line(options, host, line, filename, linenum, &active) != 0)
595 bad_options++;
596 }
597 fclose(f);
598 if (bad_options > 0)
599 fatal("%s: terminating, %d bad configuration options\n",
600 filename, bad_options);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000601}
602
Damien Miller5428f641999-11-25 11:54:57 +1100603/*
604 * Initializes options to special values that indicate that they have not yet
605 * been set. Read_config_file will only set options with this value. Options
606 * are processed in the following order: command line, user config file,
607 * system config file. Last, fill_default_options is called.
608 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000609
Damien Miller4af51302000-04-16 11:18:38 +1000610void
Damien Miller95def091999-11-25 00:26:21 +1100611initialize_options(Options * options)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000612{
Damien Miller95def091999-11-25 00:26:21 +1100613 memset(options, 'X', sizeof(*options));
614 options->forward_agent = -1;
615 options->forward_x11 = -1;
616 options->gateway_ports = -1;
617 options->use_privileged_port = -1;
618 options->rhosts_authentication = -1;
619 options->rsa_authentication = -1;
620 options->skey_authentication = -1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000621#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100622 options->kerberos_authentication = -1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000623#endif
624#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100625 options->kerberos_tgt_passing = -1;
626 options->afs_token_passing = -1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000627#endif
Damien Miller95def091999-11-25 00:26:21 +1100628 options->password_authentication = -1;
629 options->rhosts_rsa_authentication = -1;
630 options->fallback_to_rsh = -1;
631 options->use_rsh = -1;
632 options->batch_mode = -1;
633 options->check_host_ip = -1;
634 options->strict_host_key_checking = -1;
635 options->compression = -1;
636 options->keepalives = -1;
637 options->compression_level = -1;
638 options->port = -1;
639 options->connection_attempts = -1;
640 options->number_of_password_prompts = -1;
641 options->cipher = -1;
Damien Miller78928792000-04-12 20:17:38 +1000642 options->ciphers = NULL;
643 options->protocol = SSH_PROTO_UNKNOWN;
Damien Miller95def091999-11-25 00:26:21 +1100644 options->num_identity_files = 0;
645 options->hostname = NULL;
646 options->proxy_command = NULL;
647 options->user = NULL;
648 options->escape_char = -1;
649 options->system_hostfile = NULL;
650 options->user_hostfile = NULL;
651 options->num_local_forwards = 0;
652 options->num_remote_forwards = 0;
653 options->log_level = (LogLevel) - 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000654}
655
Damien Miller5428f641999-11-25 11:54:57 +1100656/*
657 * Called after processing other sources of option data, this fills those
658 * options for which no value has been specified with their default values.
659 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000660
Damien Miller4af51302000-04-16 11:18:38 +1000661void
Damien Miller95def091999-11-25 00:26:21 +1100662fill_default_options(Options * options)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000663{
Damien Miller95def091999-11-25 00:26:21 +1100664 if (options->forward_agent == -1)
665 options->forward_agent = 1;
666 if (options->forward_x11 == -1)
Damien Miller98c7ad62000-03-09 21:27:49 +1100667 options->forward_x11 = 0;
Damien Miller95def091999-11-25 00:26:21 +1100668 if (options->gateway_ports == -1)
669 options->gateway_ports = 0;
670 if (options->use_privileged_port == -1)
671 options->use_privileged_port = 1;
672 if (options->rhosts_authentication == -1)
673 options->rhosts_authentication = 1;
674 if (options->rsa_authentication == -1)
675 options->rsa_authentication = 1;
676 if (options->skey_authentication == -1)
677 options->skey_authentication = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000678#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100679 if (options->kerberos_authentication == -1)
680 options->kerberos_authentication = 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000681#endif /* KRB4 */
682#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100683 if (options->kerberos_tgt_passing == -1)
684 options->kerberos_tgt_passing = 1;
685 if (options->afs_token_passing == -1)
686 options->afs_token_passing = 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000687#endif /* AFS */
Damien Miller95def091999-11-25 00:26:21 +1100688 if (options->password_authentication == -1)
689 options->password_authentication = 1;
690 if (options->rhosts_rsa_authentication == -1)
691 options->rhosts_rsa_authentication = 1;
692 if (options->fallback_to_rsh == -1)
693 options->fallback_to_rsh = 1;
694 if (options->use_rsh == -1)
695 options->use_rsh = 0;
696 if (options->batch_mode == -1)
697 options->batch_mode = 0;
698 if (options->check_host_ip == -1)
699 options->check_host_ip = 1;
700 if (options->strict_host_key_checking == -1)
701 options->strict_host_key_checking = 2; /* 2 is default */
702 if (options->compression == -1)
703 options->compression = 0;
704 if (options->keepalives == -1)
705 options->keepalives = 1;
706 if (options->compression_level == -1)
707 options->compression_level = 6;
708 if (options->port == -1)
709 options->port = 0; /* Filled in ssh_connect. */
710 if (options->connection_attempts == -1)
711 options->connection_attempts = 4;
712 if (options->number_of_password_prompts == -1)
713 options->number_of_password_prompts = 3;
714 /* Selected in ssh_login(). */
715 if (options->cipher == -1)
716 options->cipher = SSH_CIPHER_NOT_SET;
Damien Miller78928792000-04-12 20:17:38 +1000717 if (options->protocol == SSH_PROTO_UNKNOWN)
718 options->protocol = SSH_PROTO_1;
Damien Miller95def091999-11-25 00:26:21 +1100719 if (options->num_identity_files == 0) {
720 options->identity_files[0] =
721 xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
722 sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
723 options->num_identity_files = 1;
724 }
725 if (options->escape_char == -1)
726 options->escape_char = '~';
727 if (options->system_hostfile == NULL)
728 options->system_hostfile = SSH_SYSTEM_HOSTFILE;
729 if (options->user_hostfile == NULL)
730 options->user_hostfile = SSH_USER_HOSTFILE;
731 if (options->log_level == (LogLevel) - 1)
732 options->log_level = SYSLOG_LEVEL_INFO;
733 /* options->proxy_command should not be set by default */
734 /* options->user will be set in the main program if appropriate */
735 /* options->hostname will be set in the main program if appropriate */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000736}