blob: 4f4a16de8f18775bd8340d837c269feb9289a6c3 [file] [log] [blame]
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001/*
Damien Miller95def091999-11-25 00:26:21 +11002 * Author: Tatu Ylonen <ylo@cs.hut.fi>
Damien Miller95def091999-11-25 00:26:21 +11003 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 * All rights reserved
Damien Miller95def091999-11-25 00:26:21 +11005 * Functions for reading the configuration files.
Damien Miller4af51302000-04-16 11:18:38 +10006 *
Damien Millere4340be2000-09-16 13:29:08 +11007 * As far as I am concerned, the code I have written for this software
8 * can be used freely for any purpose. Any derived versions of this
9 * software must be clearly marked as such, and if the derived work is
10 * incompatible with the protocol description in the RFC file, it must be
11 * called by a name other than "ssh" or "Secure Shell".
Damien Miller95def091999-11-25 00:26:21 +110012 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100013
14#include "includes.h"
Damien Millere4340be2000-09-16 13:29:08 +110015RCSID("$OpenBSD: readconf.c,v 1.47 2000/09/07 21:13:37 markus Exp $");
Damien Millerd4a8b7e1999-10-27 13:42:43 +100016
17#include "ssh.h"
18#include "cipher.h"
19#include "readconf.h"
Damien Millerb38eff82000-04-01 11:09:21 +100020#include "match.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100021#include "xmalloc.h"
Damien Miller78928792000-04-12 20:17:38 +100022#include "compat.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100023
24/* Format of the configuration file:
25
26 # Configuration data is parsed as follows:
27 # 1. command line options
28 # 2. user-specific file
29 # 3. system-wide file
30 # Any configuration value is only changed the first time it is set.
31 # Thus, host-specific definitions should be at the beginning of the
32 # configuration file, and defaults at the end.
33
34 # Host-specific declarations. These may override anything above. A single
35 # host may match multiple declarations; these are processed in the order
36 # that they are given in.
37
38 Host *.ngs.fi ngs.fi
39 FallBackToRsh no
40
41 Host fake.com
42 HostName another.host.name.real.org
43 User blaah
44 Port 34289
45 ForwardX11 no
46 ForwardAgent no
47
48 Host books.com
49 RemoteForward 9999 shadows.cs.hut.fi:9999
50 Cipher 3des
51
52 Host fascist.blob.com
53 Port 23123
54 User tylonen
55 RhostsAuthentication no
56 PasswordAuthentication no
57
58 Host puukko.hut.fi
59 User t35124p
60 ProxyCommand ssh-proxy %h %p
61
62 Host *.fr
63 UseRsh yes
64
65 Host *.su
66 Cipher none
67 PasswordAuthentication no
68
69 # Defaults for various options
70 Host *
71 ForwardAgent no
72 ForwardX11 yes
73 RhostsAuthentication yes
74 PasswordAuthentication yes
75 RSAAuthentication yes
76 RhostsRSAAuthentication yes
77 FallBackToRsh no
78 UseRsh no
79 StrictHostKeyChecking yes
80 KeepAlives no
81 IdentityFile ~/.ssh/identity
82 Port 22
83 EscapeChar ~
84
85*/
86
87/* Keyword tokens. */
88
Damien Miller95def091999-11-25 00:26:21 +110089typedef enum {
90 oBadOption,
91 oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
92 oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh,
Damien Millerd3a18572000-06-07 19:55:44 +100093 oSkeyAuthentication, oXAuthLocation,
Damien Millerd4a8b7e1999-10-27 13:42:43 +100094#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +110095 oKerberosAuthentication,
Damien Millerd4a8b7e1999-10-27 13:42:43 +100096#endif /* KRB4 */
97#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +110098 oKerberosTgtPassing, oAFSTokenPassing,
Damien Millerd4a8b7e1999-10-27 13:42:43 +100099#endif
Damien Miller95def091999-11-25 00:26:21 +1100100 oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
101 oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
102 oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
103 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
104 oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
Damien Millereba71ba2000-04-29 23:57:08 +1000105 oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oIdentityFile2,
Damien Millere247cc42000-05-07 12:03:14 +1000106 oGlobalKnownHostsFile2, oUserKnownHostsFile2, oDSAAuthentication
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000107} OpCodes;
108
109/* Textual representations of the tokens. */
110
Damien Miller95def091999-11-25 00:26:21 +1100111static struct {
112 const char *name;
113 OpCodes opcode;
114} keywords[] = {
115 { "forwardagent", oForwardAgent },
116 { "forwardx11", oForwardX11 },
Damien Millerd3a18572000-06-07 19:55:44 +1000117 { "xauthlocation", oXAuthLocation },
Damien Miller95def091999-11-25 00:26:21 +1100118 { "gatewayports", oGatewayPorts },
119 { "useprivilegedport", oUsePrivilegedPort },
120 { "rhostsauthentication", oRhostsAuthentication },
121 { "passwordauthentication", oPasswordAuthentication },
122 { "rsaauthentication", oRSAAuthentication },
Damien Millere247cc42000-05-07 12:03:14 +1000123 { "dsaauthentication", oDSAAuthentication },
Damien Miller95def091999-11-25 00:26:21 +1100124 { "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 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;
Damien Millerbac2d8a2000-09-05 16:13:06 +1100175#ifndef HAVE_CYGWIN
Damien Miller95def091999-11-25 00:26:21 +1100176 extern uid_t original_real_uid;
Damien Miller95def091999-11-25 00:26:21 +1100177 if (port < IPPORT_RESERVED && original_real_uid != 0)
178 fatal("Privileged ports can only be forwarded by root.\n");
Damien Millerbac2d8a2000-09-05 16:13:06 +1100179#endif
Damien Miller95def091999-11-25 00:26:21 +1100180 if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
181 fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
182 fwd = &options->local_forwards[options->num_local_forwards++];
183 fwd->port = port;
184 fwd->host = xstrdup(host);
185 fwd->host_port = host_port;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000186}
187
Damien Miller5428f641999-11-25 11:54:57 +1100188/*
189 * Adds a remote TCP/IP port forward to options. Never returns if there is
190 * an error.
191 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000192
Damien Miller4af51302000-04-16 11:18:38 +1000193void
Damien Milleraae6c611999-12-06 11:47:28 +1100194add_remote_forward(Options *options, u_short port, const char *host,
195 u_short host_port)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000196{
Damien Miller95def091999-11-25 00:26:21 +1100197 Forward *fwd;
198 if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
199 fatal("Too many remote forwards (max %d).",
200 SSH_MAX_FORWARDS_PER_DIRECTION);
201 fwd = &options->remote_forwards[options->num_remote_forwards++];
202 fwd->port = port;
203 fwd->host = xstrdup(host);
204 fwd->host_port = host_port;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000205}
206
Damien Miller5428f641999-11-25 11:54:57 +1100207/*
208 * Returns the number of the token pointed to by cp of length len. Never
209 * returns if the token is not known.
210 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000211
Damien Miller4af51302000-04-16 11:18:38 +1000212static OpCodes
Damien Miller95def091999-11-25 00:26:21 +1100213parse_token(const char *cp, const char *filename, int linenum)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000214{
Damien Miller95def091999-11-25 00:26:21 +1100215 unsigned int i;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000216
Damien Miller95def091999-11-25 00:26:21 +1100217 for (i = 0; keywords[i].name; i++)
Damien Miller5428f641999-11-25 11:54:57 +1100218 if (strcasecmp(cp, keywords[i].name) == 0)
Damien Miller95def091999-11-25 00:26:21 +1100219 return keywords[i].opcode;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000220
Damien Miller95def091999-11-25 00:26:21 +1100221 fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
222 filename, linenum, cp);
223 return oBadOption;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000224}
225
Damien Miller5428f641999-11-25 11:54:57 +1100226/*
227 * Processes a single option line as used in the configuration files. This
228 * only sets those values that have not already been set.
229 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000230
Damien Miller2ccf6611999-11-15 15:25:10 +1100231int
232process_config_line(Options *options, const char *host,
Damien Miller95def091999-11-25 00:26:21 +1100233 char *line, const char *filename, int linenum,
234 int *activep)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000235{
Damien Miller37023962000-07-11 17:31:38 +1000236 char buf[256], *s, *string, **charptr, *endofnumber, *keyword, *arg;
Damien Milleraae6c611999-12-06 11:47:28 +1100237 int opcode, *intptr, value;
238 u_short fwd_port, fwd_host_port;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000239
Damien Millerbe484b52000-07-15 14:14:16 +1000240 s = line;
241 /* Get the keyword. (Each line is supposed to begin with a keyword). */
242 keyword = strdelim(&s);
243 /* Ignore leading whitespace. */
244 if (*keyword == '\0')
245 keyword = strdelim(&s);
246 if (!*keyword || *keyword == '\n' || *keyword == '#')
Damien Miller95def091999-11-25 00:26:21 +1100247 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000248
Damien Miller37023962000-07-11 17:31:38 +1000249 opcode = parse_token(keyword, 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:
Damien Millerbe484b52000-07-15 14:14:16 +1000259 arg = strdelim(&s);
Damien Miller37023962000-07-11 17:31:38 +1000260 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100261 fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
262 value = 0; /* To avoid compiler warning... */
Damien Miller37023962000-07-11 17:31:38 +1000263 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
Damien Miller95def091999-11-25 00:26:21 +1100264 value = 1;
Damien Miller37023962000-07-11 17:31:38 +1000265 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
Damien Miller95def091999-11-25 00:26:21 +1100266 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
Damien Millere247cc42000-05-07 12:03:14 +1000293 case oDSAAuthentication:
294 intptr = &options->dsa_authentication;
295 goto parse_flag;
296
Damien Miller95def091999-11-25 00:26:21 +1100297 case oRSAAuthentication:
298 intptr = &options->rsa_authentication;
299 goto parse_flag;
300
301 case oRhostsRSAAuthentication:
302 intptr = &options->rhosts_rsa_authentication;
303 goto parse_flag;
304
305 case oTISAuthentication:
306 /* fallthrough, there is no difference on the client side */
307 case oSkeyAuthentication:
308 intptr = &options->skey_authentication;
309 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000310
311#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100312 case oKerberosAuthentication:
313 intptr = &options->kerberos_authentication;
314 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000315#endif /* KRB4 */
316
317#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100318 case oKerberosTgtPassing:
319 intptr = &options->kerberos_tgt_passing;
320 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000321
Damien Miller95def091999-11-25 00:26:21 +1100322 case oAFSTokenPassing:
323 intptr = &options->afs_token_passing;
324 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000325#endif
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000326
Damien Miller95def091999-11-25 00:26:21 +1100327 case oFallBackToRsh:
328 intptr = &options->fallback_to_rsh;
329 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000330
Damien Miller95def091999-11-25 00:26:21 +1100331 case oUseRsh:
332 intptr = &options->use_rsh;
333 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000334
Damien Miller95def091999-11-25 00:26:21 +1100335 case oBatchMode:
336 intptr = &options->batch_mode;
337 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000338
Damien Miller95def091999-11-25 00:26:21 +1100339 case oCheckHostIP:
340 intptr = &options->check_host_ip;
341 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000342
Damien Miller95def091999-11-25 00:26:21 +1100343 case oStrictHostKeyChecking:
344 intptr = &options->strict_host_key_checking;
Damien Millerbe484b52000-07-15 14:14:16 +1000345 arg = strdelim(&s);
Damien Miller37023962000-07-11 17:31:38 +1000346 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100347 fatal("%.200s line %d: Missing yes/no argument.",
348 filename, linenum);
349 value = 0; /* To avoid compiler warning... */
Damien Miller37023962000-07-11 17:31:38 +1000350 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
Damien Miller95def091999-11-25 00:26:21 +1100351 value = 1;
Damien Miller37023962000-07-11 17:31:38 +1000352 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
Damien Miller95def091999-11-25 00:26:21 +1100353 value = 0;
Damien Miller37023962000-07-11 17:31:38 +1000354 else if (strcmp(arg, "ask") == 0)
Damien Miller95def091999-11-25 00:26:21 +1100355 value = 2;
356 else
357 fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
358 if (*activep && *intptr == -1)
359 *intptr = value;
360 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000361
Damien Miller95def091999-11-25 00:26:21 +1100362 case oCompression:
363 intptr = &options->compression;
364 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000365
Damien Miller95def091999-11-25 00:26:21 +1100366 case oKeepAlives:
367 intptr = &options->keepalives;
368 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000369
Damien Miller95def091999-11-25 00:26:21 +1100370 case oNumberOfPasswordPrompts:
371 intptr = &options->number_of_password_prompts;
372 goto parse_int;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000373
Damien Miller95def091999-11-25 00:26:21 +1100374 case oCompressionLevel:
375 intptr = &options->compression_level;
376 goto parse_int;
377
378 case oIdentityFile:
Damien Millereba71ba2000-04-29 23:57:08 +1000379 case oIdentityFile2:
Damien Millerbe484b52000-07-15 14:14:16 +1000380 arg = strdelim(&s);
Damien Miller37023962000-07-11 17:31:38 +1000381 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100382 fatal("%.200s line %d: Missing argument.", filename, linenum);
383 if (*activep) {
Damien Millereba71ba2000-04-29 23:57:08 +1000384 intptr = (opcode == oIdentityFile) ?
385 &options->num_identity_files :
386 &options->num_identity_files2;
387 if (*intptr >= SSH_MAX_IDENTITY_FILES)
Damien Miller95def091999-11-25 00:26:21 +1100388 fatal("%.200s line %d: Too many identity files specified (max %d).",
389 filename, linenum, SSH_MAX_IDENTITY_FILES);
Damien Millereba71ba2000-04-29 23:57:08 +1000390 charptr = (opcode == oIdentityFile) ?
391 &options->identity_files[*intptr] :
392 &options->identity_files2[*intptr];
Damien Miller37023962000-07-11 17:31:38 +1000393 *charptr = xstrdup(arg);
Damien Millereba71ba2000-04-29 23:57:08 +1000394 *intptr = *intptr + 1;
Damien Miller95def091999-11-25 00:26:21 +1100395 }
396 break;
397
Damien Millerd3a18572000-06-07 19:55:44 +1000398 case oXAuthLocation:
399 charptr=&options->xauth_location;
400 goto parse_string;
401
Damien Miller95def091999-11-25 00:26:21 +1100402 case oUser:
403 charptr = &options->user;
404parse_string:
Damien Millerbe484b52000-07-15 14:14:16 +1000405 arg = strdelim(&s);
Damien Miller37023962000-07-11 17:31:38 +1000406 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100407 fatal("%.200s line %d: Missing argument.", filename, linenum);
408 if (*activep && *charptr == NULL)
Damien Miller37023962000-07-11 17:31:38 +1000409 *charptr = xstrdup(arg);
Damien Miller95def091999-11-25 00:26:21 +1100410 break;
411
412 case oGlobalKnownHostsFile:
413 charptr = &options->system_hostfile;
414 goto parse_string;
415
416 case oUserKnownHostsFile:
417 charptr = &options->user_hostfile;
418 goto parse_string;
419
Damien Millereba71ba2000-04-29 23:57:08 +1000420 case oGlobalKnownHostsFile2:
421 charptr = &options->system_hostfile2;
422 goto parse_string;
423
424 case oUserKnownHostsFile2:
425 charptr = &options->user_hostfile2;
426 goto parse_string;
427
Damien Miller95def091999-11-25 00:26:21 +1100428 case oHostName:
429 charptr = &options->hostname;
430 goto parse_string;
431
432 case oProxyCommand:
433 charptr = &options->proxy_command;
434 string = xstrdup("");
Damien Millerbe484b52000-07-15 14:14:16 +1000435 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
Damien Miller37023962000-07-11 17:31:38 +1000436 string = xrealloc(string, strlen(string) + strlen(arg) + 2);
Damien Miller95def091999-11-25 00:26:21 +1100437 strcat(string, " ");
Damien Miller37023962000-07-11 17:31:38 +1000438 strcat(string, arg);
Damien Miller95def091999-11-25 00:26:21 +1100439 }
440 if (*activep && *charptr == NULL)
441 *charptr = string;
442 else
443 xfree(string);
444 return 0;
445
446 case oPort:
447 intptr = &options->port;
448parse_int:
Damien Millerbe484b52000-07-15 14:14:16 +1000449 arg = strdelim(&s);
Damien Miller37023962000-07-11 17:31:38 +1000450 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100451 fatal("%.200s line %d: Missing argument.", filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000452 if (arg[0] < '0' || arg[0] > '9')
Damien Miller95def091999-11-25 00:26:21 +1100453 fatal("%.200s line %d: Bad number.", filename, linenum);
Damien Miller5428f641999-11-25 11:54:57 +1100454
455 /* Octal, decimal, or hex format? */
Damien Miller37023962000-07-11 17:31:38 +1000456 value = strtol(arg, &endofnumber, 0);
457 if (arg == endofnumber)
Damien Miller5428f641999-11-25 11:54:57 +1100458 fatal("%.200s line %d: Bad number.", filename, linenum);
Damien Miller95def091999-11-25 00:26:21 +1100459 if (*activep && *intptr == -1)
460 *intptr = value;
461 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000462
Damien Miller95def091999-11-25 00:26:21 +1100463 case oConnectionAttempts:
464 intptr = &options->connection_attempts;
465 goto parse_int;
Damien Miller5ce662a1999-11-11 17:57:39 +1100466
Damien Miller95def091999-11-25 00:26:21 +1100467 case oCipher:
468 intptr = &options->cipher;
Damien Millerbe484b52000-07-15 14:14:16 +1000469 arg = strdelim(&s);
Damien Miller37023962000-07-11 17:31:38 +1000470 if (!arg || *arg == '\0')
Damien Millerb1715dc2000-05-30 13:44:51 +1000471 fatal("%.200s line %d: Missing argument.", filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000472 value = cipher_number(arg);
Damien Miller95def091999-11-25 00:26:21 +1100473 if (value == -1)
474 fatal("%.200s line %d: Bad cipher '%s'.",
Damien Miller37023962000-07-11 17:31:38 +1000475 filename, linenum, arg ? arg : "<NONE>");
Damien Miller95def091999-11-25 00:26:21 +1100476 if (*activep && *intptr == -1)
477 *intptr = value;
478 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000479
Damien Miller78928792000-04-12 20:17:38 +1000480 case oCiphers:
Damien Millerbe484b52000-07-15 14:14:16 +1000481 arg = strdelim(&s);
Damien Miller37023962000-07-11 17:31:38 +1000482 if (!arg || *arg == '\0')
Damien Millerb1715dc2000-05-30 13:44:51 +1000483 fatal("%.200s line %d: Missing argument.", filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000484 if (!ciphers_valid(arg))
Damien Miller30c3d422000-05-09 11:02:59 +1000485 fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
Damien Miller37023962000-07-11 17:31:38 +1000486 filename, linenum, arg ? arg : "<NONE>");
Damien Miller78928792000-04-12 20:17:38 +1000487 if (*activep && options->ciphers == NULL)
Damien Miller37023962000-07-11 17:31:38 +1000488 options->ciphers = xstrdup(arg);
Damien Miller78928792000-04-12 20:17:38 +1000489 break;
490
491 case oProtocol:
492 intptr = &options->protocol;
Damien Millerbe484b52000-07-15 14:14:16 +1000493 arg = strdelim(&s);
Damien Miller37023962000-07-11 17:31:38 +1000494 if (!arg || *arg == '\0')
Damien Millerb1715dc2000-05-30 13:44:51 +1000495 fatal("%.200s line %d: Missing argument.", filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000496 value = proto_spec(arg);
Damien Miller78928792000-04-12 20:17:38 +1000497 if (value == SSH_PROTO_UNKNOWN)
498 fatal("%.200s line %d: Bad protocol spec '%s'.",
Damien Miller37023962000-07-11 17:31:38 +1000499 filename, linenum, arg ? arg : "<NONE>");
Damien Miller78928792000-04-12 20:17:38 +1000500 if (*activep && *intptr == SSH_PROTO_UNKNOWN)
501 *intptr = value;
502 break;
503
Damien Miller95def091999-11-25 00:26:21 +1100504 case oLogLevel:
505 intptr = (int *) &options->log_level;
Damien Millerbe484b52000-07-15 14:14:16 +1000506 arg = strdelim(&s);
Damien Miller37023962000-07-11 17:31:38 +1000507 value = log_level_number(arg);
Damien Miller95def091999-11-25 00:26:21 +1100508 if (value == (LogLevel) - 1)
509 fatal("%.200s line %d: unsupported log level '%s'\n",
Damien Miller37023962000-07-11 17:31:38 +1000510 filename, linenum, arg ? arg : "<NONE>");
Damien Miller95def091999-11-25 00:26:21 +1100511 if (*activep && (LogLevel) * intptr == -1)
512 *intptr = (LogLevel) value;
513 break;
514
515 case oRemoteForward:
Damien Millerbe484b52000-07-15 14:14:16 +1000516 arg = strdelim(&s);
Damien Miller37023962000-07-11 17:31:38 +1000517 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100518 fatal("%.200s line %d: Missing argument.", filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000519 if (arg[0] < '0' || arg[0] > '9')
Damien Miller95def091999-11-25 00:26:21 +1100520 fatal("%.200s line %d: Badly formatted port number.",
521 filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000522 fwd_port = atoi(arg);
Damien Millerbe484b52000-07-15 14:14:16 +1000523 arg = strdelim(&s);
Damien Miller37023962000-07-11 17:31:38 +1000524 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100525 fatal("%.200s line %d: Missing second argument.",
526 filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000527 if (sscanf(arg, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
Damien Miller95def091999-11-25 00:26:21 +1100528 fatal("%.200s line %d: Badly formatted host:port.",
529 filename, linenum);
530 if (*activep)
531 add_remote_forward(options, fwd_port, buf, fwd_host_port);
532 break;
533
534 case oLocalForward:
Damien Millerbe484b52000-07-15 14:14:16 +1000535 arg = strdelim(&s);
Damien Miller37023962000-07-11 17:31:38 +1000536 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100537 fatal("%.200s line %d: Missing argument.", filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000538 if (arg[0] < '0' || arg[0] > '9')
Damien Miller95def091999-11-25 00:26:21 +1100539 fatal("%.200s line %d: Badly formatted port number.",
540 filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000541 fwd_port = atoi(arg);
Damien Millerbe484b52000-07-15 14:14:16 +1000542 arg = strdelim(&s);
Damien Miller37023962000-07-11 17:31:38 +1000543 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100544 fatal("%.200s line %d: Missing second argument.",
545 filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000546 if (sscanf(arg, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
Damien Miller95def091999-11-25 00:26:21 +1100547 fatal("%.200s line %d: Badly formatted host:port.",
548 filename, linenum);
549 if (*activep)
550 add_local_forward(options, fwd_port, buf, fwd_host_port);
551 break;
552
553 case oHost:
554 *activep = 0;
Damien Millerbe484b52000-07-15 14:14:16 +1000555 while ((arg = strdelim(&s)) != NULL && *arg != '\0')
Damien Miller37023962000-07-11 17:31:38 +1000556 if (match_pattern(host, arg)) {
557 debug("Applying options for %.100s", arg);
Damien Miller95def091999-11-25 00:26:21 +1100558 *activep = 1;
559 break;
560 }
Damien Millerbe484b52000-07-15 14:14:16 +1000561 /* Avoid garbage check below, as strdelim is done. */
Damien Miller95def091999-11-25 00:26:21 +1100562 return 0;
563
564 case oEscapeChar:
565 intptr = &options->escape_char;
Damien Millerbe484b52000-07-15 14:14:16 +1000566 arg = strdelim(&s);
Damien Miller37023962000-07-11 17:31:38 +1000567 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100568 fatal("%.200s line %d: Missing argument.", filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000569 if (arg[0] == '^' && arg[2] == 0 &&
570 (unsigned char) arg[1] >= 64 && (unsigned char) arg[1] < 128)
571 value = (unsigned char) arg[1] & 31;
572 else if (strlen(arg) == 1)
573 value = (unsigned char) arg[0];
574 else if (strcmp(arg, "none") == 0)
Damien Miller95def091999-11-25 00:26:21 +1100575 value = -2;
576 else {
577 fatal("%.200s line %d: Bad escape character.",
578 filename, linenum);
579 /* NOTREACHED */
580 value = 0; /* Avoid compiler warning. */
581 }
582 if (*activep && *intptr == -1)
583 *intptr = value;
584 break;
585
586 default:
587 fatal("process_config_line: Unimplemented opcode %d", opcode);
588 }
589
590 /* Check that there is no garbage at end of line. */
Damien Millerbe484b52000-07-15 14:14:16 +1000591 if ((arg = strdelim(&s)) != NULL && *arg != '\0')
Damien Miller37023962000-07-11 17:31:38 +1000592 {
593 fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
594 filename, linenum, arg);
595 }
Damien Miller95def091999-11-25 00:26:21 +1100596 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000597}
598
599
Damien Miller5428f641999-11-25 11:54:57 +1100600/*
601 * Reads the config file and modifies the options accordingly. Options
602 * should already be initialized before this call. This never returns if
603 * there is an error. If the file does not exist, this returns immediately.
604 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000605
Damien Miller4af51302000-04-16 11:18:38 +1000606void
Damien Miller95def091999-11-25 00:26:21 +1100607read_config_file(const char *filename, const char *host, Options *options)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000608{
Damien Miller95def091999-11-25 00:26:21 +1100609 FILE *f;
610 char line[1024];
611 int active, linenum;
612 int bad_options = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000613
Damien Miller95def091999-11-25 00:26:21 +1100614 /* Open the file. */
615 f = fopen(filename, "r");
616 if (!f)
617 return;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000618
Damien Miller95def091999-11-25 00:26:21 +1100619 debug("Reading configuration data %.200s", filename);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000620
Damien Miller5428f641999-11-25 11:54:57 +1100621 /*
622 * Mark that we are now processing the options. This flag is turned
623 * on/off by Host specifications.
624 */
Damien Miller95def091999-11-25 00:26:21 +1100625 active = 1;
626 linenum = 0;
627 while (fgets(line, sizeof(line), f)) {
628 /* Update line number counter. */
629 linenum++;
630 if (process_config_line(options, host, line, filename, linenum, &active) != 0)
631 bad_options++;
632 }
633 fclose(f);
634 if (bad_options > 0)
635 fatal("%s: terminating, %d bad configuration options\n",
636 filename, bad_options);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000637}
638
Damien Miller5428f641999-11-25 11:54:57 +1100639/*
640 * Initializes options to special values that indicate that they have not yet
641 * been set. Read_config_file will only set options with this value. Options
642 * are processed in the following order: command line, user config file,
643 * system config file. Last, fill_default_options is called.
644 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000645
Damien Miller4af51302000-04-16 11:18:38 +1000646void
Damien Miller95def091999-11-25 00:26:21 +1100647initialize_options(Options * options)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000648{
Damien Miller95def091999-11-25 00:26:21 +1100649 memset(options, 'X', sizeof(*options));
650 options->forward_agent = -1;
651 options->forward_x11 = -1;
Damien Millerd3a18572000-06-07 19:55:44 +1000652 options->xauth_location = NULL;
Damien Miller95def091999-11-25 00:26:21 +1100653 options->gateway_ports = -1;
654 options->use_privileged_port = -1;
655 options->rhosts_authentication = -1;
656 options->rsa_authentication = -1;
Damien Millere247cc42000-05-07 12:03:14 +1000657 options->dsa_authentication = -1;
Damien Miller95def091999-11-25 00:26:21 +1100658 options->skey_authentication = -1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000659#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100660 options->kerberos_authentication = -1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000661#endif
662#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100663 options->kerberos_tgt_passing = -1;
664 options->afs_token_passing = -1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000665#endif
Damien Miller95def091999-11-25 00:26:21 +1100666 options->password_authentication = -1;
667 options->rhosts_rsa_authentication = -1;
668 options->fallback_to_rsh = -1;
669 options->use_rsh = -1;
670 options->batch_mode = -1;
671 options->check_host_ip = -1;
672 options->strict_host_key_checking = -1;
673 options->compression = -1;
674 options->keepalives = -1;
675 options->compression_level = -1;
676 options->port = -1;
677 options->connection_attempts = -1;
678 options->number_of_password_prompts = -1;
679 options->cipher = -1;
Damien Miller78928792000-04-12 20:17:38 +1000680 options->ciphers = NULL;
681 options->protocol = SSH_PROTO_UNKNOWN;
Damien Miller95def091999-11-25 00:26:21 +1100682 options->num_identity_files = 0;
Damien Millereba71ba2000-04-29 23:57:08 +1000683 options->num_identity_files2 = 0;
Damien Miller95def091999-11-25 00:26:21 +1100684 options->hostname = NULL;
685 options->proxy_command = NULL;
686 options->user = NULL;
687 options->escape_char = -1;
688 options->system_hostfile = NULL;
689 options->user_hostfile = NULL;
Damien Millereba71ba2000-04-29 23:57:08 +1000690 options->system_hostfile2 = NULL;
691 options->user_hostfile2 = NULL;
Damien Miller95def091999-11-25 00:26:21 +1100692 options->num_local_forwards = 0;
693 options->num_remote_forwards = 0;
694 options->log_level = (LogLevel) - 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000695}
696
Damien Miller5428f641999-11-25 11:54:57 +1100697/*
698 * Called after processing other sources of option data, this fills those
699 * options for which no value has been specified with their default values.
700 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000701
Damien Miller4af51302000-04-16 11:18:38 +1000702void
Damien Miller95def091999-11-25 00:26:21 +1100703fill_default_options(Options * options)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000704{
Damien Miller95def091999-11-25 00:26:21 +1100705 if (options->forward_agent == -1)
Damien Millerb1715dc2000-05-30 13:44:51 +1000706 options->forward_agent = 0;
Damien Miller95def091999-11-25 00:26:21 +1100707 if (options->forward_x11 == -1)
Damien Miller98c7ad62000-03-09 21:27:49 +1100708 options->forward_x11 = 0;
Damien Millerd3a18572000-06-07 19:55:44 +1000709#ifdef XAUTH_PATH
710 if (options->xauth_location == NULL)
711 options->xauth_location = XAUTH_PATH;
712#endif /* XAUTH_PATH */
Damien Miller95def091999-11-25 00:26:21 +1100713 if (options->gateway_ports == -1)
714 options->gateway_ports = 0;
715 if (options->use_privileged_port == -1)
716 options->use_privileged_port = 1;
717 if (options->rhosts_authentication == -1)
718 options->rhosts_authentication = 1;
719 if (options->rsa_authentication == -1)
720 options->rsa_authentication = 1;
Damien Millere247cc42000-05-07 12:03:14 +1000721 if (options->dsa_authentication == -1)
722 options->dsa_authentication = 1;
Damien Miller95def091999-11-25 00:26:21 +1100723 if (options->skey_authentication == -1)
724 options->skey_authentication = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000725#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100726 if (options->kerberos_authentication == -1)
727 options->kerberos_authentication = 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000728#endif /* KRB4 */
729#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100730 if (options->kerberos_tgt_passing == -1)
731 options->kerberos_tgt_passing = 1;
732 if (options->afs_token_passing == -1)
733 options->afs_token_passing = 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000734#endif /* AFS */
Damien Miller95def091999-11-25 00:26:21 +1100735 if (options->password_authentication == -1)
736 options->password_authentication = 1;
737 if (options->rhosts_rsa_authentication == -1)
738 options->rhosts_rsa_authentication = 1;
739 if (options->fallback_to_rsh == -1)
Damien Miller182ee6e2000-07-12 09:45:27 +1000740 options->fallback_to_rsh = 0;
Damien Miller95def091999-11-25 00:26:21 +1100741 if (options->use_rsh == -1)
742 options->use_rsh = 0;
743 if (options->batch_mode == -1)
744 options->batch_mode = 0;
745 if (options->check_host_ip == -1)
746 options->check_host_ip = 1;
747 if (options->strict_host_key_checking == -1)
748 options->strict_host_key_checking = 2; /* 2 is default */
749 if (options->compression == -1)
750 options->compression = 0;
751 if (options->keepalives == -1)
752 options->keepalives = 1;
753 if (options->compression_level == -1)
754 options->compression_level = 6;
755 if (options->port == -1)
756 options->port = 0; /* Filled in ssh_connect. */
757 if (options->connection_attempts == -1)
758 options->connection_attempts = 4;
759 if (options->number_of_password_prompts == -1)
760 options->number_of_password_prompts = 3;
761 /* Selected in ssh_login(). */
762 if (options->cipher == -1)
763 options->cipher = SSH_CIPHER_NOT_SET;
Damien Miller30c3d422000-05-09 11:02:59 +1000764 /* options->ciphers, default set in myproposals.h */
Damien Miller78928792000-04-12 20:17:38 +1000765 if (options->protocol == SSH_PROTO_UNKNOWN)
Damien Millereba71ba2000-04-29 23:57:08 +1000766 options->protocol = SSH_PROTO_1|SSH_PROTO_2|SSH_PROTO_1_PREFERRED;
Damien Miller95def091999-11-25 00:26:21 +1100767 if (options->num_identity_files == 0) {
768 options->identity_files[0] =
769 xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
770 sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
771 options->num_identity_files = 1;
772 }
Damien Millereba71ba2000-04-29 23:57:08 +1000773 if (options->num_identity_files2 == 0) {
774 options->identity_files2[0] =
Damien Millere247cc42000-05-07 12:03:14 +1000775 xmalloc(2 + strlen(SSH_CLIENT_ID_DSA) + 1);
776 sprintf(options->identity_files2[0], "~/%.100s", SSH_CLIENT_ID_DSA);
Damien Millereba71ba2000-04-29 23:57:08 +1000777 options->num_identity_files2 = 1;
778 }
Damien Miller95def091999-11-25 00:26:21 +1100779 if (options->escape_char == -1)
780 options->escape_char = '~';
781 if (options->system_hostfile == NULL)
782 options->system_hostfile = SSH_SYSTEM_HOSTFILE;
783 if (options->user_hostfile == NULL)
784 options->user_hostfile = SSH_USER_HOSTFILE;
Damien Millereba71ba2000-04-29 23:57:08 +1000785 if (options->system_hostfile2 == NULL)
786 options->system_hostfile2 = SSH_SYSTEM_HOSTFILE2;
787 if (options->user_hostfile2 == NULL)
788 options->user_hostfile2 = SSH_USER_HOSTFILE2;
Damien Miller95def091999-11-25 00:26:21 +1100789 if (options->log_level == (LogLevel) - 1)
790 options->log_level = SYSLOG_LEVEL_INFO;
791 /* options->proxy_command should not be set by default */
792 /* options->user will be set in the main program if appropriate */
793 /* options->hostname will be set in the main program if appropriate */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000794}