blob: d7011d7f78b587e93a12e2d63007247ec15a549e [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 Millerb1715dc2000-05-30 13:44:51 +100017RCSID("$Id: readconf.c,v 1.15 2000/05/30 03:44:53 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,
Damien Millere247cc42000-05-07 12:03:14 +1000108 oGlobalKnownHostsFile2, oUserKnownHostsFile2, oDSAAuthentication
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 },
Damien Millere247cc42000-05-07 12:03:14 +1000124 { "dsaauthentication", oDSAAuthentication },
Damien Miller95def091999-11-25 00:26:21 +1100125 { "skeyauthentication", oSkeyAuthentication },
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000126#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100127 { "kerberosauthentication", oKerberosAuthentication },
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000128#endif /* KRB4 */
129#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100130 { "kerberostgtpassing", oKerberosTgtPassing },
131 { "afstokenpassing", oAFSTokenPassing },
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000132#endif
Damien Miller95def091999-11-25 00:26:21 +1100133 { "fallbacktorsh", oFallBackToRsh },
134 { "usersh", oUseRsh },
135 { "identityfile", oIdentityFile },
Damien Millereba71ba2000-04-29 23:57:08 +1000136 { "identityfile2", oIdentityFile2 },
Damien Miller95def091999-11-25 00:26:21 +1100137 { "hostname", oHostName },
138 { "proxycommand", oProxyCommand },
139 { "port", oPort },
140 { "cipher", oCipher },
Damien Miller78928792000-04-12 20:17:38 +1000141 { "ciphers", oCiphers },
142 { "protocol", oProtocol },
Damien Miller95def091999-11-25 00:26:21 +1100143 { "remoteforward", oRemoteForward },
144 { "localforward", oLocalForward },
145 { "user", oUser },
146 { "host", oHost },
147 { "escapechar", oEscapeChar },
148 { "rhostsrsaauthentication", oRhostsRSAAuthentication },
149 { "globalknownhostsfile", oGlobalKnownHostsFile },
150 { "userknownhostsfile", oUserKnownHostsFile },
Damien Millereba71ba2000-04-29 23:57:08 +1000151 { "globalknownhostsfile2", oGlobalKnownHostsFile2 },
152 { "userknownhostsfile2", oUserKnownHostsFile2 },
Damien Miller95def091999-11-25 00:26:21 +1100153 { "connectionattempts", oConnectionAttempts },
154 { "batchmode", oBatchMode },
155 { "checkhostip", oCheckHostIP },
156 { "stricthostkeychecking", oStrictHostKeyChecking },
157 { "compression", oCompression },
158 { "compressionlevel", oCompressionLevel },
159 { "keepalive", oKeepAlives },
160 { "numberofpasswordprompts", oNumberOfPasswordPrompts },
161 { "tisauthentication", oTISAuthentication },
162 { "loglevel", oLogLevel },
163 { NULL, 0 }
Damien Miller5ce662a1999-11-11 17:57:39 +1100164};
165
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000166/* Characters considered whitespace in strtok calls. */
167#define WHITESPACE " \t\r\n"
168
169
Damien Miller5428f641999-11-25 11:54:57 +1100170/*
171 * Adds a local TCP/IP port forward to options. Never returns if there is an
172 * error.
173 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000174
Damien Miller4af51302000-04-16 11:18:38 +1000175void
Damien Milleraae6c611999-12-06 11:47:28 +1100176add_local_forward(Options *options, u_short port, const char *host,
177 u_short host_port)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000178{
Damien Miller95def091999-11-25 00:26:21 +1100179 Forward *fwd;
180 extern uid_t original_real_uid;
Damien Miller95def091999-11-25 00:26:21 +1100181 if (port < IPPORT_RESERVED && original_real_uid != 0)
182 fatal("Privileged ports can only be forwarded by root.\n");
183 if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
184 fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
185 fwd = &options->local_forwards[options->num_local_forwards++];
186 fwd->port = port;
187 fwd->host = xstrdup(host);
188 fwd->host_port = host_port;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000189}
190
Damien Miller5428f641999-11-25 11:54:57 +1100191/*
192 * Adds a remote TCP/IP port forward to options. Never returns if there is
193 * an error.
194 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000195
Damien Miller4af51302000-04-16 11:18:38 +1000196void
Damien Milleraae6c611999-12-06 11:47:28 +1100197add_remote_forward(Options *options, u_short port, const char *host,
198 u_short host_port)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000199{
Damien Miller95def091999-11-25 00:26:21 +1100200 Forward *fwd;
201 if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
202 fatal("Too many remote forwards (max %d).",
203 SSH_MAX_FORWARDS_PER_DIRECTION);
204 fwd = &options->remote_forwards[options->num_remote_forwards++];
205 fwd->port = port;
206 fwd->host = xstrdup(host);
207 fwd->host_port = host_port;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000208}
209
Damien Miller5428f641999-11-25 11:54:57 +1100210/*
211 * Returns the number of the token pointed to by cp of length len. Never
212 * returns if the token is not known.
213 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000214
Damien Miller4af51302000-04-16 11:18:38 +1000215static OpCodes
Damien Miller95def091999-11-25 00:26:21 +1100216parse_token(const char *cp, const char *filename, int linenum)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000217{
Damien Miller95def091999-11-25 00:26:21 +1100218 unsigned int i;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000219
Damien Miller95def091999-11-25 00:26:21 +1100220 for (i = 0; keywords[i].name; i++)
Damien Miller5428f641999-11-25 11:54:57 +1100221 if (strcasecmp(cp, keywords[i].name) == 0)
Damien Miller95def091999-11-25 00:26:21 +1100222 return keywords[i].opcode;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000223
Damien Miller95def091999-11-25 00:26:21 +1100224 fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
225 filename, linenum, cp);
226 return oBadOption;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000227}
228
Damien Miller5428f641999-11-25 11:54:57 +1100229/*
230 * Processes a single option line as used in the configuration files. This
231 * only sets those values that have not already been set.
232 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000233
Damien Miller2ccf6611999-11-15 15:25:10 +1100234int
235process_config_line(Options *options, const char *host,
Damien Miller95def091999-11-25 00:26:21 +1100236 char *line, const char *filename, int linenum,
237 int *activep)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000238{
Damien Miller5428f641999-11-25 11:54:57 +1100239 char buf[256], *cp, *string, **charptr, *cp2;
Damien Milleraae6c611999-12-06 11:47:28 +1100240 int opcode, *intptr, value;
241 u_short fwd_port, fwd_host_port;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000242
Damien Miller95def091999-11-25 00:26:21 +1100243 /* Skip leading whitespace. */
244 cp = line + strspn(line, WHITESPACE);
245 if (!*cp || *cp == '\n' || *cp == '#')
246 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000247
Damien Miller5428f641999-11-25 11:54:57 +1100248 /* Get the keyword. (Each line is supposed to begin with a keyword). */
Damien Miller95def091999-11-25 00:26:21 +1100249 cp = strtok(cp, WHITESPACE);
Damien Miller95def091999-11-25 00:26:21 +1100250 opcode = parse_token(cp, filename, linenum);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000251
Damien Miller95def091999-11-25 00:26:21 +1100252 switch (opcode) {
253 case oBadOption:
Damien Miller5428f641999-11-25 11:54:57 +1100254 /* don't panic, but count bad options */
255 return -1;
Damien Miller95def091999-11-25 00:26:21 +1100256 /* NOTREACHED */
257 case oForwardAgent:
258 intptr = &options->forward_agent;
259parse_flag:
260 cp = strtok(NULL, WHITESPACE);
261 if (!cp)
262 fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
263 value = 0; /* To avoid compiler warning... */
264 if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0)
265 value = 1;
266 else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0)
267 value = 0;
268 else
269 fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
270 if (*activep && *intptr == -1)
271 *intptr = value;
272 break;
273
274 case oForwardX11:
275 intptr = &options->forward_x11;
276 goto parse_flag;
277
278 case oGatewayPorts:
279 intptr = &options->gateway_ports;
280 goto parse_flag;
281
282 case oUsePrivilegedPort:
283 intptr = &options->use_privileged_port;
284 goto parse_flag;
285
286 case oRhostsAuthentication:
287 intptr = &options->rhosts_authentication;
288 goto parse_flag;
289
290 case oPasswordAuthentication:
291 intptr = &options->password_authentication;
292 goto parse_flag;
293
Damien Millere247cc42000-05-07 12:03:14 +1000294 case oDSAAuthentication:
295 intptr = &options->dsa_authentication;
296 goto parse_flag;
297
Damien Miller95def091999-11-25 00:26:21 +1100298 case oRSAAuthentication:
299 intptr = &options->rsa_authentication;
300 goto parse_flag;
301
302 case oRhostsRSAAuthentication:
303 intptr = &options->rhosts_rsa_authentication;
304 goto parse_flag;
305
306 case oTISAuthentication:
307 /* fallthrough, there is no difference on the client side */
308 case oSkeyAuthentication:
309 intptr = &options->skey_authentication;
310 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000311
312#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100313 case oKerberosAuthentication:
314 intptr = &options->kerberos_authentication;
315 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000316#endif /* KRB4 */
317
318#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100319 case oKerberosTgtPassing:
320 intptr = &options->kerberos_tgt_passing;
321 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000322
Damien Miller95def091999-11-25 00:26:21 +1100323 case oAFSTokenPassing:
324 intptr = &options->afs_token_passing;
325 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000326#endif
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000327
Damien Miller95def091999-11-25 00:26:21 +1100328 case oFallBackToRsh:
329 intptr = &options->fallback_to_rsh;
330 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000331
Damien Miller95def091999-11-25 00:26:21 +1100332 case oUseRsh:
333 intptr = &options->use_rsh;
334 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000335
Damien Miller95def091999-11-25 00:26:21 +1100336 case oBatchMode:
337 intptr = &options->batch_mode;
338 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000339
Damien Miller95def091999-11-25 00:26:21 +1100340 case oCheckHostIP:
341 intptr = &options->check_host_ip;
342 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000343
Damien Miller95def091999-11-25 00:26:21 +1100344 case oStrictHostKeyChecking:
345 intptr = &options->strict_host_key_checking;
346 cp = strtok(NULL, WHITESPACE);
347 if (!cp)
348 fatal("%.200s line %d: Missing yes/no argument.",
349 filename, linenum);
350 value = 0; /* To avoid compiler warning... */
351 if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0)
352 value = 1;
353 else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0)
354 value = 0;
355 else if (strcmp(cp, "ask") == 0)
356 value = 2;
357 else
358 fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
359 if (*activep && *intptr == -1)
360 *intptr = value;
361 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000362
Damien Miller95def091999-11-25 00:26:21 +1100363 case oCompression:
364 intptr = &options->compression;
365 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000366
Damien Miller95def091999-11-25 00:26:21 +1100367 case oKeepAlives:
368 intptr = &options->keepalives;
369 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000370
Damien Miller95def091999-11-25 00:26:21 +1100371 case oNumberOfPasswordPrompts:
372 intptr = &options->number_of_password_prompts;
373 goto parse_int;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000374
Damien Miller95def091999-11-25 00:26:21 +1100375 case oCompressionLevel:
376 intptr = &options->compression_level;
377 goto parse_int;
378
379 case oIdentityFile:
Damien Millereba71ba2000-04-29 23:57:08 +1000380 case oIdentityFile2:
Damien Miller95def091999-11-25 00:26:21 +1100381 cp = strtok(NULL, WHITESPACE);
382 if (!cp)
383 fatal("%.200s line %d: Missing argument.", filename, linenum);
384 if (*activep) {
Damien Millereba71ba2000-04-29 23:57:08 +1000385 intptr = (opcode == oIdentityFile) ?
386 &options->num_identity_files :
387 &options->num_identity_files2;
388 if (*intptr >= SSH_MAX_IDENTITY_FILES)
Damien Miller95def091999-11-25 00:26:21 +1100389 fatal("%.200s line %d: Too many identity files specified (max %d).",
390 filename, linenum, SSH_MAX_IDENTITY_FILES);
Damien Millereba71ba2000-04-29 23:57:08 +1000391 charptr = (opcode == oIdentityFile) ?
392 &options->identity_files[*intptr] :
393 &options->identity_files2[*intptr];
394 *charptr = xstrdup(cp);
395 *intptr = *intptr + 1;
Damien Miller95def091999-11-25 00:26:21 +1100396 }
397 break;
398
399 case oUser:
400 charptr = &options->user;
401parse_string:
402 cp = strtok(NULL, WHITESPACE);
403 if (!cp)
404 fatal("%.200s line %d: Missing argument.", filename, linenum);
405 if (*activep && *charptr == NULL)
406 *charptr = xstrdup(cp);
407 break;
408
409 case oGlobalKnownHostsFile:
410 charptr = &options->system_hostfile;
411 goto parse_string;
412
413 case oUserKnownHostsFile:
414 charptr = &options->user_hostfile;
415 goto parse_string;
416
Damien Millereba71ba2000-04-29 23:57:08 +1000417 case oGlobalKnownHostsFile2:
418 charptr = &options->system_hostfile2;
419 goto parse_string;
420
421 case oUserKnownHostsFile2:
422 charptr = &options->user_hostfile2;
423 goto parse_string;
424
Damien Miller95def091999-11-25 00:26:21 +1100425 case oHostName:
426 charptr = &options->hostname;
427 goto parse_string;
428
429 case oProxyCommand:
430 charptr = &options->proxy_command;
431 string = xstrdup("");
432 while ((cp = strtok(NULL, WHITESPACE)) != NULL) {
433 string = xrealloc(string, strlen(string) + strlen(cp) + 2);
434 strcat(string, " ");
435 strcat(string, cp);
436 }
437 if (*activep && *charptr == NULL)
438 *charptr = string;
439 else
440 xfree(string);
441 return 0;
442
443 case oPort:
444 intptr = &options->port;
445parse_int:
446 cp = strtok(NULL, WHITESPACE);
447 if (!cp)
448 fatal("%.200s line %d: Missing argument.", filename, linenum);
449 if (cp[0] < '0' || cp[0] > '9')
450 fatal("%.200s line %d: Bad number.", filename, linenum);
Damien Miller5428f641999-11-25 11:54:57 +1100451
452 /* Octal, decimal, or hex format? */
453 value = strtol(cp, &cp2, 0);
454 if (cp == cp2)
455 fatal("%.200s line %d: Bad number.", filename, linenum);
Damien Miller95def091999-11-25 00:26:21 +1100456 if (*activep && *intptr == -1)
457 *intptr = value;
458 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000459
Damien Miller95def091999-11-25 00:26:21 +1100460 case oConnectionAttempts:
461 intptr = &options->connection_attempts;
462 goto parse_int;
Damien Miller5ce662a1999-11-11 17:57:39 +1100463
Damien Miller95def091999-11-25 00:26:21 +1100464 case oCipher:
465 intptr = &options->cipher;
466 cp = strtok(NULL, WHITESPACE);
Damien Millerb1715dc2000-05-30 13:44:51 +1000467 if (!cp)
468 fatal("%.200s line %d: Missing argument.", filename, linenum);
Damien Miller95def091999-11-25 00:26:21 +1100469 value = cipher_number(cp);
470 if (value == -1)
471 fatal("%.200s line %d: Bad cipher '%s'.",
472 filename, linenum, cp ? cp : "<NONE>");
473 if (*activep && *intptr == -1)
474 *intptr = value;
475 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000476
Damien Miller78928792000-04-12 20:17:38 +1000477 case oCiphers:
478 cp = strtok(NULL, WHITESPACE);
Damien Millerb1715dc2000-05-30 13:44:51 +1000479 if (!cp)
480 fatal("%.200s line %d: Missing argument.", filename, linenum);
Damien Miller78928792000-04-12 20:17:38 +1000481 if (!ciphers_valid(cp))
Damien Miller30c3d422000-05-09 11:02:59 +1000482 fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
Damien Miller78928792000-04-12 20:17:38 +1000483 filename, linenum, cp ? cp : "<NONE>");
484 if (*activep && options->ciphers == NULL)
485 options->ciphers = xstrdup(cp);
486 break;
487
488 case oProtocol:
489 intptr = &options->protocol;
490 cp = strtok(NULL, WHITESPACE);
Damien Millerb1715dc2000-05-30 13:44:51 +1000491 if (!cp)
492 fatal("%.200s line %d: Missing argument.", filename, linenum);
Damien Miller78928792000-04-12 20:17:38 +1000493 value = proto_spec(cp);
494 if (value == SSH_PROTO_UNKNOWN)
495 fatal("%.200s line %d: Bad protocol spec '%s'.",
496 filename, linenum, cp ? cp : "<NONE>");
497 if (*activep && *intptr == SSH_PROTO_UNKNOWN)
498 *intptr = value;
499 break;
500
Damien Miller95def091999-11-25 00:26:21 +1100501 case oLogLevel:
502 intptr = (int *) &options->log_level;
503 cp = strtok(NULL, WHITESPACE);
504 value = log_level_number(cp);
505 if (value == (LogLevel) - 1)
506 fatal("%.200s line %d: unsupported log level '%s'\n",
507 filename, linenum, cp ? cp : "<NONE>");
508 if (*activep && (LogLevel) * intptr == -1)
509 *intptr = (LogLevel) value;
510 break;
511
512 case oRemoteForward:
513 cp = strtok(NULL, WHITESPACE);
514 if (!cp)
515 fatal("%.200s line %d: Missing argument.", filename, linenum);
516 if (cp[0] < '0' || cp[0] > '9')
517 fatal("%.200s line %d: Badly formatted port number.",
518 filename, linenum);
519 fwd_port = atoi(cp);
520 cp = strtok(NULL, WHITESPACE);
521 if (!cp)
522 fatal("%.200s line %d: Missing second argument.",
523 filename, linenum);
Damien Milleraae6c611999-12-06 11:47:28 +1100524 if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
Damien Miller95def091999-11-25 00:26:21 +1100525 fatal("%.200s line %d: Badly formatted host:port.",
526 filename, linenum);
527 if (*activep)
528 add_remote_forward(options, fwd_port, buf, fwd_host_port);
529 break;
530
531 case oLocalForward:
532 cp = strtok(NULL, WHITESPACE);
533 if (!cp)
534 fatal("%.200s line %d: Missing argument.", filename, linenum);
535 if (cp[0] < '0' || cp[0] > '9')
536 fatal("%.200s line %d: Badly formatted port number.",
537 filename, linenum);
538 fwd_port = atoi(cp);
539 cp = strtok(NULL, WHITESPACE);
540 if (!cp)
541 fatal("%.200s line %d: Missing second argument.",
542 filename, linenum);
Damien Milleraae6c611999-12-06 11:47:28 +1100543 if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
Damien Miller95def091999-11-25 00:26:21 +1100544 fatal("%.200s line %d: Badly formatted host:port.",
545 filename, linenum);
546 if (*activep)
547 add_local_forward(options, fwd_port, buf, fwd_host_port);
548 break;
549
550 case oHost:
551 *activep = 0;
552 while ((cp = strtok(NULL, WHITESPACE)) != NULL)
553 if (match_pattern(host, cp)) {
554 debug("Applying options for %.100s", cp);
555 *activep = 1;
556 break;
557 }
Damien Miller5428f641999-11-25 11:54:57 +1100558 /* Avoid garbage check below, as strtok already returned NULL. */
Damien Miller95def091999-11-25 00:26:21 +1100559 return 0;
560
561 case oEscapeChar:
562 intptr = &options->escape_char;
563 cp = strtok(NULL, WHITESPACE);
564 if (!cp)
565 fatal("%.200s line %d: Missing argument.", filename, linenum);
566 if (cp[0] == '^' && cp[2] == 0 &&
567 (unsigned char) cp[1] >= 64 && (unsigned char) cp[1] < 128)
568 value = (unsigned char) cp[1] & 31;
569 else if (strlen(cp) == 1)
570 value = (unsigned char) cp[0];
571 else if (strcmp(cp, "none") == 0)
572 value = -2;
573 else {
574 fatal("%.200s line %d: Bad escape character.",
575 filename, linenum);
576 /* NOTREACHED */
577 value = 0; /* Avoid compiler warning. */
578 }
579 if (*activep && *intptr == -1)
580 *intptr = value;
581 break;
582
583 default:
584 fatal("process_config_line: Unimplemented opcode %d", opcode);
585 }
586
587 /* Check that there is no garbage at end of line. */
588 if (strtok(NULL, WHITESPACE) != NULL)
589 fatal("%.200s line %d: garbage at end of line.",
590 filename, linenum);
591 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000592}
593
594
Damien Miller5428f641999-11-25 11:54:57 +1100595/*
596 * Reads the config file and modifies the options accordingly. Options
597 * should already be initialized before this call. This never returns if
598 * there is an error. If the file does not exist, this returns immediately.
599 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000600
Damien Miller4af51302000-04-16 11:18:38 +1000601void
Damien Miller95def091999-11-25 00:26:21 +1100602read_config_file(const char *filename, const char *host, Options *options)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000603{
Damien Miller95def091999-11-25 00:26:21 +1100604 FILE *f;
605 char line[1024];
606 int active, linenum;
607 int bad_options = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000608
Damien Miller95def091999-11-25 00:26:21 +1100609 /* Open the file. */
610 f = fopen(filename, "r");
611 if (!f)
612 return;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000613
Damien Miller95def091999-11-25 00:26:21 +1100614 debug("Reading configuration data %.200s", filename);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000615
Damien Miller5428f641999-11-25 11:54:57 +1100616 /*
617 * Mark that we are now processing the options. This flag is turned
618 * on/off by Host specifications.
619 */
Damien Miller95def091999-11-25 00:26:21 +1100620 active = 1;
621 linenum = 0;
622 while (fgets(line, sizeof(line), f)) {
623 /* Update line number counter. */
624 linenum++;
625 if (process_config_line(options, host, line, filename, linenum, &active) != 0)
626 bad_options++;
627 }
628 fclose(f);
629 if (bad_options > 0)
630 fatal("%s: terminating, %d bad configuration options\n",
631 filename, bad_options);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000632}
633
Damien Miller5428f641999-11-25 11:54:57 +1100634/*
635 * Initializes options to special values that indicate that they have not yet
636 * been set. Read_config_file will only set options with this value. Options
637 * are processed in the following order: command line, user config file,
638 * system config file. Last, fill_default_options is called.
639 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000640
Damien Miller4af51302000-04-16 11:18:38 +1000641void
Damien Miller95def091999-11-25 00:26:21 +1100642initialize_options(Options * options)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000643{
Damien Miller95def091999-11-25 00:26:21 +1100644 memset(options, 'X', sizeof(*options));
645 options->forward_agent = -1;
646 options->forward_x11 = -1;
647 options->gateway_ports = -1;
648 options->use_privileged_port = -1;
649 options->rhosts_authentication = -1;
650 options->rsa_authentication = -1;
Damien Millere247cc42000-05-07 12:03:14 +1000651 options->dsa_authentication = -1;
Damien Miller95def091999-11-25 00:26:21 +1100652 options->skey_authentication = -1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000653#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100654 options->kerberos_authentication = -1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000655#endif
656#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100657 options->kerberos_tgt_passing = -1;
658 options->afs_token_passing = -1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000659#endif
Damien Miller95def091999-11-25 00:26:21 +1100660 options->password_authentication = -1;
661 options->rhosts_rsa_authentication = -1;
662 options->fallback_to_rsh = -1;
663 options->use_rsh = -1;
664 options->batch_mode = -1;
665 options->check_host_ip = -1;
666 options->strict_host_key_checking = -1;
667 options->compression = -1;
668 options->keepalives = -1;
669 options->compression_level = -1;
670 options->port = -1;
671 options->connection_attempts = -1;
672 options->number_of_password_prompts = -1;
673 options->cipher = -1;
Damien Miller78928792000-04-12 20:17:38 +1000674 options->ciphers = NULL;
675 options->protocol = SSH_PROTO_UNKNOWN;
Damien Miller95def091999-11-25 00:26:21 +1100676 options->num_identity_files = 0;
Damien Millereba71ba2000-04-29 23:57:08 +1000677 options->num_identity_files2 = 0;
Damien Miller95def091999-11-25 00:26:21 +1100678 options->hostname = NULL;
679 options->proxy_command = NULL;
680 options->user = NULL;
681 options->escape_char = -1;
682 options->system_hostfile = NULL;
683 options->user_hostfile = NULL;
Damien Millereba71ba2000-04-29 23:57:08 +1000684 options->system_hostfile2 = NULL;
685 options->user_hostfile2 = NULL;
Damien Miller95def091999-11-25 00:26:21 +1100686 options->num_local_forwards = 0;
687 options->num_remote_forwards = 0;
688 options->log_level = (LogLevel) - 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000689}
690
Damien Miller5428f641999-11-25 11:54:57 +1100691/*
692 * Called after processing other sources of option data, this fills those
693 * options for which no value has been specified with their default values.
694 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000695
Damien Miller4af51302000-04-16 11:18:38 +1000696void
Damien Miller95def091999-11-25 00:26:21 +1100697fill_default_options(Options * options)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000698{
Damien Miller95def091999-11-25 00:26:21 +1100699 if (options->forward_agent == -1)
Damien Millerb1715dc2000-05-30 13:44:51 +1000700 options->forward_agent = 0;
Damien Miller95def091999-11-25 00:26:21 +1100701 if (options->forward_x11 == -1)
Damien Miller98c7ad62000-03-09 21:27:49 +1100702 options->forward_x11 = 0;
Damien Miller95def091999-11-25 00:26:21 +1100703 if (options->gateway_ports == -1)
704 options->gateway_ports = 0;
705 if (options->use_privileged_port == -1)
706 options->use_privileged_port = 1;
707 if (options->rhosts_authentication == -1)
708 options->rhosts_authentication = 1;
709 if (options->rsa_authentication == -1)
710 options->rsa_authentication = 1;
Damien Millere247cc42000-05-07 12:03:14 +1000711 if (options->dsa_authentication == -1)
712 options->dsa_authentication = 1;
Damien Miller95def091999-11-25 00:26:21 +1100713 if (options->skey_authentication == -1)
714 options->skey_authentication = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000715#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100716 if (options->kerberos_authentication == -1)
717 options->kerberos_authentication = 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000718#endif /* KRB4 */
719#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100720 if (options->kerberos_tgt_passing == -1)
721 options->kerberos_tgt_passing = 1;
722 if (options->afs_token_passing == -1)
723 options->afs_token_passing = 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000724#endif /* AFS */
Damien Miller95def091999-11-25 00:26:21 +1100725 if (options->password_authentication == -1)
726 options->password_authentication = 1;
727 if (options->rhosts_rsa_authentication == -1)
728 options->rhosts_rsa_authentication = 1;
729 if (options->fallback_to_rsh == -1)
730 options->fallback_to_rsh = 1;
731 if (options->use_rsh == -1)
732 options->use_rsh = 0;
733 if (options->batch_mode == -1)
734 options->batch_mode = 0;
735 if (options->check_host_ip == -1)
736 options->check_host_ip = 1;
737 if (options->strict_host_key_checking == -1)
738 options->strict_host_key_checking = 2; /* 2 is default */
739 if (options->compression == -1)
740 options->compression = 0;
741 if (options->keepalives == -1)
742 options->keepalives = 1;
743 if (options->compression_level == -1)
744 options->compression_level = 6;
745 if (options->port == -1)
746 options->port = 0; /* Filled in ssh_connect. */
747 if (options->connection_attempts == -1)
748 options->connection_attempts = 4;
749 if (options->number_of_password_prompts == -1)
750 options->number_of_password_prompts = 3;
751 /* Selected in ssh_login(). */
752 if (options->cipher == -1)
753 options->cipher = SSH_CIPHER_NOT_SET;
Damien Miller30c3d422000-05-09 11:02:59 +1000754 /* options->ciphers, default set in myproposals.h */
Damien Miller78928792000-04-12 20:17:38 +1000755 if (options->protocol == SSH_PROTO_UNKNOWN)
Damien Millereba71ba2000-04-29 23:57:08 +1000756 options->protocol = SSH_PROTO_1|SSH_PROTO_2|SSH_PROTO_1_PREFERRED;
Damien Miller95def091999-11-25 00:26:21 +1100757 if (options->num_identity_files == 0) {
758 options->identity_files[0] =
759 xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
760 sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
761 options->num_identity_files = 1;
762 }
Damien Millereba71ba2000-04-29 23:57:08 +1000763 if (options->num_identity_files2 == 0) {
764 options->identity_files2[0] =
Damien Millere247cc42000-05-07 12:03:14 +1000765 xmalloc(2 + strlen(SSH_CLIENT_ID_DSA) + 1);
766 sprintf(options->identity_files2[0], "~/%.100s", SSH_CLIENT_ID_DSA);
Damien Millereba71ba2000-04-29 23:57:08 +1000767 options->num_identity_files2 = 1;
768 }
Damien Miller95def091999-11-25 00:26:21 +1100769 if (options->escape_char == -1)
770 options->escape_char = '~';
771 if (options->system_hostfile == NULL)
772 options->system_hostfile = SSH_SYSTEM_HOSTFILE;
773 if (options->user_hostfile == NULL)
774 options->user_hostfile = SSH_USER_HOSTFILE;
Damien Millereba71ba2000-04-29 23:57:08 +1000775 if (options->system_hostfile2 == NULL)
776 options->system_hostfile2 = SSH_SYSTEM_HOSTFILE2;
777 if (options->user_hostfile2 == NULL)
778 options->user_hostfile2 = SSH_USER_HOSTFILE2;
Damien Miller95def091999-11-25 00:26:21 +1100779 if (options->log_level == (LogLevel) - 1)
780 options->log_level = SYSLOG_LEVEL_INFO;
781 /* options->proxy_command should not be set by default */
782 /* options->user will be set in the main program if appropriate */
783 /* options->hostname will be set in the main program if appropriate */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000784}