blob: 28aa0a8b8349efce5f09224e7e268941b3098aac [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 Miller37023962000-07-11 17:31:38 +100017RCSID("$OpenBSD: readconf.c,v 1.40 2000/07/10 16:27:05 ho 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,
Damien Millerd3a18572000-06-07 19:55:44 +100095 oSkeyAuthentication, oXAuthLocation,
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 },
Damien Millerd3a18572000-06-07 19:55:44 +1000119 { "xauthlocation", oXAuthLocation },
Damien Miller95def091999-11-25 00:26:21 +1100120 { "gatewayports", oGatewayPorts },
121 { "useprivilegedport", oUsePrivilegedPort },
122 { "rhostsauthentication", oRhostsAuthentication },
123 { "passwordauthentication", oPasswordAuthentication },
124 { "rsaauthentication", oRSAAuthentication },
Damien Millere247cc42000-05-07 12:03:14 +1000125 { "dsaauthentication", oDSAAuthentication },
Damien Miller95def091999-11-25 00:26:21 +1100126 { "skeyauthentication", oSkeyAuthentication },
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000127#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100128 { "kerberosauthentication", oKerberosAuthentication },
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000129#endif /* KRB4 */
130#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100131 { "kerberostgtpassing", oKerberosTgtPassing },
132 { "afstokenpassing", oAFSTokenPassing },
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000133#endif
Damien Miller95def091999-11-25 00:26:21 +1100134 { "fallbacktorsh", oFallBackToRsh },
135 { "usersh", oUseRsh },
136 { "identityfile", oIdentityFile },
Damien Millereba71ba2000-04-29 23:57:08 +1000137 { "identityfile2", oIdentityFile2 },
Damien Miller95def091999-11-25 00:26:21 +1100138 { "hostname", oHostName },
139 { "proxycommand", oProxyCommand },
140 { "port", oPort },
141 { "cipher", oCipher },
Damien Miller78928792000-04-12 20:17:38 +1000142 { "ciphers", oCiphers },
143 { "protocol", oProtocol },
Damien Miller95def091999-11-25 00:26:21 +1100144 { "remoteforward", oRemoteForward },
145 { "localforward", oLocalForward },
146 { "user", oUser },
147 { "host", oHost },
148 { "escapechar", oEscapeChar },
149 { "rhostsrsaauthentication", oRhostsRSAAuthentication },
150 { "globalknownhostsfile", oGlobalKnownHostsFile },
151 { "userknownhostsfile", oUserKnownHostsFile },
Damien Millereba71ba2000-04-29 23:57:08 +1000152 { "globalknownhostsfile2", oGlobalKnownHostsFile2 },
153 { "userknownhostsfile2", oUserKnownHostsFile2 },
Damien Miller95def091999-11-25 00:26:21 +1100154 { "connectionattempts", oConnectionAttempts },
155 { "batchmode", oBatchMode },
156 { "checkhostip", oCheckHostIP },
157 { "stricthostkeychecking", oStrictHostKeyChecking },
158 { "compression", oCompression },
159 { "compressionlevel", oCompressionLevel },
160 { "keepalive", oKeepAlives },
161 { "numberofpasswordprompts", oNumberOfPasswordPrompts },
162 { "tisauthentication", oTISAuthentication },
163 { "loglevel", oLogLevel },
164 { NULL, 0 }
Damien Miller5ce662a1999-11-11 17:57:39 +1100165};
166
Damien Miller37023962000-07-11 17:31:38 +1000167/* Characters considered whitespace in strsep calls. */
Damien Millerf6d9e222000-06-18 14:50:44 +1000168#define WHITESPACE " \t\r\n="
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000169
170
Damien Miller5428f641999-11-25 11:54:57 +1100171/*
172 * Adds a local TCP/IP port forward to options. Never returns if there is an
173 * error.
174 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000175
Damien Miller4af51302000-04-16 11:18:38 +1000176void
Damien Milleraae6c611999-12-06 11:47:28 +1100177add_local_forward(Options *options, u_short port, const char *host,
178 u_short host_port)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000179{
Damien Miller95def091999-11-25 00:26:21 +1100180 Forward *fwd;
181 extern uid_t original_real_uid;
Damien Miller95def091999-11-25 00:26:21 +1100182 if (port < IPPORT_RESERVED && original_real_uid != 0)
183 fatal("Privileged ports can only be forwarded by root.\n");
184 if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
185 fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
186 fwd = &options->local_forwards[options->num_local_forwards++];
187 fwd->port = port;
188 fwd->host = xstrdup(host);
189 fwd->host_port = host_port;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000190}
191
Damien Miller5428f641999-11-25 11:54:57 +1100192/*
193 * Adds a remote TCP/IP port forward to options. Never returns if there is
194 * an error.
195 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000196
Damien Miller4af51302000-04-16 11:18:38 +1000197void
Damien Milleraae6c611999-12-06 11:47:28 +1100198add_remote_forward(Options *options, u_short port, const char *host,
199 u_short host_port)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000200{
Damien Miller95def091999-11-25 00:26:21 +1100201 Forward *fwd;
202 if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
203 fatal("Too many remote forwards (max %d).",
204 SSH_MAX_FORWARDS_PER_DIRECTION);
205 fwd = &options->remote_forwards[options->num_remote_forwards++];
206 fwd->port = port;
207 fwd->host = xstrdup(host);
208 fwd->host_port = host_port;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000209}
210
Damien Miller5428f641999-11-25 11:54:57 +1100211/*
212 * Returns the number of the token pointed to by cp of length len. Never
213 * returns if the token is not known.
214 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000215
Damien Miller4af51302000-04-16 11:18:38 +1000216static OpCodes
Damien Miller95def091999-11-25 00:26:21 +1100217parse_token(const char *cp, const char *filename, int linenum)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000218{
Damien Miller95def091999-11-25 00:26:21 +1100219 unsigned int i;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000220
Damien Miller95def091999-11-25 00:26:21 +1100221 for (i = 0; keywords[i].name; i++)
Damien Miller5428f641999-11-25 11:54:57 +1100222 if (strcasecmp(cp, keywords[i].name) == 0)
Damien Miller95def091999-11-25 00:26:21 +1100223 return keywords[i].opcode;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000224
Damien Miller95def091999-11-25 00:26:21 +1100225 fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
226 filename, linenum, cp);
227 return oBadOption;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000228}
229
Damien Miller5428f641999-11-25 11:54:57 +1100230/*
231 * Processes a single option line as used in the configuration files. This
232 * only sets those values that have not already been set.
233 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000234
Damien Miller2ccf6611999-11-15 15:25:10 +1100235int
236process_config_line(Options *options, const char *host,
Damien Miller95def091999-11-25 00:26:21 +1100237 char *line, const char *filename, int linenum,
238 int *activep)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000239{
Damien Miller37023962000-07-11 17:31:38 +1000240 char buf[256], *s, *string, **charptr, *endofnumber, *keyword, *arg;
Damien Milleraae6c611999-12-06 11:47:28 +1100241 int opcode, *intptr, value;
242 u_short fwd_port, fwd_host_port;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000243
Damien Miller95def091999-11-25 00:26:21 +1100244 /* Skip leading whitespace. */
Damien Miller37023962000-07-11 17:31:38 +1000245 s = line + strspn(line, WHITESPACE);
246 if (!*s || *s == '\n' || *s == '#')
Damien Miller95def091999-11-25 00:26:21 +1100247 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000248
Damien Miller5428f641999-11-25 11:54:57 +1100249 /* Get the keyword. (Each line is supposed to begin with a keyword). */
Damien Miller37023962000-07-11 17:31:38 +1000250 keyword = strsep(&s, WHITESPACE);
251 opcode = parse_token(keyword, filename, linenum);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000252
Damien Miller95def091999-11-25 00:26:21 +1100253 switch (opcode) {
254 case oBadOption:
Damien Miller5428f641999-11-25 11:54:57 +1100255 /* don't panic, but count bad options */
256 return -1;
Damien Miller95def091999-11-25 00:26:21 +1100257 /* NOTREACHED */
258 case oForwardAgent:
259 intptr = &options->forward_agent;
260parse_flag:
Damien Miller37023962000-07-11 17:31:38 +1000261 arg = strsep(&s, WHITESPACE);
262 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100263 fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
264 value = 0; /* To avoid compiler warning... */
Damien Miller37023962000-07-11 17:31:38 +1000265 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
Damien Miller95def091999-11-25 00:26:21 +1100266 value = 1;
Damien Miller37023962000-07-11 17:31:38 +1000267 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
Damien Miller95def091999-11-25 00:26:21 +1100268 value = 0;
269 else
270 fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
271 if (*activep && *intptr == -1)
272 *intptr = value;
273 break;
274
275 case oForwardX11:
276 intptr = &options->forward_x11;
277 goto parse_flag;
278
279 case oGatewayPorts:
280 intptr = &options->gateway_ports;
281 goto parse_flag;
282
283 case oUsePrivilegedPort:
284 intptr = &options->use_privileged_port;
285 goto parse_flag;
286
287 case oRhostsAuthentication:
288 intptr = &options->rhosts_authentication;
289 goto parse_flag;
290
291 case oPasswordAuthentication:
292 intptr = &options->password_authentication;
293 goto parse_flag;
294
Damien Millere247cc42000-05-07 12:03:14 +1000295 case oDSAAuthentication:
296 intptr = &options->dsa_authentication;
297 goto parse_flag;
298
Damien Miller95def091999-11-25 00:26:21 +1100299 case oRSAAuthentication:
300 intptr = &options->rsa_authentication;
301 goto parse_flag;
302
303 case oRhostsRSAAuthentication:
304 intptr = &options->rhosts_rsa_authentication;
305 goto parse_flag;
306
307 case oTISAuthentication:
308 /* fallthrough, there is no difference on the client side */
309 case oSkeyAuthentication:
310 intptr = &options->skey_authentication;
311 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000312
313#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100314 case oKerberosAuthentication:
315 intptr = &options->kerberos_authentication;
316 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000317#endif /* KRB4 */
318
319#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100320 case oKerberosTgtPassing:
321 intptr = &options->kerberos_tgt_passing;
322 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000323
Damien Miller95def091999-11-25 00:26:21 +1100324 case oAFSTokenPassing:
325 intptr = &options->afs_token_passing;
326 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000327#endif
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000328
Damien Miller95def091999-11-25 00:26:21 +1100329 case oFallBackToRsh:
330 intptr = &options->fallback_to_rsh;
331 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000332
Damien Miller95def091999-11-25 00:26:21 +1100333 case oUseRsh:
334 intptr = &options->use_rsh;
335 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000336
Damien Miller95def091999-11-25 00:26:21 +1100337 case oBatchMode:
338 intptr = &options->batch_mode;
339 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000340
Damien Miller95def091999-11-25 00:26:21 +1100341 case oCheckHostIP:
342 intptr = &options->check_host_ip;
343 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000344
Damien Miller95def091999-11-25 00:26:21 +1100345 case oStrictHostKeyChecking:
346 intptr = &options->strict_host_key_checking;
Damien Miller37023962000-07-11 17:31:38 +1000347 arg = strsep(&s, WHITESPACE);
348 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100349 fatal("%.200s line %d: Missing yes/no argument.",
350 filename, linenum);
351 value = 0; /* To avoid compiler warning... */
Damien Miller37023962000-07-11 17:31:38 +1000352 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
Damien Miller95def091999-11-25 00:26:21 +1100353 value = 1;
Damien Miller37023962000-07-11 17:31:38 +1000354 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
Damien Miller95def091999-11-25 00:26:21 +1100355 value = 0;
Damien Miller37023962000-07-11 17:31:38 +1000356 else if (strcmp(arg, "ask") == 0)
Damien Miller95def091999-11-25 00:26:21 +1100357 value = 2;
358 else
359 fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
360 if (*activep && *intptr == -1)
361 *intptr = value;
362 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000363
Damien Miller95def091999-11-25 00:26:21 +1100364 case oCompression:
365 intptr = &options->compression;
366 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000367
Damien Miller95def091999-11-25 00:26:21 +1100368 case oKeepAlives:
369 intptr = &options->keepalives;
370 goto parse_flag;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000371
Damien Miller95def091999-11-25 00:26:21 +1100372 case oNumberOfPasswordPrompts:
373 intptr = &options->number_of_password_prompts;
374 goto parse_int;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000375
Damien Miller95def091999-11-25 00:26:21 +1100376 case oCompressionLevel:
377 intptr = &options->compression_level;
378 goto parse_int;
379
380 case oIdentityFile:
Damien Millereba71ba2000-04-29 23:57:08 +1000381 case oIdentityFile2:
Damien Miller37023962000-07-11 17:31:38 +1000382 arg = strsep(&s, WHITESPACE);
383 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100384 fatal("%.200s line %d: Missing argument.", filename, linenum);
385 if (*activep) {
Damien Millereba71ba2000-04-29 23:57:08 +1000386 intptr = (opcode == oIdentityFile) ?
387 &options->num_identity_files :
388 &options->num_identity_files2;
389 if (*intptr >= SSH_MAX_IDENTITY_FILES)
Damien Miller95def091999-11-25 00:26:21 +1100390 fatal("%.200s line %d: Too many identity files specified (max %d).",
391 filename, linenum, SSH_MAX_IDENTITY_FILES);
Damien Millereba71ba2000-04-29 23:57:08 +1000392 charptr = (opcode == oIdentityFile) ?
393 &options->identity_files[*intptr] :
394 &options->identity_files2[*intptr];
Damien Miller37023962000-07-11 17:31:38 +1000395 *charptr = xstrdup(arg);
Damien Millereba71ba2000-04-29 23:57:08 +1000396 *intptr = *intptr + 1;
Damien Miller95def091999-11-25 00:26:21 +1100397 }
398 break;
399
Damien Millerd3a18572000-06-07 19:55:44 +1000400 case oXAuthLocation:
401 charptr=&options->xauth_location;
402 goto parse_string;
403
Damien Miller95def091999-11-25 00:26:21 +1100404 case oUser:
405 charptr = &options->user;
406parse_string:
Damien Miller37023962000-07-11 17:31:38 +1000407 arg = strsep(&s, WHITESPACE);
408 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100409 fatal("%.200s line %d: Missing argument.", filename, linenum);
410 if (*activep && *charptr == NULL)
Damien Miller37023962000-07-11 17:31:38 +1000411 *charptr = xstrdup(arg);
Damien Miller95def091999-11-25 00:26:21 +1100412 break;
413
414 case oGlobalKnownHostsFile:
415 charptr = &options->system_hostfile;
416 goto parse_string;
417
418 case oUserKnownHostsFile:
419 charptr = &options->user_hostfile;
420 goto parse_string;
421
Damien Millereba71ba2000-04-29 23:57:08 +1000422 case oGlobalKnownHostsFile2:
423 charptr = &options->system_hostfile2;
424 goto parse_string;
425
426 case oUserKnownHostsFile2:
427 charptr = &options->user_hostfile2;
428 goto parse_string;
429
Damien Miller95def091999-11-25 00:26:21 +1100430 case oHostName:
431 charptr = &options->hostname;
432 goto parse_string;
433
434 case oProxyCommand:
435 charptr = &options->proxy_command;
436 string = xstrdup("");
Damien Miller37023962000-07-11 17:31:38 +1000437 while ((arg = strsep(&s, WHITESPACE)) != NULL && *arg != '\0') {
438 string = xrealloc(string, strlen(string) + strlen(arg) + 2);
Damien Miller95def091999-11-25 00:26:21 +1100439 strcat(string, " ");
Damien Miller37023962000-07-11 17:31:38 +1000440 strcat(string, arg);
Damien Miller95def091999-11-25 00:26:21 +1100441 }
442 if (*activep && *charptr == NULL)
443 *charptr = string;
444 else
445 xfree(string);
446 return 0;
447
448 case oPort:
449 intptr = &options->port;
450parse_int:
Damien Miller37023962000-07-11 17:31:38 +1000451 arg = strsep(&s, WHITESPACE);
452 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100453 fatal("%.200s line %d: Missing argument.", filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000454 if (arg[0] < '0' || arg[0] > '9')
Damien Miller95def091999-11-25 00:26:21 +1100455 fatal("%.200s line %d: Bad number.", filename, linenum);
Damien Miller5428f641999-11-25 11:54:57 +1100456
457 /* Octal, decimal, or hex format? */
Damien Miller37023962000-07-11 17:31:38 +1000458 value = strtol(arg, &endofnumber, 0);
459 if (arg == endofnumber)
Damien Miller5428f641999-11-25 11:54:57 +1100460 fatal("%.200s line %d: Bad number.", filename, linenum);
Damien Miller95def091999-11-25 00:26:21 +1100461 if (*activep && *intptr == -1)
462 *intptr = value;
463 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000464
Damien Miller95def091999-11-25 00:26:21 +1100465 case oConnectionAttempts:
466 intptr = &options->connection_attempts;
467 goto parse_int;
Damien Miller5ce662a1999-11-11 17:57:39 +1100468
Damien Miller95def091999-11-25 00:26:21 +1100469 case oCipher:
470 intptr = &options->cipher;
Damien Miller37023962000-07-11 17:31:38 +1000471 arg = strsep(&s, WHITESPACE);
472 if (!arg || *arg == '\0')
Damien Millerb1715dc2000-05-30 13:44:51 +1000473 fatal("%.200s line %d: Missing argument.", filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000474 value = cipher_number(arg);
Damien Miller95def091999-11-25 00:26:21 +1100475 if (value == -1)
476 fatal("%.200s line %d: Bad cipher '%s'.",
Damien Miller37023962000-07-11 17:31:38 +1000477 filename, linenum, arg ? arg : "<NONE>");
Damien Miller95def091999-11-25 00:26:21 +1100478 if (*activep && *intptr == -1)
479 *intptr = value;
480 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000481
Damien Miller78928792000-04-12 20:17:38 +1000482 case oCiphers:
Damien Miller37023962000-07-11 17:31:38 +1000483 arg = strsep(&s, WHITESPACE);
484 if (!arg || *arg == '\0')
Damien Millerb1715dc2000-05-30 13:44:51 +1000485 fatal("%.200s line %d: Missing argument.", filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000486 if (!ciphers_valid(arg))
Damien Miller30c3d422000-05-09 11:02:59 +1000487 fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
Damien Miller37023962000-07-11 17:31:38 +1000488 filename, linenum, arg ? arg : "<NONE>");
Damien Miller78928792000-04-12 20:17:38 +1000489 if (*activep && options->ciphers == NULL)
Damien Miller37023962000-07-11 17:31:38 +1000490 options->ciphers = xstrdup(arg);
Damien Miller78928792000-04-12 20:17:38 +1000491 break;
492
493 case oProtocol:
494 intptr = &options->protocol;
Damien Miller37023962000-07-11 17:31:38 +1000495 arg = strsep(&s, WHITESPACE);
496 if (!arg || *arg == '\0')
Damien Millerb1715dc2000-05-30 13:44:51 +1000497 fatal("%.200s line %d: Missing argument.", filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000498 value = proto_spec(arg);
Damien Miller78928792000-04-12 20:17:38 +1000499 if (value == SSH_PROTO_UNKNOWN)
500 fatal("%.200s line %d: Bad protocol spec '%s'.",
Damien Miller37023962000-07-11 17:31:38 +1000501 filename, linenum, arg ? arg : "<NONE>");
Damien Miller78928792000-04-12 20:17:38 +1000502 if (*activep && *intptr == SSH_PROTO_UNKNOWN)
503 *intptr = value;
504 break;
505
Damien Miller95def091999-11-25 00:26:21 +1100506 case oLogLevel:
507 intptr = (int *) &options->log_level;
Damien Miller37023962000-07-11 17:31:38 +1000508 arg = strsep(&s, WHITESPACE);
509 value = log_level_number(arg);
Damien Miller95def091999-11-25 00:26:21 +1100510 if (value == (LogLevel) - 1)
511 fatal("%.200s line %d: unsupported log level '%s'\n",
Damien Miller37023962000-07-11 17:31:38 +1000512 filename, linenum, arg ? arg : "<NONE>");
Damien Miller95def091999-11-25 00:26:21 +1100513 if (*activep && (LogLevel) * intptr == -1)
514 *intptr = (LogLevel) value;
515 break;
516
517 case oRemoteForward:
Damien Miller37023962000-07-11 17:31:38 +1000518 arg = strsep(&s, WHITESPACE);
519 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100520 fatal("%.200s line %d: Missing argument.", filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000521 if (arg[0] < '0' || arg[0] > '9')
Damien Miller95def091999-11-25 00:26:21 +1100522 fatal("%.200s line %d: Badly formatted port number.",
523 filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000524 fwd_port = atoi(arg);
525 arg = strsep(&s, WHITESPACE);
526 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100527 fatal("%.200s line %d: Missing second argument.",
528 filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000529 if (sscanf(arg, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
Damien Miller95def091999-11-25 00:26:21 +1100530 fatal("%.200s line %d: Badly formatted host:port.",
531 filename, linenum);
532 if (*activep)
533 add_remote_forward(options, fwd_port, buf, fwd_host_port);
534 break;
535
536 case oLocalForward:
Damien Miller37023962000-07-11 17:31:38 +1000537 arg = strsep(&s, WHITESPACE);
538 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100539 fatal("%.200s line %d: Missing argument.", filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000540 if (arg[0] < '0' || arg[0] > '9')
Damien Miller95def091999-11-25 00:26:21 +1100541 fatal("%.200s line %d: Badly formatted port number.",
542 filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000543 fwd_port = atoi(arg);
544 arg = strsep(&s, WHITESPACE);
545 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100546 fatal("%.200s line %d: Missing second argument.",
547 filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000548 if (sscanf(arg, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
Damien Miller95def091999-11-25 00:26:21 +1100549 fatal("%.200s line %d: Badly formatted host:port.",
550 filename, linenum);
551 if (*activep)
552 add_local_forward(options, fwd_port, buf, fwd_host_port);
553 break;
554
555 case oHost:
556 *activep = 0;
Damien Miller37023962000-07-11 17:31:38 +1000557 while ((arg = strsep(&s, WHITESPACE)) != NULL && *arg != '\0')
558 if (match_pattern(host, arg)) {
559 debug("Applying options for %.100s", arg);
Damien Miller95def091999-11-25 00:26:21 +1100560 *activep = 1;
561 break;
562 }
Damien Miller37023962000-07-11 17:31:38 +1000563 /* Avoid garbage check below, as strsep is done. */
Damien Miller95def091999-11-25 00:26:21 +1100564 return 0;
565
566 case oEscapeChar:
567 intptr = &options->escape_char;
Damien Miller37023962000-07-11 17:31:38 +1000568 arg = strsep(&s, WHITESPACE);
569 if (!arg || *arg == '\0')
Damien Miller95def091999-11-25 00:26:21 +1100570 fatal("%.200s line %d: Missing argument.", filename, linenum);
Damien Miller37023962000-07-11 17:31:38 +1000571 if (arg[0] == '^' && arg[2] == 0 &&
572 (unsigned char) arg[1] >= 64 && (unsigned char) arg[1] < 128)
573 value = (unsigned char) arg[1] & 31;
574 else if (strlen(arg) == 1)
575 value = (unsigned char) arg[0];
576 else if (strcmp(arg, "none") == 0)
Damien Miller95def091999-11-25 00:26:21 +1100577 value = -2;
578 else {
579 fatal("%.200s line %d: Bad escape character.",
580 filename, linenum);
581 /* NOTREACHED */
582 value = 0; /* Avoid compiler warning. */
583 }
584 if (*activep && *intptr == -1)
585 *intptr = value;
586 break;
587
588 default:
589 fatal("process_config_line: Unimplemented opcode %d", opcode);
590 }
591
592 /* Check that there is no garbage at end of line. */
Damien Miller37023962000-07-11 17:31:38 +1000593 if ((arg = strsep(&s, WHITESPACE)) != NULL && *arg != '\0')
594 {
595 fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
596 filename, linenum, arg);
597 }
Damien Miller95def091999-11-25 00:26:21 +1100598 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000599}
600
601
Damien Miller5428f641999-11-25 11:54:57 +1100602/*
603 * Reads the config file and modifies the options accordingly. Options
604 * should already be initialized before this call. This never returns if
605 * there is an error. If the file does not exist, this returns immediately.
606 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000607
Damien Miller4af51302000-04-16 11:18:38 +1000608void
Damien Miller95def091999-11-25 00:26:21 +1100609read_config_file(const char *filename, const char *host, Options *options)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000610{
Damien Miller95def091999-11-25 00:26:21 +1100611 FILE *f;
612 char line[1024];
613 int active, linenum;
614 int bad_options = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000615
Damien Miller95def091999-11-25 00:26:21 +1100616 /* Open the file. */
617 f = fopen(filename, "r");
618 if (!f)
619 return;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000620
Damien Miller95def091999-11-25 00:26:21 +1100621 debug("Reading configuration data %.200s", filename);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000622
Damien Miller5428f641999-11-25 11:54:57 +1100623 /*
624 * Mark that we are now processing the options. This flag is turned
625 * on/off by Host specifications.
626 */
Damien Miller95def091999-11-25 00:26:21 +1100627 active = 1;
628 linenum = 0;
629 while (fgets(line, sizeof(line), f)) {
630 /* Update line number counter. */
631 linenum++;
632 if (process_config_line(options, host, line, filename, linenum, &active) != 0)
633 bad_options++;
634 }
635 fclose(f);
636 if (bad_options > 0)
637 fatal("%s: terminating, %d bad configuration options\n",
638 filename, bad_options);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000639}
640
Damien Miller5428f641999-11-25 11:54:57 +1100641/*
642 * Initializes options to special values that indicate that they have not yet
643 * been set. Read_config_file will only set options with this value. Options
644 * are processed in the following order: command line, user config file,
645 * system config file. Last, fill_default_options is called.
646 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000647
Damien Miller4af51302000-04-16 11:18:38 +1000648void
Damien Miller95def091999-11-25 00:26:21 +1100649initialize_options(Options * options)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000650{
Damien Miller95def091999-11-25 00:26:21 +1100651 memset(options, 'X', sizeof(*options));
652 options->forward_agent = -1;
653 options->forward_x11 = -1;
Damien Millerd3a18572000-06-07 19:55:44 +1000654 options->xauth_location = NULL;
Damien Miller95def091999-11-25 00:26:21 +1100655 options->gateway_ports = -1;
656 options->use_privileged_port = -1;
657 options->rhosts_authentication = -1;
658 options->rsa_authentication = -1;
Damien Millere247cc42000-05-07 12:03:14 +1000659 options->dsa_authentication = -1;
Damien Miller95def091999-11-25 00:26:21 +1100660 options->skey_authentication = -1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000661#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100662 options->kerberos_authentication = -1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000663#endif
664#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100665 options->kerberos_tgt_passing = -1;
666 options->afs_token_passing = -1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000667#endif
Damien Miller95def091999-11-25 00:26:21 +1100668 options->password_authentication = -1;
669 options->rhosts_rsa_authentication = -1;
670 options->fallback_to_rsh = -1;
671 options->use_rsh = -1;
672 options->batch_mode = -1;
673 options->check_host_ip = -1;
674 options->strict_host_key_checking = -1;
675 options->compression = -1;
676 options->keepalives = -1;
677 options->compression_level = -1;
678 options->port = -1;
679 options->connection_attempts = -1;
680 options->number_of_password_prompts = -1;
681 options->cipher = -1;
Damien Miller78928792000-04-12 20:17:38 +1000682 options->ciphers = NULL;
683 options->protocol = SSH_PROTO_UNKNOWN;
Damien Miller95def091999-11-25 00:26:21 +1100684 options->num_identity_files = 0;
Damien Millereba71ba2000-04-29 23:57:08 +1000685 options->num_identity_files2 = 0;
Damien Miller95def091999-11-25 00:26:21 +1100686 options->hostname = NULL;
687 options->proxy_command = NULL;
688 options->user = NULL;
689 options->escape_char = -1;
690 options->system_hostfile = NULL;
691 options->user_hostfile = NULL;
Damien Millereba71ba2000-04-29 23:57:08 +1000692 options->system_hostfile2 = NULL;
693 options->user_hostfile2 = NULL;
Damien Miller95def091999-11-25 00:26:21 +1100694 options->num_local_forwards = 0;
695 options->num_remote_forwards = 0;
696 options->log_level = (LogLevel) - 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000697}
698
Damien Miller5428f641999-11-25 11:54:57 +1100699/*
700 * Called after processing other sources of option data, this fills those
701 * options for which no value has been specified with their default values.
702 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000703
Damien Miller4af51302000-04-16 11:18:38 +1000704void
Damien Miller95def091999-11-25 00:26:21 +1100705fill_default_options(Options * options)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000706{
Damien Miller95def091999-11-25 00:26:21 +1100707 if (options->forward_agent == -1)
Damien Millerb1715dc2000-05-30 13:44:51 +1000708 options->forward_agent = 0;
Damien Miller95def091999-11-25 00:26:21 +1100709 if (options->forward_x11 == -1)
Damien Miller98c7ad62000-03-09 21:27:49 +1100710 options->forward_x11 = 0;
Damien Millerd3a18572000-06-07 19:55:44 +1000711#ifdef XAUTH_PATH
712 if (options->xauth_location == NULL)
713 options->xauth_location = XAUTH_PATH;
714#endif /* XAUTH_PATH */
Damien Miller95def091999-11-25 00:26:21 +1100715 if (options->gateway_ports == -1)
716 options->gateway_ports = 0;
717 if (options->use_privileged_port == -1)
718 options->use_privileged_port = 1;
719 if (options->rhosts_authentication == -1)
720 options->rhosts_authentication = 1;
721 if (options->rsa_authentication == -1)
722 options->rsa_authentication = 1;
Damien Millere247cc42000-05-07 12:03:14 +1000723 if (options->dsa_authentication == -1)
724 options->dsa_authentication = 1;
Damien Miller95def091999-11-25 00:26:21 +1100725 if (options->skey_authentication == -1)
726 options->skey_authentication = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000727#ifdef KRB4
Damien Miller95def091999-11-25 00:26:21 +1100728 if (options->kerberos_authentication == -1)
729 options->kerberos_authentication = 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000730#endif /* KRB4 */
731#ifdef AFS
Damien Miller95def091999-11-25 00:26:21 +1100732 if (options->kerberos_tgt_passing == -1)
733 options->kerberos_tgt_passing = 1;
734 if (options->afs_token_passing == -1)
735 options->afs_token_passing = 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000736#endif /* AFS */
Damien Miller95def091999-11-25 00:26:21 +1100737 if (options->password_authentication == -1)
738 options->password_authentication = 1;
739 if (options->rhosts_rsa_authentication == -1)
740 options->rhosts_rsa_authentication = 1;
741 if (options->fallback_to_rsh == -1)
742 options->fallback_to_rsh = 1;
743 if (options->use_rsh == -1)
744 options->use_rsh = 0;
745 if (options->batch_mode == -1)
746 options->batch_mode = 0;
747 if (options->check_host_ip == -1)
748 options->check_host_ip = 1;
749 if (options->strict_host_key_checking == -1)
750 options->strict_host_key_checking = 2; /* 2 is default */
751 if (options->compression == -1)
752 options->compression = 0;
753 if (options->keepalives == -1)
754 options->keepalives = 1;
755 if (options->compression_level == -1)
756 options->compression_level = 6;
757 if (options->port == -1)
758 options->port = 0; /* Filled in ssh_connect. */
759 if (options->connection_attempts == -1)
760 options->connection_attempts = 4;
761 if (options->number_of_password_prompts == -1)
762 options->number_of_password_prompts = 3;
763 /* Selected in ssh_login(). */
764 if (options->cipher == -1)
765 options->cipher = SSH_CIPHER_NOT_SET;
Damien Miller30c3d422000-05-09 11:02:59 +1000766 /* options->ciphers, default set in myproposals.h */
Damien Miller78928792000-04-12 20:17:38 +1000767 if (options->protocol == SSH_PROTO_UNKNOWN)
Damien Millereba71ba2000-04-29 23:57:08 +1000768 options->protocol = SSH_PROTO_1|SSH_PROTO_2|SSH_PROTO_1_PREFERRED;
Damien Miller95def091999-11-25 00:26:21 +1100769 if (options->num_identity_files == 0) {
770 options->identity_files[0] =
771 xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
772 sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
773 options->num_identity_files = 1;
774 }
Damien Millereba71ba2000-04-29 23:57:08 +1000775 if (options->num_identity_files2 == 0) {
776 options->identity_files2[0] =
Damien Millere247cc42000-05-07 12:03:14 +1000777 xmalloc(2 + strlen(SSH_CLIENT_ID_DSA) + 1);
778 sprintf(options->identity_files2[0], "~/%.100s", SSH_CLIENT_ID_DSA);
Damien Millereba71ba2000-04-29 23:57:08 +1000779 options->num_identity_files2 = 1;
780 }
Damien Miller95def091999-11-25 00:26:21 +1100781 if (options->escape_char == -1)
782 options->escape_char = '~';
783 if (options->system_hostfile == NULL)
784 options->system_hostfile = SSH_SYSTEM_HOSTFILE;
785 if (options->user_hostfile == NULL)
786 options->user_hostfile = SSH_USER_HOSTFILE;
Damien Millereba71ba2000-04-29 23:57:08 +1000787 if (options->system_hostfile2 == NULL)
788 options->system_hostfile2 = SSH_SYSTEM_HOSTFILE2;
789 if (options->user_hostfile2 == NULL)
790 options->user_hostfile2 = SSH_USER_HOSTFILE2;
Damien Miller95def091999-11-25 00:26:21 +1100791 if (options->log_level == (LogLevel) - 1)
792 options->log_level = SYSLOG_LEVEL_INFO;
793 /* options->proxy_command should not be set by default */
794 /* options->user will be set in the main program if appropriate */
795 /* options->hostname will be set in the main program if appropriate */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000796}