blob: 529f8039b3ba020fa71052eb77ea07a0f0086b23 [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 Millereba71ba2000-04-29 23:57:08 +100017RCSID("$Id: readconf.c,v 1.12 2000/04/29 13:57:11 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 Millereba71ba2000-04-29 23:57:08 +1000107 oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oIdentityFile2,
108 oGlobalKnownHostsFile2, oUserKnownHostsFile2
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000109} OpCodes;
110
111/* Textual representations of the tokens. */
112
Damien Miller95def091999-11-25 00:26:21 +1100113static struct {
114 const char *name;
115 OpCodes opcode;
116} keywords[] = {
117 { "forwardagent", oForwardAgent },
118 { "forwardx11", oForwardX11 },
119 { "gatewayports", oGatewayPorts },
120 { "useprivilegedport", oUsePrivilegedPort },
121 { "rhostsauthentication", oRhostsAuthentication },
122 { "passwordauthentication", oPasswordAuthentication },
123 { "rsaauthentication", oRSAAuthentication },
124 { "skeyauthentication", oSkeyAuthentication },
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000125#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100126 { "kerberosauthentication", oKerberosAuthentication },
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000127#endif /* KRB4 */
128#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100129 { "kerberostgtpassing", oKerberosTgtPassing },
130 { "afstokenpassing", oAFSTokenPassing },
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000131#endif
Damien Miller95def091999-11-25 00:26:21 +1100132 { "fallbacktorsh", oFallBackToRsh },
133 { "usersh", oUseRsh },
134 { "identityfile", oIdentityFile },
Damien Millereba71ba2000-04-29 23:57:08 +1000135 { "identityfile2", oIdentityFile2 },
Damien Miller95def091999-11-25 00:26:21 +1100136 { "hostname", oHostName },
137 { "proxycommand", oProxyCommand },
138 { "port", oPort },
139 { "cipher", oCipher },
Damien Miller78928792000-04-12 20:17:38 +1000140 { "ciphers", oCiphers },
141 { "protocol", oProtocol },
Damien Miller95def091999-11-25 00:26:21 +1100142 { "remoteforward", oRemoteForward },
143 { "localforward", oLocalForward },
144 { "user", oUser },
145 { "host", oHost },
146 { "escapechar", oEscapeChar },
147 { "rhostsrsaauthentication", oRhostsRSAAuthentication },
148 { "globalknownhostsfile", oGlobalKnownHostsFile },
149 { "userknownhostsfile", oUserKnownHostsFile },
Damien Millereba71ba2000-04-29 23:57:08 +1000150 { "globalknownhostsfile2", oGlobalKnownHostsFile2 },
151 { "userknownhostsfile2", oUserKnownHostsFile2 },
Damien Miller95def091999-11-25 00:26:21 +1100152 { "connectionattempts", oConnectionAttempts },
153 { "batchmode", oBatchMode },
154 { "checkhostip", oCheckHostIP },
155 { "stricthostkeychecking", oStrictHostKeyChecking },
156 { "compression", oCompression },
157 { "compressionlevel", oCompressionLevel },
158 { "keepalive", oKeepAlives },
159 { "numberofpasswordprompts", oNumberOfPasswordPrompts },
160 { "tisauthentication", oTISAuthentication },
161 { "loglevel", oLogLevel },
162 { NULL, 0 }
Damien Miller5ce662a1999-11-11 17:57:39 +1100163};
164
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000165/* Characters considered whitespace in strtok calls. */
166#define WHITESPACE " \t\r\n"
167
168
Damien Miller5428f641999-11-25 11:54:57 +1100169/*
170 * Adds a local TCP/IP port forward to options. Never returns if there is an
171 * error.
172 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000173
Damien Miller4af51302000-04-16 11:18:38 +1000174void
Damien Milleraae6c611999-12-06 11:47:28 +1100175add_local_forward(Options *options, u_short port, const char *host,
176 u_short host_port)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000177{
Damien Miller95def091999-11-25 00:26:21 +1100178 Forward *fwd;
179 extern uid_t original_real_uid;
Damien Miller95def091999-11-25 00:26:21 +1100180 if (port < IPPORT_RESERVED && original_real_uid != 0)
181 fatal("Privileged ports can only be forwarded by root.\n");
182 if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
183 fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
184 fwd = &options->local_forwards[options->num_local_forwards++];
185 fwd->port = port;
186 fwd->host = xstrdup(host);
187 fwd->host_port = host_port;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000188}
189
Damien Miller5428f641999-11-25 11:54:57 +1100190/*
191 * Adds a remote TCP/IP port forward to options. Never returns if there is
192 * an error.
193 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000194
Damien Miller4af51302000-04-16 11:18:38 +1000195void
Damien Milleraae6c611999-12-06 11:47:28 +1100196add_remote_forward(Options *options, u_short port, const char *host,
197 u_short host_port)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000198{
Damien Miller95def091999-11-25 00:26:21 +1100199 Forward *fwd;
200 if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
201 fatal("Too many remote forwards (max %d).",
202 SSH_MAX_FORWARDS_PER_DIRECTION);
203 fwd = &options->remote_forwards[options->num_remote_forwards++];
204 fwd->port = port;
205 fwd->host = xstrdup(host);
206 fwd->host_port = host_port;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000207}
208
Damien Miller5428f641999-11-25 11:54:57 +1100209/*
210 * Returns the number of the token pointed to by cp of length len. Never
211 * returns if the token is not known.
212 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000213
Damien Miller4af51302000-04-16 11:18:38 +1000214static OpCodes
Damien Miller95def091999-11-25 00:26:21 +1100215parse_token(const char *cp, const char *filename, int linenum)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000216{
Damien Miller95def091999-11-25 00:26:21 +1100217 unsigned int i;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000218
Damien Miller95def091999-11-25 00:26:21 +1100219 for (i = 0; keywords[i].name; i++)
Damien Miller5428f641999-11-25 11:54:57 +1100220 if (strcasecmp(cp, keywords[i].name) == 0)
Damien Miller95def091999-11-25 00:26:21 +1100221 return keywords[i].opcode;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000222
Damien Miller95def091999-11-25 00:26:21 +1100223 fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
224 filename, linenum, cp);
225 return oBadOption;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000226}
227
Damien Miller5428f641999-11-25 11:54:57 +1100228/*
229 * Processes a single option line as used in the configuration files. This
230 * only sets those values that have not already been set.
231 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000232
Damien Miller2ccf6611999-11-15 15:25:10 +1100233int
234process_config_line(Options *options, const char *host,
Damien Miller95def091999-11-25 00:26:21 +1100235 char *line, const char *filename, int linenum,
236 int *activep)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000237{
Damien Miller5428f641999-11-25 11:54:57 +1100238 char buf[256], *cp, *string, **charptr, *cp2;
Damien Milleraae6c611999-12-06 11:47:28 +1100239 int opcode, *intptr, value;
240 u_short fwd_port, fwd_host_port;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000241
Damien Miller95def091999-11-25 00:26:21 +1100242 /* Skip leading whitespace. */
243 cp = line + strspn(line, WHITESPACE);
244 if (!*cp || *cp == '\n' || *cp == '#')
245 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000246
Damien Miller5428f641999-11-25 11:54:57 +1100247 /* Get the keyword. (Each line is supposed to begin with a keyword). */
Damien Miller95def091999-11-25 00:26:21 +1100248 cp = strtok(cp, WHITESPACE);
Damien Miller95def091999-11-25 00:26:21 +1100249 opcode = parse_token(cp, filename, linenum);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000250
Damien Miller95def091999-11-25 00:26:21 +1100251 switch (opcode) {
252 case oBadOption:
Damien Miller5428f641999-11-25 11:54:57 +1100253 /* don't panic, but count bad options */
254 return -1;
Damien Miller95def091999-11-25 00:26:21 +1100255 /* NOTREACHED */
256 case oForwardAgent:
257 intptr = &options->forward_agent;
258parse_flag:
259 cp = strtok(NULL, WHITESPACE);
260 if (!cp)
261 fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
262 value = 0; /* To avoid compiler warning... */
263 if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0)
264 value = 1;
265 else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0)
266 value = 0;
267 else
268 fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
269 if (*activep && *intptr == -1)
270 *intptr = value;
271 break;
272
273 case oForwardX11:
274 intptr = &options->forward_x11;
275 goto parse_flag;
276
277 case oGatewayPorts:
278 intptr = &options->gateway_ports;
279 goto parse_flag;
280
281 case oUsePrivilegedPort:
282 intptr = &options->use_privileged_port;
283 goto parse_flag;
284
285 case oRhostsAuthentication:
286 intptr = &options->rhosts_authentication;
287 goto parse_flag;
288
289 case oPasswordAuthentication:
290 intptr = &options->password_authentication;
291 goto parse_flag;
292
293 case oRSAAuthentication:
294 intptr = &options->rsa_authentication;
295 goto parse_flag;
296
297 case oRhostsRSAAuthentication:
298 intptr = &options->rhosts_rsa_authentication;
299 goto parse_flag;
300
301 case oTISAuthentication:
302 /* fallthrough, there is no difference on the client side */
303 case oSkeyAuthentication:
304 intptr = &options->skey_authentication;
305 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000306
307#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100308 case oKerberosAuthentication:
309 intptr = &options->kerberos_authentication;
310 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000311#endif /* KRB4 */
312
313#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100314 case oKerberosTgtPassing:
315 intptr = &options->kerberos_tgt_passing;
316 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000317
Damien Miller95def091999-11-25 00:26:21 +1100318 case oAFSTokenPassing:
319 intptr = &options->afs_token_passing;
320 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000321#endif
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000322
Damien Miller95def091999-11-25 00:26:21 +1100323 case oFallBackToRsh:
324 intptr = &options->fallback_to_rsh;
325 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000326
Damien Miller95def091999-11-25 00:26:21 +1100327 case oUseRsh:
328 intptr = &options->use_rsh;
329 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000330
Damien Miller95def091999-11-25 00:26:21 +1100331 case oBatchMode:
332 intptr = &options->batch_mode;
333 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000334
Damien Miller95def091999-11-25 00:26:21 +1100335 case oCheckHostIP:
336 intptr = &options->check_host_ip;
337 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000338
Damien Miller95def091999-11-25 00:26:21 +1100339 case oStrictHostKeyChecking:
340 intptr = &options->strict_host_key_checking;
341 cp = strtok(NULL, WHITESPACE);
342 if (!cp)
343 fatal("%.200s line %d: Missing yes/no argument.",
344 filename, linenum);
345 value = 0; /* To avoid compiler warning... */
346 if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0)
347 value = 1;
348 else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0)
349 value = 0;
350 else if (strcmp(cp, "ask") == 0)
351 value = 2;
352 else
353 fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
354 if (*activep && *intptr == -1)
355 *intptr = value;
356 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000357
Damien Miller95def091999-11-25 00:26:21 +1100358 case oCompression:
359 intptr = &options->compression;
360 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000361
Damien Miller95def091999-11-25 00:26:21 +1100362 case oKeepAlives:
363 intptr = &options->keepalives;
364 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000365
Damien Miller95def091999-11-25 00:26:21 +1100366 case oNumberOfPasswordPrompts:
367 intptr = &options->number_of_password_prompts;
368 goto parse_int;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000369
Damien Miller95def091999-11-25 00:26:21 +1100370 case oCompressionLevel:
371 intptr = &options->compression_level;
372 goto parse_int;
373
374 case oIdentityFile:
Damien Millereba71ba2000-04-29 23:57:08 +1000375 case oIdentityFile2:
Damien Miller95def091999-11-25 00:26:21 +1100376 cp = strtok(NULL, WHITESPACE);
377 if (!cp)
378 fatal("%.200s line %d: Missing argument.", filename, linenum);
379 if (*activep) {
Damien Millereba71ba2000-04-29 23:57:08 +1000380 intptr = (opcode == oIdentityFile) ?
381 &options->num_identity_files :
382 &options->num_identity_files2;
383 if (*intptr >= SSH_MAX_IDENTITY_FILES)
Damien Miller95def091999-11-25 00:26:21 +1100384 fatal("%.200s line %d: Too many identity files specified (max %d).",
385 filename, linenum, SSH_MAX_IDENTITY_FILES);
Damien Millereba71ba2000-04-29 23:57:08 +1000386 charptr = (opcode == oIdentityFile) ?
387 &options->identity_files[*intptr] :
388 &options->identity_files2[*intptr];
389 *charptr = xstrdup(cp);
390 *intptr = *intptr + 1;
Damien Miller95def091999-11-25 00:26:21 +1100391 }
392 break;
393
394 case oUser:
395 charptr = &options->user;
396parse_string:
397 cp = strtok(NULL, WHITESPACE);
398 if (!cp)
399 fatal("%.200s line %d: Missing argument.", filename, linenum);
400 if (*activep && *charptr == NULL)
401 *charptr = xstrdup(cp);
402 break;
403
404 case oGlobalKnownHostsFile:
405 charptr = &options->system_hostfile;
406 goto parse_string;
407
408 case oUserKnownHostsFile:
409 charptr = &options->user_hostfile;
410 goto parse_string;
411
Damien Millereba71ba2000-04-29 23:57:08 +1000412 case oGlobalKnownHostsFile2:
413 charptr = &options->system_hostfile2;
414 goto parse_string;
415
416 case oUserKnownHostsFile2:
417 charptr = &options->user_hostfile2;
418 goto parse_string;
419
Damien Miller95def091999-11-25 00:26:21 +1100420 case oHostName:
421 charptr = &options->hostname;
422 goto parse_string;
423
424 case oProxyCommand:
425 charptr = &options->proxy_command;
426 string = xstrdup("");
427 while ((cp = strtok(NULL, WHITESPACE)) != NULL) {
428 string = xrealloc(string, strlen(string) + strlen(cp) + 2);
429 strcat(string, " ");
430 strcat(string, cp);
431 }
432 if (*activep && *charptr == NULL)
433 *charptr = string;
434 else
435 xfree(string);
436 return 0;
437
438 case oPort:
439 intptr = &options->port;
440parse_int:
441 cp = strtok(NULL, WHITESPACE);
442 if (!cp)
443 fatal("%.200s line %d: Missing argument.", filename, linenum);
444 if (cp[0] < '0' || cp[0] > '9')
445 fatal("%.200s line %d: Bad number.", filename, linenum);
Damien Miller5428f641999-11-25 11:54:57 +1100446
447 /* Octal, decimal, or hex format? */
448 value = strtol(cp, &cp2, 0);
449 if (cp == cp2)
450 fatal("%.200s line %d: Bad number.", filename, linenum);
Damien Miller95def091999-11-25 00:26:21 +1100451 if (*activep && *intptr == -1)
452 *intptr = value;
453 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000454
Damien Miller95def091999-11-25 00:26:21 +1100455 case oConnectionAttempts:
456 intptr = &options->connection_attempts;
457 goto parse_int;
Damien Miller5ce662a1999-11-11 17:57:39 +1100458
Damien Miller95def091999-11-25 00:26:21 +1100459 case oCipher:
460 intptr = &options->cipher;
461 cp = strtok(NULL, WHITESPACE);
462 value = cipher_number(cp);
463 if (value == -1)
464 fatal("%.200s line %d: Bad cipher '%s'.",
465 filename, linenum, cp ? cp : "<NONE>");
466 if (*activep && *intptr == -1)
467 *intptr = value;
468 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000469
Damien Miller78928792000-04-12 20:17:38 +1000470 case oCiphers:
471 cp = strtok(NULL, WHITESPACE);
472 if (!ciphers_valid(cp))
473 fatal("%.200s line %d: Bad cipher spec '%s'.",
474 filename, linenum, cp ? cp : "<NONE>");
475 if (*activep && options->ciphers == NULL)
476 options->ciphers = xstrdup(cp);
477 break;
478
479 case oProtocol:
480 intptr = &options->protocol;
481 cp = strtok(NULL, WHITESPACE);
482 value = proto_spec(cp);
483 if (value == SSH_PROTO_UNKNOWN)
484 fatal("%.200s line %d: Bad protocol spec '%s'.",
485 filename, linenum, cp ? cp : "<NONE>");
486 if (*activep && *intptr == SSH_PROTO_UNKNOWN)
487 *intptr = value;
488 break;
489
Damien Miller95def091999-11-25 00:26:21 +1100490 case oLogLevel:
491 intptr = (int *) &options->log_level;
492 cp = strtok(NULL, WHITESPACE);
493 value = log_level_number(cp);
494 if (value == (LogLevel) - 1)
495 fatal("%.200s line %d: unsupported log level '%s'\n",
496 filename, linenum, cp ? cp : "<NONE>");
497 if (*activep && (LogLevel) * intptr == -1)
498 *intptr = (LogLevel) value;
499 break;
500
501 case oRemoteForward:
502 cp = strtok(NULL, WHITESPACE);
503 if (!cp)
504 fatal("%.200s line %d: Missing argument.", filename, linenum);
505 if (cp[0] < '0' || cp[0] > '9')
506 fatal("%.200s line %d: Badly formatted port number.",
507 filename, linenum);
508 fwd_port = atoi(cp);
509 cp = strtok(NULL, WHITESPACE);
510 if (!cp)
511 fatal("%.200s line %d: Missing second argument.",
512 filename, linenum);
Damien Milleraae6c611999-12-06 11:47:28 +1100513 if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
Damien Miller95def091999-11-25 00:26:21 +1100514 fatal("%.200s line %d: Badly formatted host:port.",
515 filename, linenum);
516 if (*activep)
517 add_remote_forward(options, fwd_port, buf, fwd_host_port);
518 break;
519
520 case oLocalForward:
521 cp = strtok(NULL, WHITESPACE);
522 if (!cp)
523 fatal("%.200s line %d: Missing argument.", filename, linenum);
524 if (cp[0] < '0' || cp[0] > '9')
525 fatal("%.200s line %d: Badly formatted port number.",
526 filename, linenum);
527 fwd_port = atoi(cp);
528 cp = strtok(NULL, WHITESPACE);
529 if (!cp)
530 fatal("%.200s line %d: Missing second argument.",
531 filename, linenum);
Damien Milleraae6c611999-12-06 11:47:28 +1100532 if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
Damien Miller95def091999-11-25 00:26:21 +1100533 fatal("%.200s line %d: Badly formatted host:port.",
534 filename, linenum);
535 if (*activep)
536 add_local_forward(options, fwd_port, buf, fwd_host_port);
537 break;
538
539 case oHost:
540 *activep = 0;
541 while ((cp = strtok(NULL, WHITESPACE)) != NULL)
542 if (match_pattern(host, cp)) {
543 debug("Applying options for %.100s", cp);
544 *activep = 1;
545 break;
546 }
Damien Miller5428f641999-11-25 11:54:57 +1100547 /* Avoid garbage check below, as strtok already returned NULL. */
Damien Miller95def091999-11-25 00:26:21 +1100548 return 0;
549
550 case oEscapeChar:
551 intptr = &options->escape_char;
552 cp = strtok(NULL, WHITESPACE);
553 if (!cp)
554 fatal("%.200s line %d: Missing argument.", filename, linenum);
555 if (cp[0] == '^' && cp[2] == 0 &&
556 (unsigned char) cp[1] >= 64 && (unsigned char) cp[1] < 128)
557 value = (unsigned char) cp[1] & 31;
558 else if (strlen(cp) == 1)
559 value = (unsigned char) cp[0];
560 else if (strcmp(cp, "none") == 0)
561 value = -2;
562 else {
563 fatal("%.200s line %d: Bad escape character.",
564 filename, linenum);
565 /* NOTREACHED */
566 value = 0; /* Avoid compiler warning. */
567 }
568 if (*activep && *intptr == -1)
569 *intptr = value;
570 break;
571
572 default:
573 fatal("process_config_line: Unimplemented opcode %d", opcode);
574 }
575
576 /* Check that there is no garbage at end of line. */
577 if (strtok(NULL, WHITESPACE) != NULL)
578 fatal("%.200s line %d: garbage at end of line.",
579 filename, linenum);
580 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000581}
582
583
Damien Miller5428f641999-11-25 11:54:57 +1100584/*
585 * Reads the config file and modifies the options accordingly. Options
586 * should already be initialized before this call. This never returns if
587 * there is an error. If the file does not exist, this returns immediately.
588 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000589
Damien Miller4af51302000-04-16 11:18:38 +1000590void
Damien Miller95def091999-11-25 00:26:21 +1100591read_config_file(const char *filename, const char *host, Options *options)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000592{
Damien Miller95def091999-11-25 00:26:21 +1100593 FILE *f;
594 char line[1024];
595 int active, linenum;
596 int bad_options = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000597
Damien Miller95def091999-11-25 00:26:21 +1100598 /* Open the file. */
599 f = fopen(filename, "r");
600 if (!f)
601 return;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000602
Damien Miller95def091999-11-25 00:26:21 +1100603 debug("Reading configuration data %.200s", filename);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000604
Damien Miller5428f641999-11-25 11:54:57 +1100605 /*
606 * Mark that we are now processing the options. This flag is turned
607 * on/off by Host specifications.
608 */
Damien Miller95def091999-11-25 00:26:21 +1100609 active = 1;
610 linenum = 0;
611 while (fgets(line, sizeof(line), f)) {
612 /* Update line number counter. */
613 linenum++;
614 if (process_config_line(options, host, line, filename, linenum, &active) != 0)
615 bad_options++;
616 }
617 fclose(f);
618 if (bad_options > 0)
619 fatal("%s: terminating, %d bad configuration options\n",
620 filename, bad_options);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000621}
622
Damien Miller5428f641999-11-25 11:54:57 +1100623/*
624 * Initializes options to special values that indicate that they have not yet
625 * been set. Read_config_file will only set options with this value. Options
626 * are processed in the following order: command line, user config file,
627 * system config file. Last, fill_default_options is called.
628 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000629
Damien Miller4af51302000-04-16 11:18:38 +1000630void
Damien Miller95def091999-11-25 00:26:21 +1100631initialize_options(Options * options)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000632{
Damien Miller95def091999-11-25 00:26:21 +1100633 memset(options, 'X', sizeof(*options));
634 options->forward_agent = -1;
635 options->forward_x11 = -1;
636 options->gateway_ports = -1;
637 options->use_privileged_port = -1;
638 options->rhosts_authentication = -1;
639 options->rsa_authentication = -1;
640 options->skey_authentication = -1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000641#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100642 options->kerberos_authentication = -1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000643#endif
644#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100645 options->kerberos_tgt_passing = -1;
646 options->afs_token_passing = -1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000647#endif
Damien Miller95def091999-11-25 00:26:21 +1100648 options->password_authentication = -1;
649 options->rhosts_rsa_authentication = -1;
650 options->fallback_to_rsh = -1;
651 options->use_rsh = -1;
652 options->batch_mode = -1;
653 options->check_host_ip = -1;
654 options->strict_host_key_checking = -1;
655 options->compression = -1;
656 options->keepalives = -1;
657 options->compression_level = -1;
658 options->port = -1;
659 options->connection_attempts = -1;
660 options->number_of_password_prompts = -1;
661 options->cipher = -1;
Damien Miller78928792000-04-12 20:17:38 +1000662 options->ciphers = NULL;
663 options->protocol = SSH_PROTO_UNKNOWN;
Damien Miller95def091999-11-25 00:26:21 +1100664 options->num_identity_files = 0;
Damien Millereba71ba2000-04-29 23:57:08 +1000665 options->num_identity_files2 = 0;
Damien Miller95def091999-11-25 00:26:21 +1100666 options->hostname = NULL;
667 options->proxy_command = NULL;
668 options->user = NULL;
669 options->escape_char = -1;
670 options->system_hostfile = NULL;
671 options->user_hostfile = NULL;
Damien Millereba71ba2000-04-29 23:57:08 +1000672 options->system_hostfile2 = NULL;
673 options->user_hostfile2 = NULL;
Damien Miller95def091999-11-25 00:26:21 +1100674 options->num_local_forwards = 0;
675 options->num_remote_forwards = 0;
676 options->log_level = (LogLevel) - 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000677}
678
Damien Miller5428f641999-11-25 11:54:57 +1100679/*
680 * Called after processing other sources of option data, this fills those
681 * options for which no value has been specified with their default values.
682 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000683
Damien Miller4af51302000-04-16 11:18:38 +1000684void
Damien Miller95def091999-11-25 00:26:21 +1100685fill_default_options(Options * options)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000686{
Damien Miller95def091999-11-25 00:26:21 +1100687 if (options->forward_agent == -1)
688 options->forward_agent = 1;
689 if (options->forward_x11 == -1)
Damien Miller98c7ad62000-03-09 21:27:49 +1100690 options->forward_x11 = 0;
Damien Miller95def091999-11-25 00:26:21 +1100691 if (options->gateway_ports == -1)
692 options->gateway_ports = 0;
693 if (options->use_privileged_port == -1)
694 options->use_privileged_port = 1;
695 if (options->rhosts_authentication == -1)
696 options->rhosts_authentication = 1;
697 if (options->rsa_authentication == -1)
698 options->rsa_authentication = 1;
699 if (options->skey_authentication == -1)
700 options->skey_authentication = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000701#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100702 if (options->kerberos_authentication == -1)
703 options->kerberos_authentication = 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000704#endif /* KRB4 */
705#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100706 if (options->kerberos_tgt_passing == -1)
707 options->kerberos_tgt_passing = 1;
708 if (options->afs_token_passing == -1)
709 options->afs_token_passing = 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000710#endif /* AFS */
Damien Miller95def091999-11-25 00:26:21 +1100711 if (options->password_authentication == -1)
712 options->password_authentication = 1;
713 if (options->rhosts_rsa_authentication == -1)
714 options->rhosts_rsa_authentication = 1;
715 if (options->fallback_to_rsh == -1)
716 options->fallback_to_rsh = 1;
717 if (options->use_rsh == -1)
718 options->use_rsh = 0;
719 if (options->batch_mode == -1)
720 options->batch_mode = 0;
721 if (options->check_host_ip == -1)
722 options->check_host_ip = 1;
723 if (options->strict_host_key_checking == -1)
724 options->strict_host_key_checking = 2; /* 2 is default */
725 if (options->compression == -1)
726 options->compression = 0;
727 if (options->keepalives == -1)
728 options->keepalives = 1;
729 if (options->compression_level == -1)
730 options->compression_level = 6;
731 if (options->port == -1)
732 options->port = 0; /* Filled in ssh_connect. */
733 if (options->connection_attempts == -1)
734 options->connection_attempts = 4;
735 if (options->number_of_password_prompts == -1)
736 options->number_of_password_prompts = 3;
737 /* Selected in ssh_login(). */
738 if (options->cipher == -1)
739 options->cipher = SSH_CIPHER_NOT_SET;
Damien Miller78928792000-04-12 20:17:38 +1000740 if (options->protocol == SSH_PROTO_UNKNOWN)
Damien Millereba71ba2000-04-29 23:57:08 +1000741 options->protocol = SSH_PROTO_1|SSH_PROTO_2|SSH_PROTO_1_PREFERRED;
Damien Miller95def091999-11-25 00:26:21 +1100742 if (options->num_identity_files == 0) {
743 options->identity_files[0] =
744 xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
745 sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
746 options->num_identity_files = 1;
747 }
Damien Millereba71ba2000-04-29 23:57:08 +1000748#if 0
749 if (options->num_identity_files2 == 0) {
750 options->identity_files2[0] =
751 xmalloc(2 + strlen(SSH2_CLIENT_IDENTITY) + 1);
752 sprintf(options->identity_files2[0], "~/%.100s", SSH2_CLIENT_IDENTITY);
753 options->num_identity_files2 = 1;
754 }
755#endif
Damien Miller95def091999-11-25 00:26:21 +1100756 if (options->escape_char == -1)
757 options->escape_char = '~';
758 if (options->system_hostfile == NULL)
759 options->system_hostfile = SSH_SYSTEM_HOSTFILE;
760 if (options->user_hostfile == NULL)
761 options->user_hostfile = SSH_USER_HOSTFILE;
Damien Millereba71ba2000-04-29 23:57:08 +1000762 if (options->system_hostfile2 == NULL)
763 options->system_hostfile2 = SSH_SYSTEM_HOSTFILE2;
764 if (options->user_hostfile2 == NULL)
765 options->user_hostfile2 = SSH_USER_HOSTFILE2;
Damien Miller95def091999-11-25 00:26:21 +1100766 if (options->log_level == (LogLevel) - 1)
767 options->log_level = SYSLOG_LEVEL_INFO;
768 /* options->proxy_command should not be set by default */
769 /* options->user will be set in the main program if appropriate */
770 /* options->hostname will be set in the main program if appropriate */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000771}