Branch data Line data Source code
1 : : /* $OpenBSD: readconf.c,v 1.218 2014/02/23 20:11:36 djm Exp $ */
2 : : /*
3 : : * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 : : * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 : : * All rights reserved
6 : : * Functions for reading the configuration files.
7 : : *
8 : : * As far as I am concerned, the code I have written for this software
9 : : * can be used freely for any purpose. Any derived versions of this
10 : : * software must be clearly marked as such, and if the derived work is
11 : : * incompatible with the protocol description in the RFC file, it must be
12 : : * called by a name other than "ssh" or "Secure Shell".
13 : : */
14 : :
15 : : #include "includes.h"
16 : :
17 : : #include <sys/types.h>
18 : : #include <sys/stat.h>
19 : : #include <sys/socket.h>
20 : : #include <sys/wait.h>
21 : :
22 : : #include <netinet/in.h>
23 : : #include <netinet/in_systm.h>
24 : : #include <netinet/ip.h>
25 : : #include <arpa/inet.h>
26 : :
27 : : #include <ctype.h>
28 : : #include <errno.h>
29 : : #include <fcntl.h>
30 : : #include <netdb.h>
31 : : #ifdef HAVE_PATHS_H
32 : : # include <paths.h>
33 : : #endif
34 : : #include <pwd.h>
35 : : #include <signal.h>
36 : : #include <stdarg.h>
37 : : #include <stdio.h>
38 : : #include <string.h>
39 : : #include <unistd.h>
40 : : #ifdef HAVE_UTIL_H
41 : : #include <util.h>
42 : : #endif
43 : :
44 : : #include "xmalloc.h"
45 : : #include "ssh.h"
46 : : #include "compat.h"
47 : : #include "cipher.h"
48 : : #include "pathnames.h"
49 : : #include "log.h"
50 : : #include "key.h"
51 : : #include "readconf.h"
52 : : #include "match.h"
53 : : #include "misc.h"
54 : : #include "buffer.h"
55 : : #include "kex.h"
56 : : #include "mac.h"
57 : : #include "uidswap.h"
58 : :
59 : : /* Format of the configuration file:
60 : :
61 : : # Configuration data is parsed as follows:
62 : : # 1. command line options
63 : : # 2. user-specific file
64 : : # 3. system-wide file
65 : : # Any configuration value is only changed the first time it is set.
66 : : # Thus, host-specific definitions should be at the beginning of the
67 : : # configuration file, and defaults at the end.
68 : :
69 : : # Host-specific declarations. These may override anything above. A single
70 : : # host may match multiple declarations; these are processed in the order
71 : : # that they are given in.
72 : :
73 : : Host *.ngs.fi ngs.fi
74 : : User foo
75 : :
76 : : Host fake.com
77 : : HostName another.host.name.real.org
78 : : User blaah
79 : : Port 34289
80 : : ForwardX11 no
81 : : ForwardAgent no
82 : :
83 : : Host books.com
84 : : RemoteForward 9999 shadows.cs.hut.fi:9999
85 : : Cipher 3des
86 : :
87 : : Host fascist.blob.com
88 : : Port 23123
89 : : User tylonen
90 : : PasswordAuthentication no
91 : :
92 : : Host puukko.hut.fi
93 : : User t35124p
94 : : ProxyCommand ssh-proxy %h %p
95 : :
96 : : Host *.fr
97 : : PublicKeyAuthentication no
98 : :
99 : : Host *.su
100 : : Cipher none
101 : : PasswordAuthentication no
102 : :
103 : : Host vpn.fake.com
104 : : Tunnel yes
105 : : TunnelDevice 3
106 : :
107 : : # Defaults for various options
108 : : Host *
109 : : ForwardAgent no
110 : : ForwardX11 no
111 : : PasswordAuthentication yes
112 : : RSAAuthentication yes
113 : : RhostsRSAAuthentication yes
114 : : StrictHostKeyChecking yes
115 : : TcpKeepAlive no
116 : : IdentityFile ~/.ssh/identity
117 : : Port 22
118 : : EscapeChar ~
119 : :
120 : : */
121 : :
122 : : /* Keyword tokens. */
123 : :
124 : : typedef enum {
125 : : oBadOption,
126 : : oHost, oMatch,
127 : : oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
128 : : oGatewayPorts, oExitOnForwardFailure,
129 : : oPasswordAuthentication, oRSAAuthentication,
130 : : oChallengeResponseAuthentication, oXAuthLocation,
131 : : oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
132 : : oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
133 : : oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
134 : : oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
135 : : oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
136 : : oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
137 : : oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
138 : : oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
139 : : oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
140 : : oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
141 : : oClearAllForwardings, oNoHostAuthenticationForLocalhost,
142 : : oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
143 : : oAddressFamily, oGssAuthentication, oGssDelegateCreds,
144 : : oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
145 : : oSendEnv, oControlPath, oControlMaster, oControlPersist,
146 : : oHashKnownHosts,
147 : : oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
148 : : oVisualHostKey, oUseRoaming,
149 : : oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
150 : : oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
151 : : oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
152 : : oIgnoredUnknownOption, oDeprecated, oUnsupported
153 : : } OpCodes;
154 : :
155 : : /* Textual representations of the tokens. */
156 : :
157 : : static struct {
158 : : const char *name;
159 : : OpCodes opcode;
160 : : } keywords[] = {
161 : : { "forwardagent", oForwardAgent },
162 : : { "forwardx11", oForwardX11 },
163 : : { "forwardx11trusted", oForwardX11Trusted },
164 : : { "forwardx11timeout", oForwardX11Timeout },
165 : : { "exitonforwardfailure", oExitOnForwardFailure },
166 : : { "xauthlocation", oXAuthLocation },
167 : : { "gatewayports", oGatewayPorts },
168 : : { "useprivilegedport", oUsePrivilegedPort },
169 : : { "rhostsauthentication", oDeprecated },
170 : : { "passwordauthentication", oPasswordAuthentication },
171 : : { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
172 : : { "kbdinteractivedevices", oKbdInteractiveDevices },
173 : : { "rsaauthentication", oRSAAuthentication },
174 : : { "pubkeyauthentication", oPubkeyAuthentication },
175 : : { "dsaauthentication", oPubkeyAuthentication }, /* alias */
176 : : { "rhostsrsaauthentication", oRhostsRSAAuthentication },
177 : : { "hostbasedauthentication", oHostbasedAuthentication },
178 : : { "challengeresponseauthentication", oChallengeResponseAuthentication },
179 : : { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
180 : : { "tisauthentication", oChallengeResponseAuthentication }, /* alias */
181 : : { "kerberosauthentication", oUnsupported },
182 : : { "kerberostgtpassing", oUnsupported },
183 : : { "afstokenpassing", oUnsupported },
184 : : #if defined(GSSAPI)
185 : : { "gssapiauthentication", oGssAuthentication },
186 : : { "gssapidelegatecredentials", oGssDelegateCreds },
187 : : #else
188 : : { "gssapiauthentication", oUnsupported },
189 : : { "gssapidelegatecredentials", oUnsupported },
190 : : #endif
191 : : { "fallbacktorsh", oDeprecated },
192 : : { "usersh", oDeprecated },
193 : : { "identityfile", oIdentityFile },
194 : : { "identityfile2", oIdentityFile }, /* obsolete */
195 : : { "identitiesonly", oIdentitiesOnly },
196 : : { "hostname", oHostName },
197 : : { "hostkeyalias", oHostKeyAlias },
198 : : { "proxycommand", oProxyCommand },
199 : : { "port", oPort },
200 : : { "cipher", oCipher },
201 : : { "ciphers", oCiphers },
202 : : { "macs", oMacs },
203 : : { "protocol", oProtocol },
204 : : { "remoteforward", oRemoteForward },
205 : : { "localforward", oLocalForward },
206 : : { "user", oUser },
207 : : { "host", oHost },
208 : : { "match", oMatch },
209 : : { "escapechar", oEscapeChar },
210 : : { "globalknownhostsfile", oGlobalKnownHostsFile },
211 : : { "globalknownhostsfile2", oDeprecated },
212 : : { "userknownhostsfile", oUserKnownHostsFile },
213 : : { "userknownhostsfile2", oDeprecated },
214 : : { "connectionattempts", oConnectionAttempts },
215 : : { "batchmode", oBatchMode },
216 : : { "checkhostip", oCheckHostIP },
217 : : { "stricthostkeychecking", oStrictHostKeyChecking },
218 : : { "compression", oCompression },
219 : : { "compressionlevel", oCompressionLevel },
220 : : { "tcpkeepalive", oTCPKeepAlive },
221 : : { "keepalive", oTCPKeepAlive }, /* obsolete */
222 : : { "numberofpasswordprompts", oNumberOfPasswordPrompts },
223 : : { "loglevel", oLogLevel },
224 : : { "dynamicforward", oDynamicForward },
225 : : { "preferredauthentications", oPreferredAuthentications },
226 : : { "hostkeyalgorithms", oHostKeyAlgorithms },
227 : : { "bindaddress", oBindAddress },
228 : : #ifdef ENABLE_PKCS11
229 : : { "smartcarddevice", oPKCS11Provider },
230 : : { "pkcs11provider", oPKCS11Provider },
231 : : #else
232 : : { "smartcarddevice", oUnsupported },
233 : : { "pkcs11provider", oUnsupported },
234 : : #endif
235 : : { "clearallforwardings", oClearAllForwardings },
236 : : { "enablesshkeysign", oEnableSSHKeysign },
237 : : { "verifyhostkeydns", oVerifyHostKeyDNS },
238 : : { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
239 : : { "rekeylimit", oRekeyLimit },
240 : : { "connecttimeout", oConnectTimeout },
241 : : { "addressfamily", oAddressFamily },
242 : : { "serveraliveinterval", oServerAliveInterval },
243 : : { "serveralivecountmax", oServerAliveCountMax },
244 : : { "sendenv", oSendEnv },
245 : : { "controlpath", oControlPath },
246 : : { "controlmaster", oControlMaster },
247 : : { "controlpersist", oControlPersist },
248 : : { "hashknownhosts", oHashKnownHosts },
249 : : { "tunnel", oTunnel },
250 : : { "tunneldevice", oTunnelDevice },
251 : : { "localcommand", oLocalCommand },
252 : : { "permitlocalcommand", oPermitLocalCommand },
253 : : { "visualhostkey", oVisualHostKey },
254 : : { "useroaming", oUseRoaming },
255 : : { "kexalgorithms", oKexAlgorithms },
256 : : { "ipqos", oIPQoS },
257 : : { "requesttty", oRequestTTY },
258 : : { "proxyusefdpass", oProxyUseFdpass },
259 : : { "canonicaldomains", oCanonicalDomains },
260 : : { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
261 : : { "canonicalizehostname", oCanonicalizeHostname },
262 : : { "canonicalizemaxdots", oCanonicalizeMaxDots },
263 : : { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
264 : : { "ignoreunknown", oIgnoreUnknown },
265 : :
266 : : { NULL, oBadOption }
267 : : };
268 : :
269 : : /*
270 : : * Adds a local TCP/IP port forward to options. Never returns if there is an
271 : : * error.
272 : : */
273 : :
274 : : void
275 : 84 : add_local_forward(Options *options, const Forward *newfwd)
276 : : {
277 : : Forward *fwd;
278 : : #ifndef NO_IPPORT_RESERVED_CONCEPT
279 : : extern uid_t original_real_uid;
280 [ - + ][ # # ]: 84 : if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
281 : 0 : fatal("Privileged ports can only be forwarded by root.");
282 : : #endif
283 : 84 : options->local_forwards = xrealloc(options->local_forwards,
284 : 84 : options->num_local_forwards + 1,
285 : : sizeof(*options->local_forwards));
286 : 84 : fwd = &options->local_forwards[options->num_local_forwards++];
287 : :
288 : 84 : fwd->listen_host = newfwd->listen_host;
289 : 84 : fwd->listen_port = newfwd->listen_port;
290 : 84 : fwd->connect_host = newfwd->connect_host;
291 : 84 : fwd->connect_port = newfwd->connect_port;
292 : 84 : }
293 : :
294 : : /*
295 : : * Adds a remote TCP/IP port forward to options. Never returns if there is
296 : : * an error.
297 : : */
298 : :
299 : : void
300 : 73 : add_remote_forward(Options *options, const Forward *newfwd)
301 : : {
302 : : Forward *fwd;
303 : :
304 : 73 : options->remote_forwards = xrealloc(options->remote_forwards,
305 : 73 : options->num_remote_forwards + 1,
306 : : sizeof(*options->remote_forwards));
307 : 73 : fwd = &options->remote_forwards[options->num_remote_forwards++];
308 : :
309 : 73 : fwd->listen_host = newfwd->listen_host;
310 : 73 : fwd->listen_port = newfwd->listen_port;
311 : 73 : fwd->connect_host = newfwd->connect_host;
312 : 73 : fwd->connect_port = newfwd->connect_port;
313 : 73 : fwd->handle = newfwd->handle;
314 : 73 : fwd->allocated_port = 0;
315 : 73 : }
316 : :
317 : : static void
318 : 8 : clear_forwardings(Options *options)
319 : : {
320 : : int i;
321 : :
322 [ + + ]: 10 : for (i = 0; i < options->num_local_forwards; i++) {
323 : 2 : free(options->local_forwards[i].listen_host);
324 : 2 : free(options->local_forwards[i].connect_host);
325 : : }
326 [ + + ]: 8 : if (options->num_local_forwards > 0) {
327 : 2 : free(options->local_forwards);
328 : 2 : options->local_forwards = NULL;
329 : : }
330 : 8 : options->num_local_forwards = 0;
331 [ + + ]: 10 : for (i = 0; i < options->num_remote_forwards; i++) {
332 : 2 : free(options->remote_forwards[i].listen_host);
333 : 2 : free(options->remote_forwards[i].connect_host);
334 : : }
335 [ + + ]: 8 : if (options->num_remote_forwards > 0) {
336 : 2 : free(options->remote_forwards);
337 : 2 : options->remote_forwards = NULL;
338 : : }
339 : 8 : options->num_remote_forwards = 0;
340 : 8 : options->tun_open = SSH_TUNMODE_NO;
341 : 8 : }
342 : :
343 : : void
344 : 5532 : add_identity_file(Options *options, const char *dir, const char *filename,
345 : : int userprovided)
346 : : {
347 : : char *path;
348 : :
349 [ - + ]: 5532 : if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
350 : 0 : fatal("Too many identity files specified (max %d)",
351 : : SSH_MAX_IDENTITY_FILES);
352 : :
353 [ + - ]: 5532 : if (dir == NULL) /* no dir, filename is absolute */
354 : 5532 : path = xstrdup(filename);
355 : : else
356 : 0 : (void)xasprintf(&path, "%.100s%.100s", dir, filename);
357 : :
358 : 5532 : options->identity_file_userprovided[options->num_identity_files] =
359 : : userprovided;
360 : 5532 : options->identity_files[options->num_identity_files++] = path;
361 : 5532 : }
362 : :
363 : : int
364 : 0 : default_ssh_port(void)
365 : : {
366 : : static int port;
367 : : struct servent *sp;
368 : :
369 [ # # ]: 0 : if (port == 0) {
370 : 0 : sp = getservbyname(SSH_SERVICE_NAME, "tcp");
371 [ # # ][ # # ]: 0 : port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
372 : : }
373 : 0 : return port;
374 : : }
375 : :
376 : : /*
377 : : * Execute a command in a shell.
378 : : * Return its exit status or -1 on abnormal exit.
379 : : */
380 : : static int
381 : 0 : execute_in_shell(const char *cmd)
382 : : {
383 : : char *shell, *command_string;
384 : : pid_t pid;
385 : : int devnull, status;
386 : : extern uid_t original_real_uid;
387 : :
388 [ # # ]: 0 : if ((shell = getenv("SHELL")) == NULL)
389 : 0 : shell = _PATH_BSHELL;
390 : :
391 : : /*
392 : : * Use "exec" to avoid "sh -c" processes on some platforms
393 : : * (e.g. Solaris)
394 : : */
395 : 0 : xasprintf(&command_string, "exec %s", cmd);
396 : :
397 : : /* Need this to redirect subprocess stdin/out */
398 [ # # ]: 0 : if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
399 : 0 : fatal("open(/dev/null): %s", strerror(errno));
400 : :
401 : 0 : debug("Executing command: '%.500s'", cmd);
402 : :
403 : : /* Fork and execute the command. */
404 [ # # ]: 0 : if ((pid = fork()) == 0) {
405 : : char *argv[4];
406 : :
407 : : /* Child. Permanently give up superuser privileges. */
408 : 0 : permanently_drop_suid(original_real_uid);
409 : :
410 : : /* Redirect child stdin and stdout. Leave stderr */
411 [ # # ]: 0 : if (dup2(devnull, STDIN_FILENO) == -1)
412 : 0 : fatal("dup2: %s", strerror(errno));
413 [ # # ]: 0 : if (dup2(devnull, STDOUT_FILENO) == -1)
414 : 0 : fatal("dup2: %s", strerror(errno));
415 [ # # ]: 0 : if (devnull > STDERR_FILENO)
416 : 0 : close(devnull);
417 : 0 : closefrom(STDERR_FILENO + 1);
418 : :
419 : 0 : argv[0] = shell;
420 : 0 : argv[1] = "-c";
421 : 0 : argv[2] = command_string;
422 : 0 : argv[3] = NULL;
423 : :
424 : 0 : execv(argv[0], argv);
425 : 0 : error("Unable to execute '%.100s': %s", cmd, strerror(errno));
426 : : /* Die with signal to make this error apparent to parent. */
427 : 0 : signal(SIGTERM, SIG_DFL);
428 : 0 : kill(getpid(), SIGTERM);
429 : 0 : _exit(1);
430 : : }
431 : : /* Parent. */
432 [ # # ]: 0 : if (pid < 0)
433 : 0 : fatal("%s: fork: %.100s", __func__, strerror(errno));
434 : :
435 : 0 : close(devnull);
436 : 0 : free(command_string);
437 : :
438 [ # # ]: 0 : while (waitpid(pid, &status, 0) == -1) {
439 [ # # ]: 0 : if (errno != EINTR && errno != EAGAIN)
440 : 0 : fatal("%s: waitpid: %s", __func__, strerror(errno));
441 : : }
442 [ # # ]: 0 : if (!WIFEXITED(status)) {
443 : 0 : error("command '%.100s' exited abnormally", cmd);
444 : 0 : return -1;
445 : : }
446 : 0 : debug3("command returned status %d", WEXITSTATUS(status));
447 : 0 : return WEXITSTATUS(status);
448 : : }
449 : :
450 : : /*
451 : : * Parse and execute a Match directive.
452 : : */
453 : : static int
454 : 0 : match_cfg_line(Options *options, char **condition, struct passwd *pw,
455 : : const char *host_arg, const char *filename, int linenum)
456 : : {
457 : 0 : char *arg, *attrib, *cmd, *cp = *condition, *host;
458 : : const char *ruser;
459 : 0 : int r, port, result = 1, attributes = 0;
460 : : size_t len;
461 : : char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
462 : :
463 : : /*
464 : : * Configuration is likely to be incomplete at this point so we
465 : : * must be prepared to use default values.
466 : : */
467 [ # # ]: 0 : port = options->port <= 0 ? default_ssh_port() : options->port;
468 [ # # ]: 0 : ruser = options->user == NULL ? pw->pw_name : options->user;
469 [ # # ]: 0 : if (options->hostname != NULL) {
470 : : /* NB. Please keep in sync with ssh.c:main() */
471 : 0 : host = percent_expand(options->hostname,
472 : : "h", host_arg, (char *)NULL);
473 : : } else
474 : 0 : host = xstrdup(host_arg);
475 : :
476 : 0 : debug3("checking match for '%s' host %s", cp, host);
477 [ # # ][ # # ]: 0 : while ((attrib = strdelim(&cp)) && *attrib != '\0') {
478 : 0 : attributes++;
479 [ # # ]: 0 : if (strcasecmp(attrib, "all") == 0) {
480 [ # # ][ # # ]: 0 : if (attributes != 1 ||
481 [ # # ]: 0 : ((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
482 : 0 : error("'all' cannot be combined with other "
483 : : "Match attributes");
484 : 0 : result = -1;
485 : : goto out;
486 : : }
487 : 0 : *condition = cp;
488 : 0 : result = 1;
489 : : goto out;
490 : : }
491 [ # # ][ # # ]: 0 : if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
492 : 0 : error("Missing Match criteria for %s", attrib);
493 : 0 : result = -1;
494 : : goto out;
495 : : }
496 : 0 : len = strlen(arg);
497 [ # # ]: 0 : if (strcasecmp(attrib, "host") == 0) {
498 [ # # ]: 0 : if (match_hostname(host, arg, len) != 1)
499 : : result = 0;
500 : : else
501 : 0 : debug("%.200s line %d: matched 'Host %.100s' ",
502 : : filename, linenum, host);
503 [ # # ]: 0 : } else if (strcasecmp(attrib, "originalhost") == 0) {
504 [ # # ]: 0 : if (match_hostname(host_arg, arg, len) != 1)
505 : : result = 0;
506 : : else
507 : 0 : debug("%.200s line %d: matched "
508 : : "'OriginalHost %.100s' ",
509 : : filename, linenum, host_arg);
510 [ # # ]: 0 : } else if (strcasecmp(attrib, "user") == 0) {
511 [ # # ]: 0 : if (match_pattern_list(ruser, arg, len, 0) != 1)
512 : : result = 0;
513 : : else
514 : 0 : debug("%.200s line %d: matched 'User %.100s' ",
515 : : filename, linenum, ruser);
516 [ # # ]: 0 : } else if (strcasecmp(attrib, "localuser") == 0) {
517 [ # # ]: 0 : if (match_pattern_list(pw->pw_name, arg, len, 0) != 1)
518 : : result = 0;
519 : : else
520 : 0 : debug("%.200s line %d: matched "
521 : : "'LocalUser %.100s' ",
522 : : filename, linenum, pw->pw_name);
523 [ # # ]: 0 : } else if (strcasecmp(attrib, "exec") == 0) {
524 [ # # ]: 0 : if (gethostname(thishost, sizeof(thishost)) == -1)
525 : 0 : fatal("gethostname: %s", strerror(errno));
526 : 0 : strlcpy(shorthost, thishost, sizeof(shorthost));
527 : 0 : shorthost[strcspn(thishost, ".")] = '\0';
528 : : snprintf(portstr, sizeof(portstr), "%d", port);
529 : :
530 : 0 : cmd = percent_expand(arg,
531 : : "L", shorthost,
532 : : "d", pw->pw_dir,
533 : : "h", host,
534 : : "l", thishost,
535 : : "n", host_arg,
536 : : "p", portstr,
537 : : "r", ruser,
538 : : "u", pw->pw_name,
539 : : (char *)NULL);
540 [ # # ]: 0 : if (result != 1) {
541 : : /* skip execution if prior predicate failed */
542 : 0 : debug("%.200s line %d: skipped exec \"%.100s\"",
543 : : filename, linenum, cmd);
544 : : } else {
545 : 0 : r = execute_in_shell(cmd);
546 [ # # ]: 0 : if (r == -1) {
547 : 0 : fatal("%.200s line %d: match exec "
548 : : "'%.100s' error", filename,
549 : : linenum, cmd);
550 [ # # ]: 0 : } else if (r == 0) {
551 : 0 : debug("%.200s line %d: matched "
552 : : "'exec \"%.100s\"'", filename,
553 : : linenum, cmd);
554 : : } else {
555 : 0 : debug("%.200s line %d: no match "
556 : : "'exec \"%.100s\"'", filename,
557 : : linenum, cmd);
558 : 0 : result = 0;
559 : : }
560 : : }
561 : 0 : free(cmd);
562 : : } else {
563 : 0 : error("Unsupported Match attribute %s", attrib);
564 : 0 : result = -1;
565 : : goto out;
566 : : }
567 : : }
568 [ # # ]: 0 : if (attributes == 0) {
569 : 0 : error("One or more attributes required for Match");
570 : 0 : result = -1;
571 : : goto out;
572 : : }
573 [ # # ]: 0 : debug3("match %sfound", result ? "" : "not ");
574 : 0 : *condition = cp;
575 : : out:
576 : 0 : free(host);
577 : 0 : return result;
578 : : }
579 : :
580 : : /* Check and prepare a domain name: removes trailing '.' and lowercases */
581 : : static void
582 : 0 : valid_domain(char *name, const char *filename, int linenum)
583 : : {
584 : 0 : size_t i, l = strlen(name);
585 : 0 : u_char c, last = '\0';
586 : :
587 [ # # ]: 0 : if (l == 0)
588 : 0 : fatal("%s line %d: empty hostname suffix", filename, linenum);
589 [ # # ]: 0 : if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0]))
590 : 0 : fatal("%s line %d: hostname suffix \"%.100s\" "
591 : : "starts with invalid character", filename, linenum, name);
592 [ # # ]: 0 : for (i = 0; i < l; i++) {
593 : 0 : c = tolower((u_char)name[i]);
594 : 0 : name[i] = (char)c;
595 [ # # ]: 0 : if (last == '.' && c == '.')
596 : 0 : fatal("%s line %d: hostname suffix \"%.100s\" contains "
597 : : "consecutive separators", filename, linenum, name);
598 [ # # ][ # # ]: 0 : if (c != '.' && c != '-' && !isalnum(c) &&
[ # # ]
599 : : c != '_') /* technically invalid, but common */
600 : 0 : fatal("%s line %d: hostname suffix \"%.100s\" contains "
601 : : "invalid characters", filename, linenum, name);
602 : 0 : last = c;
603 : : }
604 [ # # ]: 0 : if (name[l - 1] == '.')
605 : 0 : name[l - 1] = '\0';
606 : 0 : }
607 : :
608 : : /*
609 : : * Returns the number of the token pointed to by cp or oBadOption.
610 : : */
611 : : static OpCodes
612 : 53852 : parse_token(const char *cp, const char *filename, int linenum,
613 : : const char *ignored_unknown)
614 : : {
615 : : int i;
616 : :
617 [ + - ]: 1793153 : for (i = 0; keywords[i].name; i++)
618 [ + + ]: 1793153 : if (strcmp(cp, keywords[i].name) == 0)
619 : 53852 : return keywords[i].opcode;
620 [ # # ][ # # ]: 0 : if (ignored_unknown != NULL && match_pattern_list(cp, ignored_unknown,
621 : 0 : strlen(ignored_unknown), 1) == 1)
622 : : return oIgnoredUnknownOption;
623 : 0 : error("%s: line %d: Bad configuration option: %s",
624 : : filename, linenum, cp);
625 : 0 : return oBadOption;
626 : : }
627 : :
628 : : /* Multistate option parsing */
629 : : struct multistate {
630 : : char *key;
631 : : int value;
632 : : };
633 : : static const struct multistate multistate_flag[] = {
634 : : { "true", 1 },
635 : : { "false", 0 },
636 : : { "yes", 1 },
637 : : { "no", 0 },
638 : : { NULL, -1 }
639 : : };
640 : : static const struct multistate multistate_yesnoask[] = {
641 : : { "true", 1 },
642 : : { "false", 0 },
643 : : { "yes", 1 },
644 : : { "no", 0 },
645 : : { "ask", 2 },
646 : : { NULL, -1 }
647 : : };
648 : : static const struct multistate multistate_addressfamily[] = {
649 : : { "inet", AF_INET },
650 : : { "inet6", AF_INET6 },
651 : : { "any", AF_UNSPEC },
652 : : { NULL, -1 }
653 : : };
654 : : static const struct multistate multistate_controlmaster[] = {
655 : : { "true", SSHCTL_MASTER_YES },
656 : : { "yes", SSHCTL_MASTER_YES },
657 : : { "false", SSHCTL_MASTER_NO },
658 : : { "no", SSHCTL_MASTER_NO },
659 : : { "auto", SSHCTL_MASTER_AUTO },
660 : : { "ask", SSHCTL_MASTER_ASK },
661 : : { "autoask", SSHCTL_MASTER_AUTO_ASK },
662 : : { NULL, -1 }
663 : : };
664 : : static const struct multistate multistate_tunnel[] = {
665 : : { "ethernet", SSH_TUNMODE_ETHERNET },
666 : : { "point-to-point", SSH_TUNMODE_POINTOPOINT },
667 : : { "true", SSH_TUNMODE_DEFAULT },
668 : : { "yes", SSH_TUNMODE_DEFAULT },
669 : : { "false", SSH_TUNMODE_NO },
670 : : { "no", SSH_TUNMODE_NO },
671 : : { NULL, -1 }
672 : : };
673 : : static const struct multistate multistate_requesttty[] = {
674 : : { "true", REQUEST_TTY_YES },
675 : : { "yes", REQUEST_TTY_YES },
676 : : { "false", REQUEST_TTY_NO },
677 : : { "no", REQUEST_TTY_NO },
678 : : { "force", REQUEST_TTY_FORCE },
679 : : { "auto", REQUEST_TTY_AUTO },
680 : : { NULL, -1 }
681 : : };
682 : : static const struct multistate multistate_canonicalizehostname[] = {
683 : : { "true", SSH_CANONICALISE_YES },
684 : : { "false", SSH_CANONICALISE_NO },
685 : : { "yes", SSH_CANONICALISE_YES },
686 : : { "no", SSH_CANONICALISE_NO },
687 : : { "always", SSH_CANONICALISE_ALWAYS },
688 : : { NULL, -1 }
689 : : };
690 : :
691 : : /*
692 : : * Processes a single option line as used in the configuration files. This
693 : : * only sets those values that have not already been set.
694 : : */
695 : : #define WHITESPACE " \t\r\n"
696 : : int
697 : 53852 : process_config_line(Options *options, struct passwd *pw, const char *host,
698 : : char *line, const char *filename, int linenum, int *activep, int userconfig)
699 : : {
700 : : char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
701 : : char **cpptr, fwdarg[256];
702 : 53852 : u_int i, *uintptr, max_entries = 0;
703 : 53852 : int negated, opcode, *intptr, value, value2, cmdline = 0;
704 : : LogLevel *log_level_ptr;
705 : : long long val64;
706 : : size_t len;
707 : : Forward fwd;
708 : : const struct multistate *multistate_ptr;
709 : : struct allowed_cname *cname;
710 : :
711 [ + + ]: 53852 : if (activep == NULL) { /* We are processing a command line directive */
712 : 1290 : cmdline = 1;
713 : 1290 : activep = &cmdline;
714 : : }
715 : :
716 : : /* Strip trailing whitespace */
717 [ + - ]: 106414 : for (len = strlen(line) - 1; len > 0; len--) {
718 [ + + ]: 106414 : if (strchr(WHITESPACE, line[len]) == NULL)
719 : : break;
720 : 52562 : line[len] = '\0';
721 : : }
722 : :
723 : 53852 : s = line;
724 : : /* Get the keyword. (Each line is supposed to begin with a keyword). */
725 [ + - ]: 53852 : if ((keyword = strdelim(&s)) == NULL)
726 : : return 0;
727 : : /* Ignore leading whitespace. */
728 [ + + ]: 53852 : if (*keyword == '\0')
729 : 41864 : keyword = strdelim(&s);
730 [ + - ][ + - ]: 53852 : if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
[ + - ][ + - ]
731 : : return 0;
732 : : /* Match lowercase keyword */
733 : 53852 : lowercase(keyword);
734 : :
735 : 53852 : opcode = parse_token(keyword, filename, linenum,
736 : 53852 : options->ignored_unknown);
737 : :
738 [ + - - + : 53852 : switch (opcode) {
+ - - - +
- + - - +
+ + + + -
- + - - +
+ - - - -
+ + - + +
+ + + - -
- + + + -
+ + + - +
+ + + + -
- - - - +
+ + - - -
- - + + -
- - - - -
- - - - -
- - - - ]
739 : : case oBadOption:
740 : : /* don't panic, but count bad options */
741 : : return -1;
742 : : /* NOTREACHED */
743 : : case oIgnoredUnknownOption:
744 : 0 : debug("%s line %d: Ignored unknown option \"%s\"",
745 : : filename, linenum, keyword);
746 : 0 : return 0;
747 : : case oConnectTimeout:
748 : 0 : intptr = &options->connection_timeout;
749 : : parse_time:
750 : 222 : arg = strdelim(&s);
751 [ + - ][ - + ]: 222 : if (!arg || *arg == '\0')
752 : 0 : fatal("%s line %d: missing time value.",
753 : : filename, linenum);
754 [ - + ]: 222 : if ((value = convtime(arg)) == -1)
755 : 0 : fatal("%s line %d: invalid time value.",
756 : : filename, linenum);
757 [ + - ][ + - ]: 222 : if (*activep && *intptr == -1)
758 : 222 : *intptr = value;
759 : : break;
760 : :
761 : : case oForwardAgent:
762 : 2 : intptr = &options->forward_agent;
763 : : parse_flag:
764 : : multistate_ptr = multistate_flag;
765 : : parse_multistate:
766 : 21139 : arg = strdelim(&s);
767 [ + - ][ + - ]: 21139 : if (!arg || *arg == '\0')
768 : 0 : fatal("%s line %d: missing argument.",
769 : : filename, linenum);
770 : : value = -1;
771 [ + - ]: 73971 : for (i = 0; multistate_ptr[i].key != NULL; i++) {
772 [ + + ]: 73971 : if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
773 : 21139 : value = multistate_ptr[i].value;
774 : 21139 : break;
775 : : }
776 : : }
777 [ - + ]: 21139 : if (value == -1)
778 : 0 : fatal("%s line %d: unsupported option \"%s\".",
779 : : filename, linenum, arg);
780 [ + - ][ + + ]: 21139 : if (*activep && *intptr == -1)
781 : 10651 : *intptr = value;
782 : : break;
783 : :
784 : : case oForwardX11:
785 : 1 : intptr = &options->forward_x11;
786 : 1 : goto parse_flag;
787 : :
788 : : case oForwardX11Trusted:
789 : 0 : intptr = &options->forward_x11_trusted;
790 : 0 : goto parse_flag;
791 : :
792 : : case oForwardX11Timeout:
793 : 0 : intptr = &options->forward_x11_timeout;
794 : 0 : goto parse_time;
795 : :
796 : : case oGatewayPorts:
797 : 0 : intptr = &options->gateway_ports;
798 : 0 : goto parse_flag;
799 : :
800 : : case oExitOnForwardFailure:
801 : 105 : intptr = &options->exit_on_forward_failure;
802 : 105 : goto parse_flag;
803 : :
804 : : case oUsePrivilegedPort:
805 : 0 : intptr = &options->use_privileged_port;
806 : 0 : goto parse_flag;
807 : :
808 : : case oPasswordAuthentication:
809 : 2616 : intptr = &options->password_authentication;
810 : 2616 : goto parse_flag;
811 : :
812 : : case oKbdInteractiveAuthentication:
813 : 0 : intptr = &options->kbd_interactive_authentication;
814 : 0 : goto parse_flag;
815 : :
816 : : case oKbdInteractiveDevices:
817 : 0 : charptr = &options->kbd_interactive_devices;
818 : 0 : goto parse_string;
819 : :
820 : : case oPubkeyAuthentication:
821 : 2616 : intptr = &options->pubkey_authentication;
822 : 2616 : goto parse_flag;
823 : :
824 : : case oRSAAuthentication:
825 : 2616 : intptr = &options->rsa_authentication;
826 : 2616 : goto parse_flag;
827 : :
828 : : case oRhostsRSAAuthentication:
829 : 2616 : intptr = &options->rhosts_rsa_authentication;
830 : 2616 : goto parse_flag;
831 : :
832 : : case oHostbasedAuthentication:
833 : 2616 : intptr = &options->hostbased_authentication;
834 : 2616 : goto parse_flag;
835 : :
836 : : case oChallengeResponseAuthentication:
837 : 2616 : intptr = &options->challenge_response_authentication;
838 : 2616 : goto parse_flag;
839 : :
840 : : case oGssAuthentication:
841 : 0 : intptr = &options->gss_authentication;
842 : 0 : goto parse_flag;
843 : :
844 : : case oGssDelegateCreds:
845 : 0 : intptr = &options->gss_deleg_creds;
846 : 0 : goto parse_flag;
847 : :
848 : : case oBatchMode:
849 : 2616 : intptr = &options->batch_mode;
850 : 2616 : goto parse_flag;
851 : :
852 : : case oCheckHostIP:
853 : 0 : intptr = &options->check_host_ip;
854 : 0 : goto parse_flag;
855 : :
856 : : case oVerifyHostKeyDNS:
857 : 0 : intptr = &options->verify_host_key_dns;
858 : 0 : multistate_ptr = multistate_yesnoask;
859 : 0 : goto parse_multistate;
860 : :
861 : : case oStrictHostKeyChecking:
862 : 2616 : intptr = &options->strict_host_key_checking;
863 : 2616 : multistate_ptr = multistate_yesnoask;
864 : 2616 : goto parse_multistate;
865 : :
866 : : case oCompression:
867 : 85 : intptr = &options->compression;
868 : 85 : goto parse_flag;
869 : :
870 : : case oTCPKeepAlive:
871 : 0 : intptr = &options->tcp_keep_alive;
872 : 0 : goto parse_flag;
873 : :
874 : : case oNoHostAuthenticationForLocalhost:
875 : 0 : intptr = &options->no_host_authentication_for_localhost;
876 : 0 : goto parse_flag;
877 : :
878 : : case oNumberOfPasswordPrompts:
879 : 0 : intptr = &options->number_of_password_prompts;
880 : 0 : goto parse_int;
881 : :
882 : : case oCompressionLevel:
883 : 0 : intptr = &options->compression_level;
884 : 0 : goto parse_int;
885 : :
886 : : case oRekeyLimit:
887 : 79 : arg = strdelim(&s);
888 [ + - ][ - + ]: 79 : if (!arg || *arg == '\0')
889 : 0 : fatal("%.200s line %d: Missing argument.", filename,
890 : : linenum);
891 [ + + ]: 79 : if (strcmp(arg, "default") == 0) {
892 : 4 : val64 = 0;
893 : : } else {
894 [ - + ]: 75 : if (scan_scaled(arg, &val64) == -1)
895 : 0 : fatal("%.200s line %d: Bad number '%s': %s",
896 : 0 : filename, linenum, arg, strerror(errno));
897 : : /* check for too-large or too-small limits */
898 [ - + ]: 75 : if (val64 > UINT_MAX)
899 : 0 : fatal("%.200s line %d: RekeyLimit too large",
900 : : filename, linenum);
901 [ - + ]: 75 : if (val64 != 0 && val64 < 16)
902 : 0 : fatal("%.200s line %d: RekeyLimit too small",
903 : : filename, linenum);
904 : : }
905 [ + - ][ + - ]: 79 : if (*activep && options->rekey_limit == -1)
906 : 79 : options->rekey_limit = (u_int32_t)val64;
907 [ + + ]: 79 : if (s != NULL) { /* optional rekey interval present */
908 [ - + ]: 4 : if (strcmp(s, "none") == 0) {
909 : 0 : (void)strdelim(&s); /* discard */
910 : 0 : break;
911 : : }
912 : 4 : intptr = &options->rekey_interval;
913 : 4 : goto parse_time;
914 : : }
915 : : break;
916 : :
917 : : case oIdentityFile:
918 : 5190 : arg = strdelim(&s);
919 [ + - ][ - + ]: 5190 : if (!arg || *arg == '\0')
920 : 0 : fatal("%.200s line %d: Missing argument.", filename, linenum);
921 [ + - ]: 5190 : if (*activep) {
922 : 5190 : intptr = &options->num_identity_files;
923 [ - + ]: 5190 : if (*intptr >= SSH_MAX_IDENTITY_FILES)
924 : 0 : fatal("%.200s line %d: Too many identity files specified (max %d).",
925 : : filename, linenum, SSH_MAX_IDENTITY_FILES);
926 : 5190 : add_identity_file(options, NULL, arg, userconfig);
927 : : }
928 : : break;
929 : :
930 : : case oXAuthLocation:
931 : 0 : charptr=&options->xauth_location;
932 : 0 : goto parse_string;
933 : :
934 : : case oUser:
935 : 2616 : charptr = &options->user;
936 : : parse_string:
937 : 7850 : arg = strdelim(&s);
938 [ + - ][ - + ]: 7850 : if (!arg || *arg == '\0')
939 : 0 : fatal("%.200s line %d: Missing argument.",
940 : : filename, linenum);
941 [ + - ][ + + ]: 7850 : if (*activep && *charptr == NULL)
942 : 3924 : *charptr = xstrdup(arg);
943 : : break;
944 : :
945 : : case oGlobalKnownHostsFile:
946 : 2678 : cpptr = (char **)&options->system_hostfiles;
947 : 2678 : uintptr = &options->num_system_hostfiles;
948 : 2678 : max_entries = SSH_MAX_HOSTS_FILES;
949 : : parse_char_array:
950 [ + - ][ + + ]: 5356 : if (*activep && *uintptr == 0) {
951 [ + + ][ + - ]: 5232 : while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
952 [ - + ]: 2616 : if ((*uintptr) >= max_entries)
953 : 0 : fatal("%s line %d: "
954 : : "too many authorized keys files.",
955 : : filename, linenum);
956 : 2616 : cpptr[(*uintptr)++] = xstrdup(arg);
957 : : }
958 : : }
959 : : return 0;
960 : :
961 : : case oUserKnownHostsFile:
962 : 2678 : cpptr = (char **)&options->user_hostfiles;
963 : 2678 : uintptr = &options->num_user_hostfiles;
964 : 2678 : max_entries = SSH_MAX_HOSTS_FILES;
965 : 2678 : goto parse_char_array;
966 : :
967 : : case oHostName:
968 : 2616 : charptr = &options->hostname;
969 : 2616 : goto parse_string;
970 : :
971 : : case oHostKeyAlias:
972 : 2616 : charptr = &options->host_key_alias;
973 : 2616 : goto parse_string;
974 : :
975 : : case oPreferredAuthentications:
976 : 0 : charptr = &options->preferred_authentications;
977 : 0 : goto parse_string;
978 : :
979 : : case oBindAddress:
980 : 0 : charptr = &options->bind_address;
981 : 0 : goto parse_string;
982 : :
983 : : case oPKCS11Provider:
984 : 0 : charptr = &options->pkcs11_provider;
985 : 0 : goto parse_string;
986 : :
987 : : case oProxyCommand:
988 : 2611 : charptr = &options->proxy_command;
989 : : parse_command:
990 [ - + ]: 2619 : if (s == NULL)
991 : 0 : fatal("%.200s line %d: Missing argument.", filename, linenum);
992 : 2619 : len = strspn(s, WHITESPACE "=");
993 [ + - ][ + + ]: 2619 : if (*activep && *charptr == NULL)
994 : 1205 : *charptr = xstrdup(s + len);
995 : : return 0;
996 : :
997 : : case oPort:
998 : 2616 : intptr = &options->port;
999 : : parse_int:
1000 : 2866 : arg = strdelim(&s);
1001 [ + - ][ - + ]: 2866 : if (!arg || *arg == '\0')
1002 : 0 : fatal("%.200s line %d: Missing argument.", filename, linenum);
1003 [ - + ]: 2866 : if (arg[0] < '0' || arg[0] > '9')
1004 : 0 : fatal("%.200s line %d: Bad number.", filename, linenum);
1005 : :
1006 : : /* Octal, decimal, or hex format? */
1007 : 2866 : value = strtol(arg, &endofnumber, 0);
1008 [ - + ]: 2866 : if (arg == endofnumber)
1009 : 0 : fatal("%.200s line %d: Bad number.", filename, linenum);
1010 [ + - ][ + + ]: 2866 : if (*activep && *intptr == -1)
1011 : 1507 : *intptr = value;
1012 : : break;
1013 : :
1014 : : case oConnectionAttempts:
1015 : 32 : intptr = &options->connection_attempts;
1016 : 32 : goto parse_int;
1017 : :
1018 : : case oCipher:
1019 : 0 : intptr = &options->cipher;
1020 : 0 : arg = strdelim(&s);
1021 [ # # ][ # # ]: 0 : if (!arg || *arg == '\0')
1022 : 0 : fatal("%.200s line %d: Missing argument.", filename, linenum);
1023 : 0 : value = cipher_number(arg);
1024 [ # # ]: 0 : if (value == -1)
1025 [ # # ]: 0 : fatal("%.200s line %d: Bad cipher '%s'.",
1026 : : filename, linenum, arg ? arg : "<NONE>");
1027 [ # # ][ # # ]: 0 : if (*activep && *intptr == -1)
1028 : 0 : *intptr = value;
1029 : : break;
1030 : :
1031 : : case oCiphers:
1032 : 43 : arg = strdelim(&s);
1033 [ + - ][ - + ]: 43 : if (!arg || *arg == '\0')
1034 : 0 : fatal("%.200s line %d: Missing argument.", filename, linenum);
1035 [ - + ]: 43 : if (!ciphers_valid(arg))
1036 [ # # ]: 0 : fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
1037 : : filename, linenum, arg ? arg : "<NONE>");
1038 [ + - ][ + - ]: 43 : if (*activep && options->ciphers == NULL)
1039 : 43 : options->ciphers = xstrdup(arg);
1040 : : break;
1041 : :
1042 : : case oMacs:
1043 : 19 : arg = strdelim(&s);
1044 [ + - ][ - + ]: 19 : if (!arg || *arg == '\0')
1045 : 0 : fatal("%.200s line %d: Missing argument.", filename, linenum);
1046 [ - + ]: 19 : if (!mac_valid(arg))
1047 [ # # ]: 0 : fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
1048 : : filename, linenum, arg ? arg : "<NONE>");
1049 [ + - ][ + - ]: 19 : if (*activep && options->macs == NULL)
1050 : 19 : options->macs = xstrdup(arg);
1051 : : break;
1052 : :
1053 : : case oKexAlgorithms:
1054 : 508 : arg = strdelim(&s);
1055 [ + - ][ - + ]: 508 : if (!arg || *arg == '\0')
1056 : 0 : fatal("%.200s line %d: Missing argument.",
1057 : : filename, linenum);
1058 [ - + ]: 508 : if (!kex_names_valid(arg))
1059 [ # # ]: 0 : fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
1060 : : filename, linenum, arg ? arg : "<NONE>");
1061 [ + - ][ + + ]: 508 : if (*activep && options->kex_algorithms == NULL)
1062 : 290 : options->kex_algorithms = xstrdup(arg);
1063 : : break;
1064 : :
1065 : : case oHostKeyAlgorithms:
1066 : 0 : arg = strdelim(&s);
1067 [ # # ][ # # ]: 0 : if (!arg || *arg == '\0')
1068 : 0 : fatal("%.200s line %d: Missing argument.", filename, linenum);
1069 [ # # ]: 0 : if (!key_names_valid2(arg))
1070 [ # # ]: 0 : fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
1071 : : filename, linenum, arg ? arg : "<NONE>");
1072 [ # # ][ # # ]: 0 : if (*activep && options->hostkeyalgorithms == NULL)
1073 : 0 : options->hostkeyalgorithms = xstrdup(arg);
1074 : : break;
1075 : :
1076 : : case oProtocol:
1077 : 2695 : intptr = &options->protocol;
1078 : 2695 : arg = strdelim(&s);
1079 [ + - ][ - + ]: 2695 : if (!arg || *arg == '\0')
1080 : 0 : fatal("%.200s line %d: Missing argument.", filename, linenum);
1081 : 2695 : value = proto_spec(arg);
1082 [ - + ]: 2695 : if (value == SSH_PROTO_UNKNOWN)
1083 [ # # ]: 0 : fatal("%.200s line %d: Bad protocol spec '%s'.",
1084 : : filename, linenum, arg ? arg : "<NONE>");
1085 [ + - ][ + + ]: 2695 : if (*activep && *intptr == SSH_PROTO_UNKNOWN)
1086 : 294 : *intptr = value;
1087 : : break;
1088 : :
1089 : : case oLogLevel:
1090 : 2616 : log_level_ptr = &options->log_level;
1091 : 2616 : arg = strdelim(&s);
1092 : 2616 : value = log_level_number(arg);
1093 [ - + ]: 2616 : if (value == SYSLOG_LEVEL_NOT_SET)
1094 [ # # ]: 0 : fatal("%.200s line %d: unsupported log level '%s'",
1095 : : filename, linenum, arg ? arg : "<NONE>");
1096 [ + - ][ + + ]: 2616 : if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1097 : 1169 : *log_level_ptr = (LogLevel) value;
1098 : : break;
1099 : :
1100 : : case oLocalForward:
1101 : : case oRemoteForward:
1102 : : case oDynamicForward:
1103 : 16 : arg = strdelim(&s);
1104 [ + - ][ - + ]: 16 : if (arg == NULL || *arg == '\0')
1105 : 0 : fatal("%.200s line %d: Missing port argument.",
1106 : : filename, linenum);
1107 : :
1108 [ + - ]: 16 : if (opcode == oLocalForward ||
1109 : : opcode == oRemoteForward) {
1110 : 16 : arg2 = strdelim(&s);
1111 [ + - ][ - + ]: 16 : if (arg2 == NULL || *arg2 == '\0')
1112 : 0 : fatal("%.200s line %d: Missing target argument.",
1113 : : filename, linenum);
1114 : :
1115 : : /* construct a string for parse_forward */
1116 : : snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
1117 [ # # ]: 0 : } else if (opcode == oDynamicForward) {
1118 : 0 : strlcpy(fwdarg, arg, sizeof(fwdarg));
1119 : : }
1120 : :
1121 [ - + ]: 16 : if (parse_forward(&fwd, fwdarg,
1122 : : opcode == oDynamicForward ? 1 : 0,
1123 : : opcode == oRemoteForward ? 1 : 0) == 0)
1124 : 0 : fatal("%.200s line %d: Bad forwarding specification.",
1125 : : filename, linenum);
1126 : :
1127 [ + - ]: 16 : if (*activep) {
1128 [ + + ]: 16 : if (opcode == oLocalForward ||
1129 : : opcode == oDynamicForward)
1130 : 8 : add_local_forward(options, &fwd);
1131 [ + - ]: 8 : else if (opcode == oRemoteForward)
1132 : 8 : add_remote_forward(options, &fwd);
1133 : : }
1134 : : break;
1135 : :
1136 : : case oClearAllForwardings:
1137 : 8 : intptr = &options->clear_forwardings;
1138 : 8 : goto parse_flag;
1139 : :
1140 : : case oHost:
1141 [ - + ]: 2624 : if (cmdline)
1142 : 0 : fatal("Host directive not supported as a command-line "
1143 : : "option");
1144 : 2624 : *activep = 0;
1145 : 2624 : arg2 = NULL;
1146 [ + + ][ + - ]: 7872 : while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1147 : 2624 : negated = *arg == '!';
1148 [ - + ]: 2624 : if (negated)
1149 : 0 : arg++;
1150 [ + + ]: 2624 : if (match_pattern(host, arg)) {
1151 [ - + ]: 2616 : if (negated) {
1152 : 0 : debug("%.200s line %d: Skipping Host "
1153 : : "block because of negated match "
1154 : : "for %.100s", filename, linenum,
1155 : : arg);
1156 : 0 : *activep = 0;
1157 : 0 : break;
1158 : : }
1159 [ + - ]: 2616 : if (!*activep)
1160 : 2616 : arg2 = arg; /* logged below */
1161 : 5240 : *activep = 1;
1162 : : }
1163 : : }
1164 [ + + ]: 2624 : if (*activep)
1165 : 2616 : debug("%.200s line %d: Applying options for %.100s",
1166 : : filename, linenum, arg2);
1167 : : /* Avoid garbage check below, as strdelim is done. */
1168 : : return 0;
1169 : :
1170 : : case oMatch:
1171 [ # # ]: 0 : if (cmdline)
1172 : 0 : fatal("Host directive not supported as a command-line "
1173 : : "option");
1174 : 0 : value = match_cfg_line(options, &s, pw, host,
1175 : : filename, linenum);
1176 [ # # ]: 0 : if (value < 0)
1177 : 0 : fatal("%.200s line %d: Bad Match condition", filename,
1178 : : linenum);
1179 : 0 : *activep = value;
1180 : 0 : break;
1181 : :
1182 : : case oEscapeChar:
1183 : 0 : intptr = &options->escape_char;
1184 : 0 : arg = strdelim(&s);
1185 [ # # ][ # # ]: 0 : if (!arg || *arg == '\0')
1186 : 0 : fatal("%.200s line %d: Missing argument.", filename, linenum);
1187 [ # # ][ # # ]: 0 : if (arg[0] == '^' && arg[2] == 0 &&
[ # # ]
1188 [ # # ]: 0 : (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1189 : 0 : value = (u_char) arg[1] & 31;
1190 [ # # ]: 0 : else if (strlen(arg) == 1)
1191 : 0 : value = (u_char) arg[0];
1192 [ # # ]: 0 : else if (strcmp(arg, "none") == 0)
1193 : : value = SSH_ESCAPECHAR_NONE;
1194 : : else {
1195 : 0 : fatal("%.200s line %d: Bad escape character.",
1196 : : filename, linenum);
1197 : : /* NOTREACHED */
1198 : : value = 0; /* Avoid compiler warning. */
1199 : : }
1200 [ # # ][ # # ]: 0 : if (*activep && *intptr == -1)
1201 : 0 : *intptr = value;
1202 : : break;
1203 : :
1204 : : case oAddressFamily:
1205 : 0 : intptr = &options->address_family;
1206 : 0 : multistate_ptr = multistate_addressfamily;
1207 : 0 : goto parse_multistate;
1208 : :
1209 : : case oEnableSSHKeysign:
1210 : 0 : intptr = &options->enable_ssh_keysign;
1211 : 0 : goto parse_flag;
1212 : :
1213 : : case oIdentitiesOnly:
1214 : 0 : intptr = &options->identities_only;
1215 : 0 : goto parse_flag;
1216 : :
1217 : : case oServerAliveInterval:
1218 : 218 : intptr = &options->server_alive_interval;
1219 : 218 : goto parse_time;
1220 : :
1221 : : case oServerAliveCountMax:
1222 : 218 : intptr = &options->server_alive_count_max;
1223 : 218 : goto parse_int;
1224 : :
1225 : : case oSendEnv:
1226 [ + + ][ + - ]: 28 : while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1227 [ - + ]: 14 : if (strchr(arg, '=') != NULL)
1228 : 0 : fatal("%s line %d: Invalid environment name.",
1229 : : filename, linenum);
1230 [ + + ]: 14 : if (!*activep)
1231 : 8 : continue;
1232 [ - + ]: 6 : if (options->num_send_env >= MAX_SEND_ENV)
1233 : 0 : fatal("%s line %d: too many send env.",
1234 : : filename, linenum);
1235 : 14 : options->send_env[options->num_send_env++] =
1236 : 6 : xstrdup(arg);
1237 : : }
1238 : : break;
1239 : :
1240 : : case oControlPath:
1241 : 2 : charptr = &options->control_path;
1242 : 2 : goto parse_string;
1243 : :
1244 : : case oControlMaster:
1245 : 0 : intptr = &options->control_master;
1246 : 0 : multistate_ptr = multistate_controlmaster;
1247 : 0 : goto parse_multistate;
1248 : :
1249 : : case oControlPersist:
1250 : : /* no/false/yes/true, or a time spec */
1251 : 0 : intptr = &options->control_persist;
1252 : 0 : arg = strdelim(&s);
1253 [ # # ][ # # ]: 0 : if (!arg || *arg == '\0')
1254 : 0 : fatal("%.200s line %d: Missing ControlPersist"
1255 : : " argument.", filename, linenum);
1256 : 0 : value = 0;
1257 : 0 : value2 = 0; /* timeout */
1258 [ # # ][ # # ]: 0 : if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
[ # # ][ # # ]
1259 : : value = 0;
1260 [ # # ][ # # ]: 0 : else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
[ # # ][ # # ]
[ # # ]
1261 : : value = 1;
1262 [ # # ]: 0 : else if ((value2 = convtime(arg)) >= 0)
1263 : : value = 1;
1264 : : else
1265 : 0 : fatal("%.200s line %d: Bad ControlPersist argument.",
1266 : : filename, linenum);
1267 [ # # ][ # # ]: 0 : if (*activep && *intptr == -1) {
1268 : 0 : *intptr = value;
1269 : 0 : options->control_persist_timeout = value2;
1270 : : }
1271 : : break;
1272 : :
1273 : : case oHashKnownHosts:
1274 : 0 : intptr = &options->hash_known_hosts;
1275 : 0 : goto parse_flag;
1276 : :
1277 : : case oTunnel:
1278 : 0 : intptr = &options->tun_open;
1279 : 0 : multistate_ptr = multistate_tunnel;
1280 : 0 : goto parse_multistate;
1281 : :
1282 : : case oTunnelDevice:
1283 : 0 : arg = strdelim(&s);
1284 [ # # ][ # # ]: 0 : if (!arg || *arg == '\0')
1285 : 0 : fatal("%.200s line %d: Missing argument.", filename, linenum);
1286 : 0 : value = a2tun(arg, &value2);
1287 [ # # ]: 0 : if (value == SSH_TUNID_ERR)
1288 : 0 : fatal("%.200s line %d: Bad tun device.", filename, linenum);
1289 [ # # ]: 0 : if (*activep) {
1290 : 0 : options->tun_local = value;
1291 : 0 : options->tun_remote = value2;
1292 : : }
1293 : : break;
1294 : :
1295 : : case oLocalCommand:
1296 : 8 : charptr = &options->local_command;
1297 : 8 : goto parse_command;
1298 : :
1299 : : case oPermitLocalCommand:
1300 : 10 : intptr = &options->permit_local_command;
1301 : 10 : goto parse_flag;
1302 : :
1303 : : case oVisualHostKey:
1304 : 0 : intptr = &options->visual_host_key;
1305 : 0 : goto parse_flag;
1306 : :
1307 : : case oIPQoS:
1308 : 0 : arg = strdelim(&s);
1309 [ # # ]: 0 : if ((value = parse_ipqos(arg)) == -1)
1310 : 0 : fatal("%s line %d: Bad IPQoS value: %s",
1311 : : filename, linenum, arg);
1312 : 0 : arg = strdelim(&s);
1313 [ # # ]: 0 : if (arg == NULL)
1314 : 0 : value2 = value;
1315 [ # # ]: 0 : else if ((value2 = parse_ipqos(arg)) == -1)
1316 : 0 : fatal("%s line %d: Bad IPQoS value: %s",
1317 : : filename, linenum, arg);
1318 [ # # ]: 0 : if (*activep) {
1319 : 0 : options->ip_qos_interactive = value;
1320 : 0 : options->ip_qos_bulk = value2;
1321 : : }
1322 : : break;
1323 : :
1324 : : case oUseRoaming:
1325 : 0 : intptr = &options->use_roaming;
1326 : 0 : goto parse_flag;
1327 : :
1328 : : case oRequestTTY:
1329 : 0 : intptr = &options->request_tty;
1330 : 0 : multistate_ptr = multistate_requesttty;
1331 : 0 : goto parse_multistate;
1332 : :
1333 : : case oIgnoreUnknown:
1334 : 0 : charptr = &options->ignored_unknown;
1335 : 0 : goto parse_string;
1336 : :
1337 : : case oProxyUseFdpass:
1338 : 0 : intptr = &options->proxy_use_fdpass;
1339 : 0 : goto parse_flag;
1340 : :
1341 : : case oCanonicalDomains:
1342 : 0 : value = options->num_canonical_domains != 0;
1343 [ # # ][ # # ]: 0 : while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1344 : 0 : valid_domain(arg, filename, linenum);
1345 [ # # ][ # # ]: 0 : if (!*activep || value)
1346 : 0 : continue;
1347 [ # # ]: 0 : if (options->num_canonical_domains >= MAX_CANON_DOMAINS)
1348 : 0 : fatal("%s line %d: too many hostname suffixes.",
1349 : : filename, linenum);
1350 : : options->canonical_domains[
1351 : 0 : options->num_canonical_domains++] = xstrdup(arg);
1352 : : }
1353 : : break;
1354 : :
1355 : : case oCanonicalizePermittedCNAMEs:
1356 : 0 : value = options->num_permitted_cnames != 0;
1357 [ # # ][ # # ]: 0 : while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1358 : : /* Either '*' for everything or 'list:list' */
1359 [ # # ][ # # ]: 0 : if (strcmp(arg, "*") == 0)
1360 : : arg2 = arg;
1361 : : else {
1362 : 0 : lowercase(arg);
1363 [ # # ][ # # ]: 0 : if ((arg2 = strchr(arg, ':')) == NULL ||
1364 : 0 : arg2[1] == '\0') {
1365 : 0 : fatal("%s line %d: "
1366 : : "Invalid permitted CNAME \"%s\"",
1367 : : filename, linenum, arg);
1368 : : }
1369 : 0 : *arg2 = '\0';
1370 : 0 : arg2++;
1371 : : }
1372 [ # # ][ # # ]: 0 : if (!*activep || value)
1373 : 0 : continue;
1374 [ # # ]: 0 : if (options->num_permitted_cnames >= MAX_CANON_DOMAINS)
1375 : 0 : fatal("%s line %d: too many permitted CNAMEs.",
1376 : : filename, linenum);
1377 : 0 : cname = options->permitted_cnames +
1378 : 0 : options->num_permitted_cnames++;
1379 : 0 : cname->source_list = xstrdup(arg);
1380 : 0 : cname->target_list = xstrdup(arg2);
1381 : : }
1382 : : break;
1383 : :
1384 : : case oCanonicalizeHostname:
1385 : 0 : intptr = &options->canonicalize_hostname;
1386 : 0 : multistate_ptr = multistate_canonicalizehostname;
1387 : 0 : goto parse_multistate;
1388 : :
1389 : : case oCanonicalizeMaxDots:
1390 : 0 : intptr = &options->canonicalize_max_dots;
1391 : 0 : goto parse_int;
1392 : :
1393 : : case oCanonicalizeFallbackLocal:
1394 : 0 : intptr = &options->canonicalize_fallback_local;
1395 : 0 : goto parse_flag;
1396 : :
1397 : : case oDeprecated:
1398 : 0 : debug("%s line %d: Deprecated option \"%s\"",
1399 : : filename, linenum, keyword);
1400 : 0 : return 0;
1401 : :
1402 : : case oUnsupported:
1403 : 0 : error("%s line %d: Unsupported option \"%s\"",
1404 : : filename, linenum, keyword);
1405 : 0 : return 0;
1406 : :
1407 : : default:
1408 : 0 : fatal("process_config_line: Unimplemented opcode %d", opcode);
1409 : : }
1410 : :
1411 : : /* Check that there is no garbage at end of line. */
1412 [ - + ][ # # ]: 43253 : if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1413 : 0 : fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
1414 : : filename, linenum, arg);
1415 : : }
1416 : : return 0;
1417 : : }
1418 : :
1419 : :
1420 : : /*
1421 : : * Reads the config file and modifies the options accordingly. Options
1422 : : * should already be initialized before this call. This never returns if
1423 : : * there is an error. If the file does not exist, this returns 0.
1424 : : */
1425 : :
1426 : : int
1427 : 2616 : read_config_file(const char *filename, struct passwd *pw, const char *host,
1428 : : Options *options, int flags)
1429 : : {
1430 : : FILE *f;
1431 : : char line[1024];
1432 : : int active, linenum;
1433 : 2616 : int bad_options = 0;
1434 : :
1435 [ + - ]: 2616 : if ((f = fopen(filename, "r")) == NULL)
1436 : : return 0;
1437 : :
1438 [ - + ]: 2616 : if (flags & SSHCONF_CHECKPERM) {
1439 : : struct stat sb;
1440 : :
1441 [ # # ]: 0 : if (fstat(fileno(f), &sb) == -1)
1442 : 0 : fatal("fstat %s: %s", filename, strerror(errno));
1443 [ # # ][ # # ]: 0 : if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
[ # # ]
1444 : 0 : (sb.st_mode & 022) != 0))
1445 : 0 : fatal("Bad owner or permissions on %s", filename);
1446 : : }
1447 : :
1448 : 2616 : debug("Reading configuration data %.200s", filename);
1449 : :
1450 : : /*
1451 : : * Mark that we are now processing the options. This flag is turned
1452 : : * on/off by Host specifications.
1453 : : */
1454 : 2616 : active = 1;
1455 : 2616 : linenum = 0;
1456 [ + + ]: 57794 : while (fgets(line, sizeof(line), f)) {
1457 : : /* Update line number counter. */
1458 : 52562 : linenum++;
1459 [ - + ]: 52562 : if (process_config_line(options, pw, host, line, filename,
1460 : : linenum, &active, flags & SSHCONF_USERCONF) != 0)
1461 : 52562 : bad_options++;
1462 : : }
1463 : 2616 : fclose(f);
1464 [ - + ]: 2616 : if (bad_options > 0)
1465 : 0 : fatal("%s: terminating, %d bad configuration options",
1466 : : filename, bad_options);
1467 : : return 1;
1468 : : }
1469 : :
1470 : : /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
1471 : : int
1472 : 0 : option_clear_or_none(const char *o)
1473 : : {
1474 [ + + ][ + - ]: 3924 : return o == NULL || strcasecmp(o, "none") == 0;
[ + + ][ + - ]
[ + + ][ + - ]
[ # # ][ # # ]
1475 : : }
1476 : :
1477 : : /*
1478 : : * Initializes options to special values that indicate that they have not yet
1479 : : * been set. Read_config_file will only set options with this value. Options
1480 : : * are processed in the following order: command line, user config file,
1481 : : * system config file. Last, fill_default_options is called.
1482 : : */
1483 : :
1484 : : void
1485 : 1812 : initialize_options(Options * options)
1486 : : {
1487 : : memset(options, 'X', sizeof(*options));
1488 : 1812 : options->forward_agent = -1;
1489 : 1812 : options->forward_x11 = -1;
1490 : 1812 : options->forward_x11_trusted = -1;
1491 : 1812 : options->forward_x11_timeout = -1;
1492 : 1812 : options->exit_on_forward_failure = -1;
1493 : 1812 : options->xauth_location = NULL;
1494 : 1812 : options->gateway_ports = -1;
1495 : 1812 : options->use_privileged_port = -1;
1496 : 1812 : options->rsa_authentication = -1;
1497 : 1812 : options->pubkey_authentication = -1;
1498 : 1812 : options->challenge_response_authentication = -1;
1499 : 1812 : options->gss_authentication = -1;
1500 : 1812 : options->gss_deleg_creds = -1;
1501 : 1812 : options->password_authentication = -1;
1502 : 1812 : options->kbd_interactive_authentication = -1;
1503 : 1812 : options->kbd_interactive_devices = NULL;
1504 : 1812 : options->rhosts_rsa_authentication = -1;
1505 : 1812 : options->hostbased_authentication = -1;
1506 : 1812 : options->batch_mode = -1;
1507 : 1812 : options->check_host_ip = -1;
1508 : 1812 : options->strict_host_key_checking = -1;
1509 : 1812 : options->compression = -1;
1510 : 1812 : options->tcp_keep_alive = -1;
1511 : 1812 : options->compression_level = -1;
1512 : 1812 : options->port = -1;
1513 : 1812 : options->address_family = -1;
1514 : 1812 : options->connection_attempts = -1;
1515 : 1812 : options->connection_timeout = -1;
1516 : 1812 : options->number_of_password_prompts = -1;
1517 : 1812 : options->cipher = -1;
1518 : 1812 : options->ciphers = NULL;
1519 : 1812 : options->macs = NULL;
1520 : 1812 : options->kex_algorithms = NULL;
1521 : 1812 : options->hostkeyalgorithms = NULL;
1522 : 1812 : options->protocol = SSH_PROTO_UNKNOWN;
1523 : 1812 : options->num_identity_files = 0;
1524 : 1812 : options->hostname = NULL;
1525 : 1812 : options->host_key_alias = NULL;
1526 : 1812 : options->proxy_command = NULL;
1527 : 1812 : options->user = NULL;
1528 : 1812 : options->escape_char = -1;
1529 : 1812 : options->num_system_hostfiles = 0;
1530 : 1812 : options->num_user_hostfiles = 0;
1531 : 1812 : options->local_forwards = NULL;
1532 : 1812 : options->num_local_forwards = 0;
1533 : 1812 : options->remote_forwards = NULL;
1534 : 1812 : options->num_remote_forwards = 0;
1535 : 1812 : options->clear_forwardings = -1;
1536 : 1812 : options->log_level = SYSLOG_LEVEL_NOT_SET;
1537 : 1812 : options->preferred_authentications = NULL;
1538 : 1812 : options->bind_address = NULL;
1539 : 1812 : options->pkcs11_provider = NULL;
1540 : 1812 : options->enable_ssh_keysign = - 1;
1541 : 1812 : options->no_host_authentication_for_localhost = - 1;
1542 : 1812 : options->identities_only = - 1;
1543 : 1812 : options->rekey_limit = - 1;
1544 : 1812 : options->rekey_interval = -1;
1545 : 1812 : options->verify_host_key_dns = -1;
1546 : 1812 : options->server_alive_interval = -1;
1547 : 1812 : options->server_alive_count_max = -1;
1548 : 1812 : options->num_send_env = 0;
1549 : 1812 : options->control_path = NULL;
1550 : 1812 : options->control_master = -1;
1551 : 1812 : options->control_persist = -1;
1552 : 1812 : options->control_persist_timeout = 0;
1553 : 1812 : options->hash_known_hosts = -1;
1554 : 1812 : options->tun_open = -1;
1555 : 1812 : options->tun_local = -1;
1556 : 1812 : options->tun_remote = -1;
1557 : 1812 : options->local_command = NULL;
1558 : 1812 : options->permit_local_command = -1;
1559 : 1812 : options->use_roaming = -1;
1560 : 1812 : options->visual_host_key = -1;
1561 : 1812 : options->ip_qos_interactive = -1;
1562 : 1812 : options->ip_qos_bulk = -1;
1563 : 1812 : options->request_tty = -1;
1564 : 1812 : options->proxy_use_fdpass = -1;
1565 : 1812 : options->ignored_unknown = NULL;
1566 : 1812 : options->num_canonical_domains = 0;
1567 : 1812 : options->num_permitted_cnames = 0;
1568 : 1812 : options->canonicalize_max_dots = -1;
1569 : 1812 : options->canonicalize_fallback_local = -1;
1570 : 1812 : options->canonicalize_hostname = -1;
1571 : 1812 : }
1572 : :
1573 : : /*
1574 : : * A petite version of fill_default_options() that just fills the options
1575 : : * needed for hostname canonicalization to proceed.
1576 : : */
1577 : : void
1578 : 1308 : fill_default_options_for_canonicalization(Options *options)
1579 : : {
1580 [ + - ]: 1308 : if (options->canonicalize_max_dots == -1)
1581 : 1308 : options->canonicalize_max_dots = 1;
1582 [ + - ]: 1308 : if (options->canonicalize_fallback_local == -1)
1583 : 1308 : options->canonicalize_fallback_local = 1;
1584 [ + - ]: 1308 : if (options->canonicalize_hostname == -1)
1585 : 1308 : options->canonicalize_hostname = SSH_CANONICALISE_NO;
1586 : 1308 : }
1587 : :
1588 : : /*
1589 : : * Called after processing other sources of option data, this fills those
1590 : : * options for which no value has been specified with their default values.
1591 : : */
1592 : : void
1593 : 1308 : fill_default_options(Options * options)
1594 : : {
1595 [ + + ]: 1308 : if (options->forward_agent == -1)
1596 : 1302 : options->forward_agent = 0;
1597 [ + + ]: 1308 : if (options->forward_x11 == -1)
1598 : 1306 : options->forward_x11 = 0;
1599 [ + - ]: 1308 : if (options->forward_x11_trusted == -1)
1600 : 1308 : options->forward_x11_trusted = 0;
1601 [ + - ]: 1308 : if (options->forward_x11_timeout == -1)
1602 : 1308 : options->forward_x11_timeout = 1200;
1603 [ + + ]: 1308 : if (options->exit_on_forward_failure == -1)
1604 : 1219 : options->exit_on_forward_failure = 0;
1605 [ + - ]: 1308 : if (options->xauth_location == NULL)
1606 : 1308 : options->xauth_location = _PATH_XAUTH;
1607 [ + - ]: 1308 : if (options->gateway_ports == -1)
1608 : 1308 : options->gateway_ports = 0;
1609 [ + - ]: 1308 : if (options->use_privileged_port == -1)
1610 : 1308 : options->use_privileged_port = 0;
1611 [ - + ]: 1308 : if (options->rsa_authentication == -1)
1612 : 0 : options->rsa_authentication = 1;
1613 [ - + ]: 1308 : if (options->pubkey_authentication == -1)
1614 : 0 : options->pubkey_authentication = 1;
1615 [ - + ]: 1308 : if (options->challenge_response_authentication == -1)
1616 : 0 : options->challenge_response_authentication = 1;
1617 [ + - ]: 1308 : if (options->gss_authentication == -1)
1618 : 1308 : options->gss_authentication = 0;
1619 [ + - ]: 1308 : if (options->gss_deleg_creds == -1)
1620 : 1308 : options->gss_deleg_creds = 0;
1621 [ - + ]: 1308 : if (options->password_authentication == -1)
1622 : 0 : options->password_authentication = 1;
1623 [ + - ]: 1308 : if (options->kbd_interactive_authentication == -1)
1624 : 1308 : options->kbd_interactive_authentication = 1;
1625 [ - + ]: 1308 : if (options->rhosts_rsa_authentication == -1)
1626 : 0 : options->rhosts_rsa_authentication = 0;
1627 [ - + ]: 1308 : if (options->hostbased_authentication == -1)
1628 : 0 : options->hostbased_authentication = 0;
1629 [ - + ]: 1308 : if (options->batch_mode == -1)
1630 : 0 : options->batch_mode = 0;
1631 [ + - ]: 1308 : if (options->check_host_ip == -1)
1632 : 1308 : options->check_host_ip = 1;
1633 [ - + ]: 1308 : if (options->strict_host_key_checking == -1)
1634 : 0 : options->strict_host_key_checking = 2; /* 2 is default */
1635 [ + + ]: 1308 : if (options->compression == -1)
1636 : 1227 : options->compression = 0;
1637 [ + - ]: 1308 : if (options->tcp_keep_alive == -1)
1638 : 1308 : options->tcp_keep_alive = 1;
1639 [ + - ]: 1308 : if (options->compression_level == -1)
1640 : 1308 : options->compression_level = 6;
1641 [ - + ]: 1308 : if (options->port == -1)
1642 : 0 : options->port = 0; /* Filled in ssh_connect. */
1643 [ + - ]: 1308 : if (options->address_family == -1)
1644 : 1308 : options->address_family = AF_UNSPEC;
1645 [ + + ]: 1308 : if (options->connection_attempts == -1)
1646 : 1276 : options->connection_attempts = 1;
1647 [ + - ]: 1308 : if (options->number_of_password_prompts == -1)
1648 : 1308 : options->number_of_password_prompts = 3;
1649 : : /* Selected in ssh_login(). */
1650 [ + + ]: 1308 : if (options->cipher == -1)
1651 : 838 : options->cipher = SSH_CIPHER_NOT_SET;
1652 : : /* options->ciphers, default set in myproposals.h */
1653 : : /* options->macs, default set in myproposals.h */
1654 : : /* options->kex_algorithms, default set in myproposals.h */
1655 : : /* options->hostkeyalgorithms, default set in myproposals.h */
1656 [ - + ]: 1308 : if (options->protocol == SSH_PROTO_UNKNOWN)
1657 : 0 : options->protocol = SSH_PROTO_2;
1658 [ - + ]: 1308 : if (options->num_identity_files == 0) {
1659 [ # # ]: 0 : if (options->protocol & SSH_PROTO_1) {
1660 : 0 : add_identity_file(options, "~/",
1661 : : _PATH_SSH_CLIENT_IDENTITY, 0);
1662 : : }
1663 [ # # ]: 0 : if (options->protocol & SSH_PROTO_2) {
1664 : 0 : add_identity_file(options, "~/",
1665 : : _PATH_SSH_CLIENT_ID_RSA, 0);
1666 : 0 : add_identity_file(options, "~/",
1667 : : _PATH_SSH_CLIENT_ID_DSA, 0);
1668 : : #ifdef OPENSSL_HAS_ECC
1669 : 0 : add_identity_file(options, "~/",
1670 : : _PATH_SSH_CLIENT_ID_ECDSA, 0);
1671 : : #endif
1672 : 0 : add_identity_file(options, "~/",
1673 : : _PATH_SSH_CLIENT_ID_ED25519, 0);
1674 : : }
1675 : : }
1676 [ + - ]: 1308 : if (options->escape_char == -1)
1677 : 1308 : options->escape_char = '~';
1678 [ - + ]: 1308 : if (options->num_system_hostfiles == 0) {
1679 : 0 : options->system_hostfiles[options->num_system_hostfiles++] =
1680 : 0 : xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
1681 : 0 : options->system_hostfiles[options->num_system_hostfiles++] =
1682 : 0 : xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
1683 : : }
1684 [ - + ]: 1308 : if (options->num_user_hostfiles == 0) {
1685 : 0 : options->user_hostfiles[options->num_user_hostfiles++] =
1686 : 0 : xstrdup(_PATH_SSH_USER_HOSTFILE);
1687 : 0 : options->user_hostfiles[options->num_user_hostfiles++] =
1688 : 0 : xstrdup(_PATH_SSH_USER_HOSTFILE2);
1689 : : }
1690 [ - + ]: 1308 : if (options->log_level == SYSLOG_LEVEL_NOT_SET)
1691 : 0 : options->log_level = SYSLOG_LEVEL_INFO;
1692 [ + + ]: 1308 : if (options->clear_forwardings == 1)
1693 : 8 : clear_forwardings(options);
1694 [ + - ]: 1308 : if (options->no_host_authentication_for_localhost == - 1)
1695 : 1308 : options->no_host_authentication_for_localhost = 0;
1696 [ + - ]: 1308 : if (options->identities_only == -1)
1697 : 1308 : options->identities_only = 0;
1698 [ + - ]: 1308 : if (options->enable_ssh_keysign == -1)
1699 : 1308 : options->enable_ssh_keysign = 0;
1700 [ + + ]: 1308 : if (options->rekey_limit == -1)
1701 : 1229 : options->rekey_limit = 0;
1702 [ + + ]: 1308 : if (options->rekey_interval == -1)
1703 : 1304 : options->rekey_interval = 0;
1704 [ + - ]: 1308 : if (options->verify_host_key_dns == -1)
1705 : 1308 : options->verify_host_key_dns = 0;
1706 [ + + ]: 1308 : if (options->server_alive_interval == -1)
1707 : 1090 : options->server_alive_interval = 0;
1708 [ + + ]: 1308 : if (options->server_alive_count_max == -1)
1709 : 1090 : options->server_alive_count_max = 3;
1710 [ + + ]: 1308 : if (options->control_master == -1)
1711 : 1306 : options->control_master = 0;
1712 [ + - ]: 1308 : if (options->control_persist == -1) {
1713 : 1308 : options->control_persist = 0;
1714 : 1308 : options->control_persist_timeout = 0;
1715 : : }
1716 [ + - ]: 1308 : if (options->hash_known_hosts == -1)
1717 : 1308 : options->hash_known_hosts = 0;
1718 [ + + ]: 1308 : if (options->tun_open == -1)
1719 : 1300 : options->tun_open = SSH_TUNMODE_NO;
1720 [ + - ]: 1308 : if (options->tun_local == -1)
1721 : 1308 : options->tun_local = SSH_TUNID_ANY;
1722 [ + - ]: 1308 : if (options->tun_remote == -1)
1723 : 1308 : options->tun_remote = SSH_TUNID_ANY;
1724 [ + + ]: 1308 : if (options->permit_local_command == -1)
1725 : 1302 : options->permit_local_command = 0;
1726 [ + - ]: 1308 : if (options->use_roaming == -1)
1727 : 1308 : options->use_roaming = 1;
1728 [ + - ]: 1308 : if (options->visual_host_key == -1)
1729 : 1308 : options->visual_host_key = 0;
1730 [ + - ]: 1308 : if (options->ip_qos_interactive == -1)
1731 : 1308 : options->ip_qos_interactive = IPTOS_LOWDELAY;
1732 [ + - ]: 1308 : if (options->ip_qos_bulk == -1)
1733 : 1308 : options->ip_qos_bulk = IPTOS_THROUGHPUT;
1734 [ + + ]: 1308 : if (options->request_tty == -1)
1735 : 1306 : options->request_tty = REQUEST_TTY_AUTO;
1736 [ + - ]: 1308 : if (options->proxy_use_fdpass == -1)
1737 : 1308 : options->proxy_use_fdpass = 0;
1738 [ - + ]: 1308 : if (options->canonicalize_max_dots == -1)
1739 : 0 : options->canonicalize_max_dots = 1;
1740 [ - + ]: 1308 : if (options->canonicalize_fallback_local == -1)
1741 : 0 : options->canonicalize_fallback_local = 1;
1742 [ - + ]: 1308 : if (options->canonicalize_hostname == -1)
1743 : 0 : options->canonicalize_hostname = SSH_CANONICALISE_NO;
1744 : : #define CLEAR_ON_NONE(v) \
1745 : : do { \
1746 : : if (option_clear_or_none(v)) { \
1747 : : free(v); \
1748 : : v = NULL; \
1749 : : } \
1750 : : } while(0)
1751 [ + + ]: 1308 : CLEAR_ON_NONE(options->local_command);
1752 [ + + ]: 1308 : CLEAR_ON_NONE(options->proxy_command);
1753 [ + + ]: 1308 : CLEAR_ON_NONE(options->control_path);
1754 : : /* options->user will be set in the main program if appropriate */
1755 : : /* options->hostname will be set in the main program if appropriate */
1756 : : /* options->host_key_alias should not be set by default */
1757 : : /* options->preferred_authentications will be set in ssh */
1758 : 1308 : }
1759 : :
1760 : : /*
1761 : : * parse_forward
1762 : : * parses a string containing a port forwarding specification of the form:
1763 : : * dynamicfwd == 0
1764 : : * [listenhost:]listenport:connecthost:connectport
1765 : : * dynamicfwd == 1
1766 : : * [listenhost:]listenport
1767 : : * returns number of arguments parsed or zero on error
1768 : : */
1769 : : int
1770 : 155 : parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
1771 : : {
1772 : : int i;
1773 : : char *p, *cp, *fwdarg[4];
1774 : :
1775 : : memset(fwd, '\0', sizeof(*fwd));
1776 : :
1777 : 155 : cp = p = xstrdup(fwdspec);
1778 : :
1779 : : /* skip leading spaces */
1780 [ - + ]: 155 : while (isspace((u_char)*cp))
1781 : 0 : cp++;
1782 : :
1783 [ + - ]: 618 : for (i = 0; i < 4; ++i)
1784 [ + + ]: 618 : if ((fwdarg[i] = hpdelim(&cp)) == NULL)
1785 : : break;
1786 : :
1787 : : /* Check for trailing garbage */
1788 [ - + ]: 155 : if (cp != NULL)
1789 : 0 : i = 0; /* failure */
1790 : :
1791 [ + - + - : 155 : switch (i) {
- ]
1792 : : case 1:
1793 : 1 : fwd->listen_host = NULL;
1794 : 1 : fwd->listen_port = a2port(fwdarg[0]);
1795 : 1 : fwd->connect_host = xstrdup("socks");
1796 : 1 : break;
1797 : :
1798 : : case 2:
1799 : 0 : fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1800 : 0 : fwd->listen_port = a2port(fwdarg[1]);
1801 : 0 : fwd->connect_host = xstrdup("socks");
1802 : 0 : break;
1803 : :
1804 : : case 3:
1805 : 154 : fwd->listen_host = NULL;
1806 : 154 : fwd->listen_port = a2port(fwdarg[0]);
1807 : 154 : fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
1808 : 154 : fwd->connect_port = a2port(fwdarg[2]);
1809 : 154 : break;
1810 : :
1811 : : case 4:
1812 : 0 : fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1813 : 0 : fwd->listen_port = a2port(fwdarg[1]);
1814 : 0 : fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
1815 : 0 : fwd->connect_port = a2port(fwdarg[3]);
1816 : 0 : break;
1817 : : default:
1818 : : i = 0; /* failure */
1819 : : }
1820 : :
1821 : 155 : free(p);
1822 : :
1823 [ + + ]: 155 : if (dynamicfwd) {
1824 [ + - ]: 1 : if (!(i == 1 || i == 2))
1825 : : goto fail_free;
1826 : : } else {
1827 [ + - ]: 154 : if (!(i == 3 || i == 4))
1828 : : goto fail_free;
1829 [ + - ]: 154 : if (fwd->connect_port <= 0)
1830 : : goto fail_free;
1831 : : }
1832 : :
1833 [ + - ][ + + ]: 155 : if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0))
[ + - ]
1834 : : goto fail_free;
1835 : :
1836 [ + - ][ + - ]: 155 : if (fwd->connect_host != NULL &&
1837 : 155 : strlen(fwd->connect_host) >= NI_MAXHOST)
1838 : : goto fail_free;
1839 [ - + ][ # # ]: 155 : if (fwd->listen_host != NULL &&
1840 : 0 : strlen(fwd->listen_host) >= NI_MAXHOST)
1841 : : goto fail_free;
1842 : :
1843 : :
1844 : : return (i);
1845 : :
1846 : : fail_free:
1847 : 0 : free(fwd->connect_host);
1848 : 0 : fwd->connect_host = NULL;
1849 : 0 : free(fwd->listen_host);
1850 : 0 : fwd->listen_host = NULL;
1851 : 0 : return (0);
1852 : : }
|