kernel - CAM cleanup 3/N - Remove unnecessary mplocks
[dragonfly.git] / crypto / openssh / readconf.c
blobc177202b1a944e670ee2ba83a072dff9afe267ee
1 /* $OpenBSD: readconf.c,v 1.259 2016/07/22 03:35:11 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.
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".
15 #include "includes.h"
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <sys/socket.h>
20 #include <sys/wait.h>
21 #include <sys/un.h>
23 #include <netinet/in.h>
24 #include <netinet/in_systm.h>
25 #include <netinet/ip.h>
26 #include <arpa/inet.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <limits.h>
32 #include <netdb.h>
33 #ifdef HAVE_PATHS_H
34 # include <paths.h>
35 #endif
36 #include <pwd.h>
37 #include <signal.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <unistd.h>
42 #ifdef USE_SYSTEM_GLOB
43 # include <glob.h>
44 #else
45 # include "openbsd-compat/glob.h"
46 #endif
47 #ifdef HAVE_UTIL_H
48 #include <util.h>
49 #endif
50 #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
51 # include <vis.h>
52 #endif
54 #include "xmalloc.h"
55 #include "ssh.h"
56 #include "compat.h"
57 #include "cipher.h"
58 #include "pathnames.h"
59 #include "log.h"
60 #include "sshkey.h"
61 #include "misc.h"
62 #include "readconf.h"
63 #include "match.h"
64 #include "kex.h"
65 #include "mac.h"
66 #include "uidswap.h"
67 #include "myproposal.h"
68 #include "digest.h"
70 /* Format of the configuration file:
72 # Configuration data is parsed as follows:
73 # 1. command line options
74 # 2. user-specific file
75 # 3. system-wide file
76 # Any configuration value is only changed the first time it is set.
77 # Thus, host-specific definitions should be at the beginning of the
78 # configuration file, and defaults at the end.
80 # Host-specific declarations. These may override anything above. A single
81 # host may match multiple declarations; these are processed in the order
82 # that they are given in.
84 Host *.ngs.fi ngs.fi
85 User foo
87 Host fake.com
88 HostName another.host.name.real.org
89 User blaah
90 Port 34289
91 ForwardX11 no
92 ForwardAgent no
94 Host books.com
95 RemoteForward 9999 shadows.cs.hut.fi:9999
96 Cipher 3des
98 Host fascist.blob.com
99 Port 23123
100 User tylonen
101 PasswordAuthentication no
103 Host puukko.hut.fi
104 User t35124p
105 ProxyCommand ssh-proxy %h %p
107 Host *.fr
108 PublicKeyAuthentication no
110 Host *.su
111 Cipher none
112 PasswordAuthentication no
114 Host vpn.fake.com
115 Tunnel yes
116 TunnelDevice 3
118 # Defaults for various options
119 Host *
120 ForwardAgent no
121 ForwardX11 no
122 PasswordAuthentication yes
123 RSAAuthentication yes
124 RhostsRSAAuthentication yes
125 StrictHostKeyChecking yes
126 TcpKeepAlive no
127 IdentityFile ~/.ssh/identity
128 Port 22
129 EscapeChar ~
133 static int read_config_file_depth(const char *filename, struct passwd *pw,
134 const char *host, const char *original_host, Options *options,
135 int flags, int *activep, int depth);
136 static int process_config_line_depth(Options *options, struct passwd *pw,
137 const char *host, const char *original_host, char *line,
138 const char *filename, int linenum, int *activep, int flags, int depth);
140 /* Keyword tokens. */
142 typedef enum {
143 oBadOption,
144 oHost, oMatch, oInclude,
145 oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
146 oGatewayPorts, oExitOnForwardFailure,
147 oPasswordAuthentication, oRSAAuthentication,
148 oChallengeResponseAuthentication, oXAuthLocation,
149 oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
150 oCertificateFile, oAddKeysToAgent, oIdentityAgent,
151 oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
152 oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
153 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
154 oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
155 oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
156 oPubkeyAuthentication,
157 oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
158 oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
159 oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
160 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
161 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
162 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
163 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
164 oSendEnv, oControlPath, oControlMaster, oControlPersist,
165 oHashKnownHosts,
166 oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
167 oVisualHostKey,
168 oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
169 oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
170 oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
171 oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
172 oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
173 oPubkeyAcceptedKeyTypes, oProxyJump,
174 oIgnoredUnknownOption, oDeprecated, oUnsupported
175 } OpCodes;
177 /* Textual representations of the tokens. */
179 static struct {
180 const char *name;
181 OpCodes opcode;
182 } keywords[] = {
183 { "forwardagent", oForwardAgent },
184 { "forwardx11", oForwardX11 },
185 { "forwardx11trusted", oForwardX11Trusted },
186 { "forwardx11timeout", oForwardX11Timeout },
187 { "exitonforwardfailure", oExitOnForwardFailure },
188 { "xauthlocation", oXAuthLocation },
189 { "gatewayports", oGatewayPorts },
190 { "useprivilegedport", oUsePrivilegedPort },
191 { "rhostsauthentication", oDeprecated },
192 { "passwordauthentication", oPasswordAuthentication },
193 { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
194 { "kbdinteractivedevices", oKbdInteractiveDevices },
195 { "rsaauthentication", oRSAAuthentication },
196 { "pubkeyauthentication", oPubkeyAuthentication },
197 { "dsaauthentication", oPubkeyAuthentication }, /* alias */
198 { "rhostsrsaauthentication", oRhostsRSAAuthentication },
199 { "hostbasedauthentication", oHostbasedAuthentication },
200 { "challengeresponseauthentication", oChallengeResponseAuthentication },
201 { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
202 { "tisauthentication", oChallengeResponseAuthentication }, /* alias */
203 { "kerberosauthentication", oUnsupported },
204 { "kerberostgtpassing", oUnsupported },
205 { "afstokenpassing", oUnsupported },
206 #if defined(GSSAPI)
207 { "gssapiauthentication", oGssAuthentication },
208 { "gssapidelegatecredentials", oGssDelegateCreds },
209 #else
210 { "gssapiauthentication", oUnsupported },
211 { "gssapidelegatecredentials", oUnsupported },
212 #endif
213 { "fallbacktorsh", oDeprecated },
214 { "usersh", oDeprecated },
215 { "identityfile", oIdentityFile },
216 { "identityfile2", oIdentityFile }, /* obsolete */
217 { "identitiesonly", oIdentitiesOnly },
218 { "certificatefile", oCertificateFile },
219 { "addkeystoagent", oAddKeysToAgent },
220 { "identityagent", oIdentityAgent },
221 { "hostname", oHostName },
222 { "hostkeyalias", oHostKeyAlias },
223 { "proxycommand", oProxyCommand },
224 { "port", oPort },
225 { "cipher", oCipher },
226 { "ciphers", oCiphers },
227 { "macs", oMacs },
228 { "protocol", oProtocol },
229 { "remoteforward", oRemoteForward },
230 { "localforward", oLocalForward },
231 { "user", oUser },
232 { "host", oHost },
233 { "match", oMatch },
234 { "escapechar", oEscapeChar },
235 { "globalknownhostsfile", oGlobalKnownHostsFile },
236 { "globalknownhostsfile2", oDeprecated },
237 { "userknownhostsfile", oUserKnownHostsFile },
238 { "userknownhostsfile2", oDeprecated },
239 { "connectionattempts", oConnectionAttempts },
240 { "batchmode", oBatchMode },
241 { "checkhostip", oCheckHostIP },
242 { "stricthostkeychecking", oStrictHostKeyChecking },
243 { "compression", oCompression },
244 { "compressionlevel", oCompressionLevel },
245 { "tcpkeepalive", oTCPKeepAlive },
246 { "keepalive", oTCPKeepAlive }, /* obsolete */
247 { "numberofpasswordprompts", oNumberOfPasswordPrompts },
248 { "loglevel", oLogLevel },
249 { "dynamicforward", oDynamicForward },
250 { "preferredauthentications", oPreferredAuthentications },
251 { "hostkeyalgorithms", oHostKeyAlgorithms },
252 { "bindaddress", oBindAddress },
253 #ifdef ENABLE_PKCS11
254 { "smartcarddevice", oPKCS11Provider },
255 { "pkcs11provider", oPKCS11Provider },
256 #else
257 { "smartcarddevice", oUnsupported },
258 { "pkcs11provider", oUnsupported },
259 #endif
260 { "clearallforwardings", oClearAllForwardings },
261 { "enablesshkeysign", oEnableSSHKeysign },
262 { "verifyhostkeydns", oVerifyHostKeyDNS },
263 { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
264 { "rekeylimit", oRekeyLimit },
265 { "connecttimeout", oConnectTimeout },
266 { "addressfamily", oAddressFamily },
267 { "serveraliveinterval", oServerAliveInterval },
268 { "serveralivecountmax", oServerAliveCountMax },
269 { "sendenv", oSendEnv },
270 { "controlpath", oControlPath },
271 { "controlmaster", oControlMaster },
272 { "controlpersist", oControlPersist },
273 { "hashknownhosts", oHashKnownHosts },
274 { "include", oInclude },
275 { "tunnel", oTunnel },
276 { "tunneldevice", oTunnelDevice },
277 { "localcommand", oLocalCommand },
278 { "permitlocalcommand", oPermitLocalCommand },
279 { "visualhostkey", oVisualHostKey },
280 { "useroaming", oDeprecated },
281 { "kexalgorithms", oKexAlgorithms },
282 { "ipqos", oIPQoS },
283 { "requesttty", oRequestTTY },
284 { "proxyusefdpass", oProxyUseFdpass },
285 { "canonicaldomains", oCanonicalDomains },
286 { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
287 { "canonicalizehostname", oCanonicalizeHostname },
288 { "canonicalizemaxdots", oCanonicalizeMaxDots },
289 { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
290 { "streamlocalbindmask", oStreamLocalBindMask },
291 { "streamlocalbindunlink", oStreamLocalBindUnlink },
292 { "revokedhostkeys", oRevokedHostKeys },
293 { "fingerprinthash", oFingerprintHash },
294 { "updatehostkeys", oUpdateHostkeys },
295 { "hostbasedkeytypes", oHostbasedKeyTypes },
296 { "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes },
297 { "ignoreunknown", oIgnoreUnknown },
298 { "proxyjump", oProxyJump },
300 { NULL, oBadOption }
304 * Adds a local TCP/IP port forward to options. Never returns if there is an
305 * error.
308 void
309 add_local_forward(Options *options, const struct Forward *newfwd)
311 struct Forward *fwd;
312 extern uid_t original_real_uid;
313 int i;
315 if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0 &&
316 newfwd->listen_path == NULL)
317 fatal("Privileged ports can only be forwarded by root.");
318 /* Don't add duplicates */
319 for (i = 0; i < options->num_local_forwards; i++) {
320 if (forward_equals(newfwd, options->local_forwards + i))
321 return;
323 options->local_forwards = xreallocarray(options->local_forwards,
324 options->num_local_forwards + 1,
325 sizeof(*options->local_forwards));
326 fwd = &options->local_forwards[options->num_local_forwards++];
328 fwd->listen_host = newfwd->listen_host;
329 fwd->listen_port = newfwd->listen_port;
330 fwd->listen_path = newfwd->listen_path;
331 fwd->connect_host = newfwd->connect_host;
332 fwd->connect_port = newfwd->connect_port;
333 fwd->connect_path = newfwd->connect_path;
337 * Adds a remote TCP/IP port forward to options. Never returns if there is
338 * an error.
341 void
342 add_remote_forward(Options *options, const struct Forward *newfwd)
344 struct Forward *fwd;
345 int i;
347 /* Don't add duplicates */
348 for (i = 0; i < options->num_remote_forwards; i++) {
349 if (forward_equals(newfwd, options->remote_forwards + i))
350 return;
352 options->remote_forwards = xreallocarray(options->remote_forwards,
353 options->num_remote_forwards + 1,
354 sizeof(*options->remote_forwards));
355 fwd = &options->remote_forwards[options->num_remote_forwards++];
357 fwd->listen_host = newfwd->listen_host;
358 fwd->listen_port = newfwd->listen_port;
359 fwd->listen_path = newfwd->listen_path;
360 fwd->connect_host = newfwd->connect_host;
361 fwd->connect_port = newfwd->connect_port;
362 fwd->connect_path = newfwd->connect_path;
363 fwd->handle = newfwd->handle;
364 fwd->allocated_port = 0;
367 static void
368 clear_forwardings(Options *options)
370 int i;
372 for (i = 0; i < options->num_local_forwards; i++) {
373 free(options->local_forwards[i].listen_host);
374 free(options->local_forwards[i].listen_path);
375 free(options->local_forwards[i].connect_host);
376 free(options->local_forwards[i].connect_path);
378 if (options->num_local_forwards > 0) {
379 free(options->local_forwards);
380 options->local_forwards = NULL;
382 options->num_local_forwards = 0;
383 for (i = 0; i < options->num_remote_forwards; i++) {
384 free(options->remote_forwards[i].listen_host);
385 free(options->remote_forwards[i].listen_path);
386 free(options->remote_forwards[i].connect_host);
387 free(options->remote_forwards[i].connect_path);
389 if (options->num_remote_forwards > 0) {
390 free(options->remote_forwards);
391 options->remote_forwards = NULL;
393 options->num_remote_forwards = 0;
394 options->tun_open = SSH_TUNMODE_NO;
397 void
398 add_certificate_file(Options *options, const char *path, int userprovided)
400 int i;
402 if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
403 fatal("Too many certificate files specified (max %d)",
404 SSH_MAX_CERTIFICATE_FILES);
406 /* Avoid registering duplicates */
407 for (i = 0; i < options->num_certificate_files; i++) {
408 if (options->certificate_file_userprovided[i] == userprovided &&
409 strcmp(options->certificate_files[i], path) == 0) {
410 debug2("%s: ignoring duplicate key %s", __func__, path);
411 return;
415 options->certificate_file_userprovided[options->num_certificate_files] =
416 userprovided;
417 options->certificate_files[options->num_certificate_files++] =
418 xstrdup(path);
421 void
422 add_identity_file(Options *options, const char *dir, const char *filename,
423 int userprovided)
425 char *path;
426 int i;
428 if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
429 fatal("Too many identity files specified (max %d)",
430 SSH_MAX_IDENTITY_FILES);
432 if (dir == NULL) /* no dir, filename is absolute */
433 path = xstrdup(filename);
434 else
435 (void)xasprintf(&path, "%.100s%.100s", dir, filename);
437 /* Avoid registering duplicates */
438 for (i = 0; i < options->num_identity_files; i++) {
439 if (options->identity_file_userprovided[i] == userprovided &&
440 strcmp(options->identity_files[i], path) == 0) {
441 debug2("%s: ignoring duplicate key %s", __func__, path);
442 free(path);
443 return;
447 options->identity_file_userprovided[options->num_identity_files] =
448 userprovided;
449 options->identity_files[options->num_identity_files++] = path;
453 default_ssh_port(void)
455 static int port;
456 struct servent *sp;
458 if (port == 0) {
459 sp = getservbyname(SSH_SERVICE_NAME, "tcp");
460 port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
462 return port;
466 * Execute a command in a shell.
467 * Return its exit status or -1 on abnormal exit.
469 static int
470 execute_in_shell(const char *cmd)
472 char *shell;
473 pid_t pid;
474 int devnull, status;
475 extern uid_t original_real_uid;
477 if ((shell = getenv("SHELL")) == NULL)
478 shell = _PATH_BSHELL;
480 /* Need this to redirect subprocess stdin/out */
481 if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
482 fatal("open(/dev/null): %s", strerror(errno));
484 debug("Executing command: '%.500s'", cmd);
486 /* Fork and execute the command. */
487 if ((pid = fork()) == 0) {
488 char *argv[4];
490 /* Child. Permanently give up superuser privileges. */
491 permanently_drop_suid(original_real_uid);
493 /* Redirect child stdin and stdout. Leave stderr */
494 if (dup2(devnull, STDIN_FILENO) == -1)
495 fatal("dup2: %s", strerror(errno));
496 if (dup2(devnull, STDOUT_FILENO) == -1)
497 fatal("dup2: %s", strerror(errno));
498 if (devnull > STDERR_FILENO)
499 close(devnull);
500 closefrom(STDERR_FILENO + 1);
502 argv[0] = shell;
503 argv[1] = "-c";
504 argv[2] = xstrdup(cmd);
505 argv[3] = NULL;
507 execv(argv[0], argv);
508 error("Unable to execute '%.100s': %s", cmd, strerror(errno));
509 /* Die with signal to make this error apparent to parent. */
510 signal(SIGTERM, SIG_DFL);
511 kill(getpid(), SIGTERM);
512 _exit(1);
514 /* Parent. */
515 if (pid < 0)
516 fatal("%s: fork: %.100s", __func__, strerror(errno));
518 close(devnull);
520 while (waitpid(pid, &status, 0) == -1) {
521 if (errno != EINTR && errno != EAGAIN)
522 fatal("%s: waitpid: %s", __func__, strerror(errno));
524 if (!WIFEXITED(status)) {
525 error("command '%.100s' exited abnormally", cmd);
526 return -1;
528 debug3("command returned status %d", WEXITSTATUS(status));
529 return WEXITSTATUS(status);
533 * Parse and execute a Match directive.
535 static int
536 match_cfg_line(Options *options, char **condition, struct passwd *pw,
537 const char *host_arg, const char *original_host, int post_canon,
538 const char *filename, int linenum)
540 char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
541 const char *ruser;
542 int r, port, this_result, result = 1, attributes = 0, negate;
543 char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
546 * Configuration is likely to be incomplete at this point so we
547 * must be prepared to use default values.
549 port = options->port <= 0 ? default_ssh_port() : options->port;
550 ruser = options->user == NULL ? pw->pw_name : options->user;
551 if (post_canon) {
552 host = xstrdup(options->hostname);
553 } else if (options->hostname != NULL) {
554 /* NB. Please keep in sync with ssh.c:main() */
555 host = percent_expand(options->hostname,
556 "h", host_arg, (char *)NULL);
557 } else {
558 host = xstrdup(host_arg);
561 debug2("checking match for '%s' host %s originally %s",
562 cp, host, original_host);
563 while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
564 criteria = NULL;
565 this_result = 1;
566 if ((negate = attrib[0] == '!'))
567 attrib++;
568 /* criteria "all" and "canonical" have no argument */
569 if (strcasecmp(attrib, "all") == 0) {
570 if (attributes > 1 ||
571 ((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
572 error("%.200s line %d: '%s' cannot be combined "
573 "with other Match attributes",
574 filename, linenum, oattrib);
575 result = -1;
576 goto out;
578 if (result)
579 result = negate ? 0 : 1;
580 goto out;
582 attributes++;
583 if (strcasecmp(attrib, "canonical") == 0) {
584 r = !!post_canon; /* force bitmask member to boolean */
585 if (r == (negate ? 1 : 0))
586 this_result = result = 0;
587 debug3("%.200s line %d: %smatched '%s'",
588 filename, linenum,
589 this_result ? "" : "not ", oattrib);
590 continue;
592 /* All other criteria require an argument */
593 if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
594 error("Missing Match criteria for %s", attrib);
595 result = -1;
596 goto out;
598 if (strcasecmp(attrib, "host") == 0) {
599 criteria = xstrdup(host);
600 r = match_hostname(host, arg) == 1;
601 if (r == (negate ? 1 : 0))
602 this_result = result = 0;
603 } else if (strcasecmp(attrib, "originalhost") == 0) {
604 criteria = xstrdup(original_host);
605 r = match_hostname(original_host, arg) == 1;
606 if (r == (negate ? 1 : 0))
607 this_result = result = 0;
608 } else if (strcasecmp(attrib, "user") == 0) {
609 criteria = xstrdup(ruser);
610 r = match_pattern_list(ruser, arg, 0) == 1;
611 if (r == (negate ? 1 : 0))
612 this_result = result = 0;
613 } else if (strcasecmp(attrib, "localuser") == 0) {
614 criteria = xstrdup(pw->pw_name);
615 r = match_pattern_list(pw->pw_name, arg, 0) == 1;
616 if (r == (negate ? 1 : 0))
617 this_result = result = 0;
618 } else if (strcasecmp(attrib, "exec") == 0) {
619 if (gethostname(thishost, sizeof(thishost)) == -1)
620 fatal("gethostname: %s", strerror(errno));
621 strlcpy(shorthost, thishost, sizeof(shorthost));
622 shorthost[strcspn(thishost, ".")] = '\0';
623 snprintf(portstr, sizeof(portstr), "%d", port);
625 cmd = percent_expand(arg,
626 "L", shorthost,
627 "d", pw->pw_dir,
628 "h", host,
629 "l", thishost,
630 "n", original_host,
631 "p", portstr,
632 "r", ruser,
633 "u", pw->pw_name,
634 (char *)NULL);
635 if (result != 1) {
636 /* skip execution if prior predicate failed */
637 debug3("%.200s line %d: skipped exec "
638 "\"%.100s\"", filename, linenum, cmd);
639 free(cmd);
640 continue;
642 r = execute_in_shell(cmd);
643 if (r == -1) {
644 fatal("%.200s line %d: match exec "
645 "'%.100s' error", filename,
646 linenum, cmd);
648 criteria = xstrdup(cmd);
649 free(cmd);
650 /* Force exit status to boolean */
651 r = r == 0;
652 if (r == (negate ? 1 : 0))
653 this_result = result = 0;
654 } else {
655 error("Unsupported Match attribute %s", attrib);
656 result = -1;
657 goto out;
659 debug3("%.200s line %d: %smatched '%s \"%.100s\"' ",
660 filename, linenum, this_result ? "": "not ",
661 oattrib, criteria);
662 free(criteria);
664 if (attributes == 0) {
665 error("One or more attributes required for Match");
666 result = -1;
667 goto out;
669 out:
670 if (result != -1)
671 debug2("match %sfound", result ? "" : "not ");
672 *condition = cp;
673 free(host);
674 return result;
677 /* Check and prepare a domain name: removes trailing '.' and lowercases */
678 static void
679 valid_domain(char *name, const char *filename, int linenum)
681 size_t i, l = strlen(name);
682 u_char c, last = '\0';
684 if (l == 0)
685 fatal("%s line %d: empty hostname suffix", filename, linenum);
686 if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0]))
687 fatal("%s line %d: hostname suffix \"%.100s\" "
688 "starts with invalid character", filename, linenum, name);
689 for (i = 0; i < l; i++) {
690 c = tolower((u_char)name[i]);
691 name[i] = (char)c;
692 if (last == '.' && c == '.')
693 fatal("%s line %d: hostname suffix \"%.100s\" contains "
694 "consecutive separators", filename, linenum, name);
695 if (c != '.' && c != '-' && !isalnum(c) &&
696 c != '_') /* technically invalid, but common */
697 fatal("%s line %d: hostname suffix \"%.100s\" contains "
698 "invalid characters", filename, linenum, name);
699 last = c;
701 if (name[l - 1] == '.')
702 name[l - 1] = '\0';
706 * Returns the number of the token pointed to by cp or oBadOption.
708 static OpCodes
709 parse_token(const char *cp, const char *filename, int linenum,
710 const char *ignored_unknown)
712 int i;
714 for (i = 0; keywords[i].name; i++)
715 if (strcmp(cp, keywords[i].name) == 0)
716 return keywords[i].opcode;
717 if (ignored_unknown != NULL &&
718 match_pattern_list(cp, ignored_unknown, 1) == 1)
719 return oIgnoredUnknownOption;
720 error("%s: line %d: Bad configuration option: %s",
721 filename, linenum, cp);
722 return oBadOption;
725 /* Multistate option parsing */
726 struct multistate {
727 char *key;
728 int value;
730 static const struct multistate multistate_flag[] = {
731 { "true", 1 },
732 { "false", 0 },
733 { "yes", 1 },
734 { "no", 0 },
735 { NULL, -1 }
737 static const struct multistate multistate_yesnoask[] = {
738 { "true", 1 },
739 { "false", 0 },
740 { "yes", 1 },
741 { "no", 0 },
742 { "ask", 2 },
743 { NULL, -1 }
745 static const struct multistate multistate_yesnoaskconfirm[] = {
746 { "true", 1 },
747 { "false", 0 },
748 { "yes", 1 },
749 { "no", 0 },
750 { "ask", 2 },
751 { "confirm", 3 },
752 { NULL, -1 }
754 static const struct multistate multistate_addressfamily[] = {
755 { "inet", AF_INET },
756 { "inet6", AF_INET6 },
757 { "any", AF_UNSPEC },
758 { NULL, -1 }
760 static const struct multistate multistate_controlmaster[] = {
761 { "true", SSHCTL_MASTER_YES },
762 { "yes", SSHCTL_MASTER_YES },
763 { "false", SSHCTL_MASTER_NO },
764 { "no", SSHCTL_MASTER_NO },
765 { "auto", SSHCTL_MASTER_AUTO },
766 { "ask", SSHCTL_MASTER_ASK },
767 { "autoask", SSHCTL_MASTER_AUTO_ASK },
768 { NULL, -1 }
770 static const struct multistate multistate_tunnel[] = {
771 { "ethernet", SSH_TUNMODE_ETHERNET },
772 { "point-to-point", SSH_TUNMODE_POINTOPOINT },
773 { "true", SSH_TUNMODE_DEFAULT },
774 { "yes", SSH_TUNMODE_DEFAULT },
775 { "false", SSH_TUNMODE_NO },
776 { "no", SSH_TUNMODE_NO },
777 { NULL, -1 }
779 static const struct multistate multistate_requesttty[] = {
780 { "true", REQUEST_TTY_YES },
781 { "yes", REQUEST_TTY_YES },
782 { "false", REQUEST_TTY_NO },
783 { "no", REQUEST_TTY_NO },
784 { "force", REQUEST_TTY_FORCE },
785 { "auto", REQUEST_TTY_AUTO },
786 { NULL, -1 }
788 static const struct multistate multistate_canonicalizehostname[] = {
789 { "true", SSH_CANONICALISE_YES },
790 { "false", SSH_CANONICALISE_NO },
791 { "yes", SSH_CANONICALISE_YES },
792 { "no", SSH_CANONICALISE_NO },
793 { "always", SSH_CANONICALISE_ALWAYS },
794 { NULL, -1 }
798 * Processes a single option line as used in the configuration files. This
799 * only sets those values that have not already been set.
802 process_config_line(Options *options, struct passwd *pw, const char *host,
803 const char *original_host, char *line, const char *filename,
804 int linenum, int *activep, int flags)
806 return process_config_line_depth(options, pw, host, original_host,
807 line, filename, linenum, activep, flags, 0);
810 #define WHITESPACE " \t\r\n"
811 static int
812 process_config_line_depth(Options *options, struct passwd *pw, const char *host,
813 const char *original_host, char *line, const char *filename,
814 int linenum, int *activep, int flags, int depth)
816 char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
817 char **cpptr, fwdarg[256];
818 u_int i, *uintptr, max_entries = 0;
819 int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
820 LogLevel *log_level_ptr;
821 long long val64;
822 size_t len;
823 struct Forward fwd;
824 const struct multistate *multistate_ptr;
825 struct allowed_cname *cname;
826 glob_t gl;
828 if (activep == NULL) { /* We are processing a command line directive */
829 cmdline = 1;
830 activep = &cmdline;
833 /* Strip trailing whitespace */
834 if ((len = strlen(line)) == 0)
835 return 0;
836 for (len--; len > 0; len--) {
837 if (strchr(WHITESPACE, line[len]) == NULL)
838 break;
839 line[len] = '\0';
842 s = line;
843 /* Get the keyword. (Each line is supposed to begin with a keyword). */
844 if ((keyword = strdelim(&s)) == NULL)
845 return 0;
846 /* Ignore leading whitespace. */
847 if (*keyword == '\0')
848 keyword = strdelim(&s);
849 if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
850 return 0;
851 /* Match lowercase keyword */
852 lowercase(keyword);
854 opcode = parse_token(keyword, filename, linenum,
855 options->ignored_unknown);
857 switch (opcode) {
858 case oBadOption:
859 /* don't panic, but count bad options */
860 return -1;
861 /* NOTREACHED */
862 case oIgnoredUnknownOption:
863 debug("%s line %d: Ignored unknown option \"%s\"",
864 filename, linenum, keyword);
865 return 0;
866 case oConnectTimeout:
867 intptr = &options->connection_timeout;
868 parse_time:
869 arg = strdelim(&s);
870 if (!arg || *arg == '\0')
871 fatal("%s line %d: missing time value.",
872 filename, linenum);
873 if (strcmp(arg, "none") == 0)
874 value = -1;
875 else if ((value = convtime(arg)) == -1)
876 fatal("%s line %d: invalid time value.",
877 filename, linenum);
878 if (*activep && *intptr == -1)
879 *intptr = value;
880 break;
882 case oForwardAgent:
883 intptr = &options->forward_agent;
884 parse_flag:
885 multistate_ptr = multistate_flag;
886 parse_multistate:
887 arg = strdelim(&s);
888 if (!arg || *arg == '\0')
889 fatal("%s line %d: missing argument.",
890 filename, linenum);
891 value = -1;
892 for (i = 0; multistate_ptr[i].key != NULL; i++) {
893 if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
894 value = multistate_ptr[i].value;
895 break;
898 if (value == -1)
899 fatal("%s line %d: unsupported option \"%s\".",
900 filename, linenum, arg);
901 if (*activep && *intptr == -1)
902 *intptr = value;
903 break;
905 case oForwardX11:
906 intptr = &options->forward_x11;
907 goto parse_flag;
909 case oForwardX11Trusted:
910 intptr = &options->forward_x11_trusted;
911 goto parse_flag;
913 case oForwardX11Timeout:
914 intptr = &options->forward_x11_timeout;
915 goto parse_time;
917 case oGatewayPorts:
918 intptr = &options->fwd_opts.gateway_ports;
919 goto parse_flag;
921 case oExitOnForwardFailure:
922 intptr = &options->exit_on_forward_failure;
923 goto parse_flag;
925 case oUsePrivilegedPort:
926 intptr = &options->use_privileged_port;
927 goto parse_flag;
929 case oPasswordAuthentication:
930 intptr = &options->password_authentication;
931 goto parse_flag;
933 case oKbdInteractiveAuthentication:
934 intptr = &options->kbd_interactive_authentication;
935 goto parse_flag;
937 case oKbdInteractiveDevices:
938 charptr = &options->kbd_interactive_devices;
939 goto parse_string;
941 case oPubkeyAuthentication:
942 intptr = &options->pubkey_authentication;
943 goto parse_flag;
945 case oRSAAuthentication:
946 intptr = &options->rsa_authentication;
947 goto parse_flag;
949 case oRhostsRSAAuthentication:
950 intptr = &options->rhosts_rsa_authentication;
951 goto parse_flag;
953 case oHostbasedAuthentication:
954 intptr = &options->hostbased_authentication;
955 goto parse_flag;
957 case oChallengeResponseAuthentication:
958 intptr = &options->challenge_response_authentication;
959 goto parse_flag;
961 case oGssAuthentication:
962 intptr = &options->gss_authentication;
963 goto parse_flag;
965 case oGssDelegateCreds:
966 intptr = &options->gss_deleg_creds;
967 goto parse_flag;
969 case oBatchMode:
970 intptr = &options->batch_mode;
971 goto parse_flag;
973 case oCheckHostIP:
974 intptr = &options->check_host_ip;
975 goto parse_flag;
977 case oVerifyHostKeyDNS:
978 intptr = &options->verify_host_key_dns;
979 multistate_ptr = multistate_yesnoask;
980 goto parse_multistate;
982 case oStrictHostKeyChecking:
983 intptr = &options->strict_host_key_checking;
984 multistate_ptr = multistate_yesnoask;
985 goto parse_multistate;
987 case oCompression:
988 intptr = &options->compression;
989 goto parse_flag;
991 case oTCPKeepAlive:
992 intptr = &options->tcp_keep_alive;
993 goto parse_flag;
995 case oNoHostAuthenticationForLocalhost:
996 intptr = &options->no_host_authentication_for_localhost;
997 goto parse_flag;
999 case oNumberOfPasswordPrompts:
1000 intptr = &options->number_of_password_prompts;
1001 goto parse_int;
1003 case oCompressionLevel:
1004 intptr = &options->compression_level;
1005 goto parse_int;
1007 case oRekeyLimit:
1008 arg = strdelim(&s);
1009 if (!arg || *arg == '\0')
1010 fatal("%.200s line %d: Missing argument.", filename,
1011 linenum);
1012 if (strcmp(arg, "default") == 0) {
1013 val64 = 0;
1014 } else {
1015 if (scan_scaled(arg, &val64) == -1)
1016 fatal("%.200s line %d: Bad number '%s': %s",
1017 filename, linenum, arg, strerror(errno));
1018 if (val64 != 0 && val64 < 16)
1019 fatal("%.200s line %d: RekeyLimit too small",
1020 filename, linenum);
1022 if (*activep && options->rekey_limit == -1)
1023 options->rekey_limit = val64;
1024 if (s != NULL) { /* optional rekey interval present */
1025 if (strcmp(s, "none") == 0) {
1026 (void)strdelim(&s); /* discard */
1027 break;
1029 intptr = &options->rekey_interval;
1030 goto parse_time;
1032 break;
1034 case oIdentityFile:
1035 arg = strdelim(&s);
1036 if (!arg || *arg == '\0')
1037 fatal("%.200s line %d: Missing argument.", filename, linenum);
1038 if (*activep) {
1039 intptr = &options->num_identity_files;
1040 if (*intptr >= SSH_MAX_IDENTITY_FILES)
1041 fatal("%.200s line %d: Too many identity files specified (max %d).",
1042 filename, linenum, SSH_MAX_IDENTITY_FILES);
1043 add_identity_file(options, NULL,
1044 arg, flags & SSHCONF_USERCONF);
1046 break;
1048 case oCertificateFile:
1049 arg = strdelim(&s);
1050 if (!arg || *arg == '\0')
1051 fatal("%.200s line %d: Missing argument.",
1052 filename, linenum);
1053 if (*activep) {
1054 intptr = &options->num_certificate_files;
1055 if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
1056 fatal("%.200s line %d: Too many certificate "
1057 "files specified (max %d).",
1058 filename, linenum,
1059 SSH_MAX_CERTIFICATE_FILES);
1061 add_certificate_file(options, arg,
1062 flags & SSHCONF_USERCONF);
1064 break;
1066 case oXAuthLocation:
1067 charptr=&options->xauth_location;
1068 goto parse_string;
1070 case oUser:
1071 charptr = &options->user;
1072 parse_string:
1073 arg = strdelim(&s);
1074 if (!arg || *arg == '\0')
1075 fatal("%.200s line %d: Missing argument.",
1076 filename, linenum);
1077 if (*activep && *charptr == NULL)
1078 *charptr = xstrdup(arg);
1079 break;
1081 case oGlobalKnownHostsFile:
1082 cpptr = (char **)&options->system_hostfiles;
1083 uintptr = &options->num_system_hostfiles;
1084 max_entries = SSH_MAX_HOSTS_FILES;
1085 parse_char_array:
1086 if (*activep && *uintptr == 0) {
1087 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1088 if ((*uintptr) >= max_entries)
1089 fatal("%s line %d: "
1090 "too many authorized keys files.",
1091 filename, linenum);
1092 cpptr[(*uintptr)++] = xstrdup(arg);
1095 return 0;
1097 case oUserKnownHostsFile:
1098 cpptr = (char **)&options->user_hostfiles;
1099 uintptr = &options->num_user_hostfiles;
1100 max_entries = SSH_MAX_HOSTS_FILES;
1101 goto parse_char_array;
1103 case oHostName:
1104 charptr = &options->hostname;
1105 goto parse_string;
1107 case oHostKeyAlias:
1108 charptr = &options->host_key_alias;
1109 goto parse_string;
1111 case oPreferredAuthentications:
1112 charptr = &options->preferred_authentications;
1113 goto parse_string;
1115 case oBindAddress:
1116 charptr = &options->bind_address;
1117 goto parse_string;
1119 case oPKCS11Provider:
1120 charptr = &options->pkcs11_provider;
1121 goto parse_string;
1123 case oProxyCommand:
1124 charptr = &options->proxy_command;
1125 /* Ignore ProxyCommand if ProxyJump already specified */
1126 if (options->jump_host != NULL)
1127 charptr = &options->jump_host; /* Skip below */
1128 parse_command:
1129 if (s == NULL)
1130 fatal("%.200s line %d: Missing argument.", filename, linenum);
1131 len = strspn(s, WHITESPACE "=");
1132 if (*activep && *charptr == NULL)
1133 *charptr = xstrdup(s + len);
1134 return 0;
1136 case oProxyJump:
1137 if (s == NULL) {
1138 fatal("%.200s line %d: Missing argument.",
1139 filename, linenum);
1141 len = strspn(s, WHITESPACE "=");
1142 if (parse_jump(s + len, options, *activep) == -1) {
1143 fatal("%.200s line %d: Invalid ProxyJump \"%s\"",
1144 filename, linenum, s + len);
1146 return 0;
1148 case oPort:
1149 intptr = &options->port;
1150 parse_int:
1151 arg = strdelim(&s);
1152 if (!arg || *arg == '\0')
1153 fatal("%.200s line %d: Missing argument.", filename, linenum);
1154 if (arg[0] < '0' || arg[0] > '9')
1155 fatal("%.200s line %d: Bad number.", filename, linenum);
1157 /* Octal, decimal, or hex format? */
1158 value = strtol(arg, &endofnumber, 0);
1159 if (arg == endofnumber)
1160 fatal("%.200s line %d: Bad number.", filename, linenum);
1161 if (*activep && *intptr == -1)
1162 *intptr = value;
1163 break;
1165 case oConnectionAttempts:
1166 intptr = &options->connection_attempts;
1167 goto parse_int;
1169 case oCipher:
1170 intptr = &options->cipher;
1171 arg = strdelim(&s);
1172 if (!arg || *arg == '\0')
1173 fatal("%.200s line %d: Missing argument.", filename, linenum);
1174 value = cipher_number(arg);
1175 if (value == -1)
1176 fatal("%.200s line %d: Bad cipher '%s'.",
1177 filename, linenum, arg ? arg : "<NONE>");
1178 if (*activep && *intptr == -1)
1179 *intptr = value;
1180 break;
1182 case oCiphers:
1183 arg = strdelim(&s);
1184 if (!arg || *arg == '\0')
1185 fatal("%.200s line %d: Missing argument.", filename, linenum);
1186 if (!ciphers_valid(*arg == '+' ? arg + 1 : arg))
1187 fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
1188 filename, linenum, arg ? arg : "<NONE>");
1189 if (*activep && options->ciphers == NULL)
1190 options->ciphers = xstrdup(arg);
1191 break;
1193 case oMacs:
1194 arg = strdelim(&s);
1195 if (!arg || *arg == '\0')
1196 fatal("%.200s line %d: Missing argument.", filename, linenum);
1197 if (!mac_valid(*arg == '+' ? arg + 1 : arg))
1198 fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
1199 filename, linenum, arg ? arg : "<NONE>");
1200 if (*activep && options->macs == NULL)
1201 options->macs = xstrdup(arg);
1202 break;
1204 case oKexAlgorithms:
1205 arg = strdelim(&s);
1206 if (!arg || *arg == '\0')
1207 fatal("%.200s line %d: Missing argument.",
1208 filename, linenum);
1209 if (!kex_names_valid(*arg == '+' ? arg + 1 : arg))
1210 fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
1211 filename, linenum, arg ? arg : "<NONE>");
1212 if (*activep && options->kex_algorithms == NULL)
1213 options->kex_algorithms = xstrdup(arg);
1214 break;
1216 case oHostKeyAlgorithms:
1217 charptr = &options->hostkeyalgorithms;
1218 parse_keytypes:
1219 arg = strdelim(&s);
1220 if (!arg || *arg == '\0')
1221 fatal("%.200s line %d: Missing argument.",
1222 filename, linenum);
1223 if (!sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1))
1224 fatal("%s line %d: Bad key types '%s'.",
1225 filename, linenum, arg ? arg : "<NONE>");
1226 if (*activep && *charptr == NULL)
1227 *charptr = xstrdup(arg);
1228 break;
1230 case oProtocol:
1231 intptr = &options->protocol;
1232 arg = strdelim(&s);
1233 if (!arg || *arg == '\0')
1234 fatal("%.200s line %d: Missing argument.", filename, linenum);
1235 value = proto_spec(arg);
1236 if (value == SSH_PROTO_UNKNOWN)
1237 fatal("%.200s line %d: Bad protocol spec '%s'.",
1238 filename, linenum, arg ? arg : "<NONE>");
1239 if (*activep && *intptr == SSH_PROTO_UNKNOWN)
1240 *intptr = value;
1241 break;
1243 case oLogLevel:
1244 log_level_ptr = &options->log_level;
1245 arg = strdelim(&s);
1246 value = log_level_number(arg);
1247 if (value == SYSLOG_LEVEL_NOT_SET)
1248 fatal("%.200s line %d: unsupported log level '%s'",
1249 filename, linenum, arg ? arg : "<NONE>");
1250 if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1251 *log_level_ptr = (LogLevel) value;
1252 break;
1254 case oLocalForward:
1255 case oRemoteForward:
1256 case oDynamicForward:
1257 arg = strdelim(&s);
1258 if (arg == NULL || *arg == '\0')
1259 fatal("%.200s line %d: Missing port argument.",
1260 filename, linenum);
1262 if (opcode == oLocalForward ||
1263 opcode == oRemoteForward) {
1264 arg2 = strdelim(&s);
1265 if (arg2 == NULL || *arg2 == '\0')
1266 fatal("%.200s line %d: Missing target argument.",
1267 filename, linenum);
1269 /* construct a string for parse_forward */
1270 snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
1271 } else if (opcode == oDynamicForward) {
1272 strlcpy(fwdarg, arg, sizeof(fwdarg));
1275 if (parse_forward(&fwd, fwdarg,
1276 opcode == oDynamicForward ? 1 : 0,
1277 opcode == oRemoteForward ? 1 : 0) == 0)
1278 fatal("%.200s line %d: Bad forwarding specification.",
1279 filename, linenum);
1281 if (*activep) {
1282 if (opcode == oLocalForward ||
1283 opcode == oDynamicForward)
1284 add_local_forward(options, &fwd);
1285 else if (opcode == oRemoteForward)
1286 add_remote_forward(options, &fwd);
1288 break;
1290 case oClearAllForwardings:
1291 intptr = &options->clear_forwardings;
1292 goto parse_flag;
1294 case oHost:
1295 if (cmdline)
1296 fatal("Host directive not supported as a command-line "
1297 "option");
1298 *activep = 0;
1299 arg2 = NULL;
1300 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1301 if ((flags & SSHCONF_NEVERMATCH) != 0)
1302 break;
1303 negated = *arg == '!';
1304 if (negated)
1305 arg++;
1306 if (match_pattern(host, arg)) {
1307 if (negated) {
1308 debug("%.200s line %d: Skipping Host "
1309 "block because of negated match "
1310 "for %.100s", filename, linenum,
1311 arg);
1312 *activep = 0;
1313 break;
1315 if (!*activep)
1316 arg2 = arg; /* logged below */
1317 *activep = 1;
1320 if (*activep)
1321 debug("%.200s line %d: Applying options for %.100s",
1322 filename, linenum, arg2);
1323 /* Avoid garbage check below, as strdelim is done. */
1324 return 0;
1326 case oMatch:
1327 if (cmdline)
1328 fatal("Host directive not supported as a command-line "
1329 "option");
1330 value = match_cfg_line(options, &s, pw, host, original_host,
1331 flags & SSHCONF_POSTCANON, filename, linenum);
1332 if (value < 0)
1333 fatal("%.200s line %d: Bad Match condition", filename,
1334 linenum);
1335 *activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
1336 break;
1338 case oEscapeChar:
1339 intptr = &options->escape_char;
1340 arg = strdelim(&s);
1341 if (!arg || *arg == '\0')
1342 fatal("%.200s line %d: Missing argument.", filename, linenum);
1343 if (strcmp(arg, "none") == 0)
1344 value = SSH_ESCAPECHAR_NONE;
1345 else if (arg[1] == '\0')
1346 value = (u_char) arg[0];
1347 else if (arg[0] == '^' && arg[2] == 0 &&
1348 (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1349 value = (u_char) arg[1] & 31;
1350 else {
1351 fatal("%.200s line %d: Bad escape character.",
1352 filename, linenum);
1353 /* NOTREACHED */
1354 value = 0; /* Avoid compiler warning. */
1356 if (*activep && *intptr == -1)
1357 *intptr = value;
1358 break;
1360 case oAddressFamily:
1361 intptr = &options->address_family;
1362 multistate_ptr = multistate_addressfamily;
1363 goto parse_multistate;
1365 case oEnableSSHKeysign:
1366 intptr = &options->enable_ssh_keysign;
1367 goto parse_flag;
1369 case oIdentitiesOnly:
1370 intptr = &options->identities_only;
1371 goto parse_flag;
1373 case oServerAliveInterval:
1374 intptr = &options->server_alive_interval;
1375 goto parse_time;
1377 case oServerAliveCountMax:
1378 intptr = &options->server_alive_count_max;
1379 goto parse_int;
1381 case oSendEnv:
1382 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1383 if (strchr(arg, '=') != NULL)
1384 fatal("%s line %d: Invalid environment name.",
1385 filename, linenum);
1386 if (!*activep)
1387 continue;
1388 if (options->num_send_env >= MAX_SEND_ENV)
1389 fatal("%s line %d: too many send env.",
1390 filename, linenum);
1391 options->send_env[options->num_send_env++] =
1392 xstrdup(arg);
1394 break;
1396 case oControlPath:
1397 charptr = &options->control_path;
1398 goto parse_string;
1400 case oControlMaster:
1401 intptr = &options->control_master;
1402 multistate_ptr = multistate_controlmaster;
1403 goto parse_multistate;
1405 case oControlPersist:
1406 /* no/false/yes/true, or a time spec */
1407 intptr = &options->control_persist;
1408 arg = strdelim(&s);
1409 if (!arg || *arg == '\0')
1410 fatal("%.200s line %d: Missing ControlPersist"
1411 " argument.", filename, linenum);
1412 value = 0;
1413 value2 = 0; /* timeout */
1414 if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1415 value = 0;
1416 else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1417 value = 1;
1418 else if ((value2 = convtime(arg)) >= 0)
1419 value = 1;
1420 else
1421 fatal("%.200s line %d: Bad ControlPersist argument.",
1422 filename, linenum);
1423 if (*activep && *intptr == -1) {
1424 *intptr = value;
1425 options->control_persist_timeout = value2;
1427 break;
1429 case oHashKnownHosts:
1430 intptr = &options->hash_known_hosts;
1431 goto parse_flag;
1433 case oTunnel:
1434 intptr = &options->tun_open;
1435 multistate_ptr = multistate_tunnel;
1436 goto parse_multistate;
1438 case oTunnelDevice:
1439 arg = strdelim(&s);
1440 if (!arg || *arg == '\0')
1441 fatal("%.200s line %d: Missing argument.", filename, linenum);
1442 value = a2tun(arg, &value2);
1443 if (value == SSH_TUNID_ERR)
1444 fatal("%.200s line %d: Bad tun device.", filename, linenum);
1445 if (*activep) {
1446 options->tun_local = value;
1447 options->tun_remote = value2;
1449 break;
1451 case oLocalCommand:
1452 charptr = &options->local_command;
1453 goto parse_command;
1455 case oPermitLocalCommand:
1456 intptr = &options->permit_local_command;
1457 goto parse_flag;
1459 case oVisualHostKey:
1460 intptr = &options->visual_host_key;
1461 goto parse_flag;
1463 case oInclude:
1464 if (cmdline)
1465 fatal("Include directive not supported as a "
1466 "command-line option");
1467 value = 0;
1468 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1470 * Ensure all paths are anchored. User configuration
1471 * files may begin with '~/' but system configurations
1472 * must not. If the path is relative, then treat it
1473 * as living in ~/.ssh for user configurations or
1474 * /etc/ssh for system ones.
1476 if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0)
1477 fatal("%.200s line %d: bad include path %s.",
1478 filename, linenum, arg);
1479 if (*arg != '/' && *arg != '~') {
1480 xasprintf(&arg2, "%s/%s",
1481 (flags & SSHCONF_USERCONF) ?
1482 "~/" _PATH_SSH_USER_DIR : SSHDIR, arg);
1483 } else
1484 arg2 = xstrdup(arg);
1485 memset(&gl, 0, sizeof(gl));
1486 r = glob(arg2, GLOB_TILDE, NULL, &gl);
1487 if (r == GLOB_NOMATCH) {
1488 debug("%.200s line %d: include %s matched no "
1489 "files",filename, linenum, arg2);
1490 continue;
1491 } else if (r != 0 || gl.gl_pathc < 0)
1492 fatal("%.200s line %d: glob failed for %s.",
1493 filename, linenum, arg2);
1494 free(arg2);
1495 oactive = *activep;
1496 for (i = 0; i < (u_int)gl.gl_pathc; i++) {
1497 debug3("%.200s line %d: Including file %s "
1498 "depth %d%s", filename, linenum,
1499 gl.gl_pathv[i], depth,
1500 oactive ? "" : " (parse only)");
1501 r = read_config_file_depth(gl.gl_pathv[i],
1502 pw, host, original_host, options,
1503 flags | SSHCONF_CHECKPERM |
1504 (oactive ? 0 : SSHCONF_NEVERMATCH),
1505 activep, depth + 1);
1507 * don't let Match in includes clobber the
1508 * containing file's Match state.
1510 *activep = oactive;
1511 if (r != 1)
1512 value = -1;
1514 globfree(&gl);
1516 if (value != 0)
1517 return value;
1518 break;
1520 case oIPQoS:
1521 arg = strdelim(&s);
1522 if ((value = parse_ipqos(arg)) == -1)
1523 fatal("%s line %d: Bad IPQoS value: %s",
1524 filename, linenum, arg);
1525 arg = strdelim(&s);
1526 if (arg == NULL)
1527 value2 = value;
1528 else if ((value2 = parse_ipqos(arg)) == -1)
1529 fatal("%s line %d: Bad IPQoS value: %s",
1530 filename, linenum, arg);
1531 if (*activep) {
1532 options->ip_qos_interactive = value;
1533 options->ip_qos_bulk = value2;
1535 break;
1537 case oRequestTTY:
1538 intptr = &options->request_tty;
1539 multistate_ptr = multistate_requesttty;
1540 goto parse_multistate;
1542 case oIgnoreUnknown:
1543 charptr = &options->ignored_unknown;
1544 goto parse_string;
1546 case oProxyUseFdpass:
1547 intptr = &options->proxy_use_fdpass;
1548 goto parse_flag;
1550 case oCanonicalDomains:
1551 value = options->num_canonical_domains != 0;
1552 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1553 valid_domain(arg, filename, linenum);
1554 if (!*activep || value)
1555 continue;
1556 if (options->num_canonical_domains >= MAX_CANON_DOMAINS)
1557 fatal("%s line %d: too many hostname suffixes.",
1558 filename, linenum);
1559 options->canonical_domains[
1560 options->num_canonical_domains++] = xstrdup(arg);
1562 break;
1564 case oCanonicalizePermittedCNAMEs:
1565 value = options->num_permitted_cnames != 0;
1566 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1567 /* Either '*' for everything or 'list:list' */
1568 if (strcmp(arg, "*") == 0)
1569 arg2 = arg;
1570 else {
1571 lowercase(arg);
1572 if ((arg2 = strchr(arg, ':')) == NULL ||
1573 arg2[1] == '\0') {
1574 fatal("%s line %d: "
1575 "Invalid permitted CNAME \"%s\"",
1576 filename, linenum, arg);
1578 *arg2 = '\0';
1579 arg2++;
1581 if (!*activep || value)
1582 continue;
1583 if (options->num_permitted_cnames >= MAX_CANON_DOMAINS)
1584 fatal("%s line %d: too many permitted CNAMEs.",
1585 filename, linenum);
1586 cname = options->permitted_cnames +
1587 options->num_permitted_cnames++;
1588 cname->source_list = xstrdup(arg);
1589 cname->target_list = xstrdup(arg2);
1591 break;
1593 case oCanonicalizeHostname:
1594 intptr = &options->canonicalize_hostname;
1595 multistate_ptr = multistate_canonicalizehostname;
1596 goto parse_multistate;
1598 case oCanonicalizeMaxDots:
1599 intptr = &options->canonicalize_max_dots;
1600 goto parse_int;
1602 case oCanonicalizeFallbackLocal:
1603 intptr = &options->canonicalize_fallback_local;
1604 goto parse_flag;
1606 case oStreamLocalBindMask:
1607 arg = strdelim(&s);
1608 if (!arg || *arg == '\0')
1609 fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum);
1610 /* Parse mode in octal format */
1611 value = strtol(arg, &endofnumber, 8);
1612 if (arg == endofnumber || value < 0 || value > 0777)
1613 fatal("%.200s line %d: Bad mask.", filename, linenum);
1614 options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
1615 break;
1617 case oStreamLocalBindUnlink:
1618 intptr = &options->fwd_opts.streamlocal_bind_unlink;
1619 goto parse_flag;
1621 case oRevokedHostKeys:
1622 charptr = &options->revoked_host_keys;
1623 goto parse_string;
1625 case oFingerprintHash:
1626 intptr = &options->fingerprint_hash;
1627 arg = strdelim(&s);
1628 if (!arg || *arg == '\0')
1629 fatal("%.200s line %d: Missing argument.",
1630 filename, linenum);
1631 if ((value = ssh_digest_alg_by_name(arg)) == -1)
1632 fatal("%.200s line %d: Invalid hash algorithm \"%s\".",
1633 filename, linenum, arg);
1634 if (*activep && *intptr == -1)
1635 *intptr = value;
1636 break;
1638 case oUpdateHostkeys:
1639 intptr = &options->update_hostkeys;
1640 multistate_ptr = multistate_yesnoask;
1641 goto parse_multistate;
1643 case oHostbasedKeyTypes:
1644 charptr = &options->hostbased_key_types;
1645 goto parse_keytypes;
1647 case oPubkeyAcceptedKeyTypes:
1648 charptr = &options->pubkey_key_types;
1649 goto parse_keytypes;
1651 case oAddKeysToAgent:
1652 intptr = &options->add_keys_to_agent;
1653 multistate_ptr = multistate_yesnoaskconfirm;
1654 goto parse_multistate;
1656 case oIdentityAgent:
1657 charptr = &options->identity_agent;
1658 goto parse_string;
1660 case oDeprecated:
1661 debug("%s line %d: Deprecated option \"%s\"",
1662 filename, linenum, keyword);
1663 return 0;
1665 case oUnsupported:
1666 error("%s line %d: Unsupported option \"%s\"",
1667 filename, linenum, keyword);
1668 return 0;
1670 default:
1671 fatal("%s: Unimplemented opcode %d", __func__, opcode);
1674 /* Check that there is no garbage at end of line. */
1675 if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1676 fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
1677 filename, linenum, arg);
1679 return 0;
1683 * Reads the config file and modifies the options accordingly. Options
1684 * should already be initialized before this call. This never returns if
1685 * there is an error. If the file does not exist, this returns 0.
1688 read_config_file(const char *filename, struct passwd *pw, const char *host,
1689 const char *original_host, Options *options, int flags)
1691 int active = 1;
1693 return read_config_file_depth(filename, pw, host, original_host,
1694 options, flags, &active, 0);
1697 #define READCONF_MAX_DEPTH 16
1698 static int
1699 read_config_file_depth(const char *filename, struct passwd *pw,
1700 const char *host, const char *original_host, Options *options,
1701 int flags, int *activep, int depth)
1703 FILE *f;
1704 char line[1024];
1705 int linenum;
1706 int bad_options = 0;
1708 if (depth < 0 || depth > READCONF_MAX_DEPTH)
1709 fatal("Too many recursive configuration includes");
1711 if ((f = fopen(filename, "r")) == NULL)
1712 return 0;
1714 if (flags & SSHCONF_CHECKPERM) {
1715 struct stat sb;
1717 if (fstat(fileno(f), &sb) == -1)
1718 fatal("fstat %s: %s", filename, strerror(errno));
1719 if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
1720 (sb.st_mode & 022) != 0))
1721 fatal("Bad owner or permissions on %s", filename);
1724 debug("Reading configuration data %.200s", filename);
1727 * Mark that we are now processing the options. This flag is turned
1728 * on/off by Host specifications.
1730 linenum = 0;
1731 while (fgets(line, sizeof(line), f)) {
1732 /* Update line number counter. */
1733 linenum++;
1734 if (process_config_line_depth(options, pw, host, original_host,
1735 line, filename, linenum, activep, flags, depth) != 0)
1736 bad_options++;
1738 fclose(f);
1739 if (bad_options > 0)
1740 fatal("%s: terminating, %d bad configuration options",
1741 filename, bad_options);
1742 return 1;
1745 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
1747 option_clear_or_none(const char *o)
1749 return o == NULL || strcasecmp(o, "none") == 0;
1753 * Initializes options to special values that indicate that they have not yet
1754 * been set. Read_config_file will only set options with this value. Options
1755 * are processed in the following order: command line, user config file,
1756 * system config file. Last, fill_default_options is called.
1759 void
1760 initialize_options(Options * options)
1762 memset(options, 'X', sizeof(*options));
1763 options->forward_agent = -1;
1764 options->forward_x11 = -1;
1765 options->forward_x11_trusted = -1;
1766 options->forward_x11_timeout = -1;
1767 options->stdio_forward_host = NULL;
1768 options->stdio_forward_port = 0;
1769 options->clear_forwardings = -1;
1770 options->exit_on_forward_failure = -1;
1771 options->xauth_location = NULL;
1772 options->fwd_opts.gateway_ports = -1;
1773 options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
1774 options->fwd_opts.streamlocal_bind_unlink = -1;
1775 options->use_privileged_port = -1;
1776 options->rsa_authentication = -1;
1777 options->pubkey_authentication = -1;
1778 options->challenge_response_authentication = -1;
1779 options->gss_authentication = -1;
1780 options->gss_deleg_creds = -1;
1781 options->password_authentication = -1;
1782 options->kbd_interactive_authentication = -1;
1783 options->kbd_interactive_devices = NULL;
1784 options->rhosts_rsa_authentication = -1;
1785 options->hostbased_authentication = -1;
1786 options->batch_mode = -1;
1787 options->check_host_ip = -1;
1788 options->strict_host_key_checking = -1;
1789 options->compression = -1;
1790 options->tcp_keep_alive = -1;
1791 options->compression_level = -1;
1792 options->port = -1;
1793 options->address_family = -1;
1794 options->connection_attempts = -1;
1795 options->connection_timeout = -1;
1796 options->number_of_password_prompts = -1;
1797 options->cipher = -1;
1798 options->ciphers = NULL;
1799 options->macs = NULL;
1800 options->kex_algorithms = NULL;
1801 options->hostkeyalgorithms = NULL;
1802 options->protocol = SSH_PROTO_UNKNOWN;
1803 options->num_identity_files = 0;
1804 options->num_certificate_files = 0;
1805 options->hostname = NULL;
1806 options->host_key_alias = NULL;
1807 options->proxy_command = NULL;
1808 options->jump_user = NULL;
1809 options->jump_host = NULL;
1810 options->jump_port = -1;
1811 options->jump_extra = NULL;
1812 options->user = NULL;
1813 options->escape_char = -1;
1814 options->num_system_hostfiles = 0;
1815 options->num_user_hostfiles = 0;
1816 options->local_forwards = NULL;
1817 options->num_local_forwards = 0;
1818 options->remote_forwards = NULL;
1819 options->num_remote_forwards = 0;
1820 options->log_level = SYSLOG_LEVEL_NOT_SET;
1821 options->preferred_authentications = NULL;
1822 options->bind_address = NULL;
1823 options->pkcs11_provider = NULL;
1824 options->enable_ssh_keysign = - 1;
1825 options->no_host_authentication_for_localhost = - 1;
1826 options->identities_only = - 1;
1827 options->rekey_limit = - 1;
1828 options->rekey_interval = -1;
1829 options->verify_host_key_dns = -1;
1830 options->server_alive_interval = -1;
1831 options->server_alive_count_max = -1;
1832 options->num_send_env = 0;
1833 options->control_path = NULL;
1834 options->control_master = -1;
1835 options->control_persist = -1;
1836 options->control_persist_timeout = 0;
1837 options->hash_known_hosts = -1;
1838 options->tun_open = -1;
1839 options->tun_local = -1;
1840 options->tun_remote = -1;
1841 options->local_command = NULL;
1842 options->permit_local_command = -1;
1843 options->add_keys_to_agent = -1;
1844 options->identity_agent = NULL;
1845 options->visual_host_key = -1;
1846 options->ip_qos_interactive = -1;
1847 options->ip_qos_bulk = -1;
1848 options->request_tty = -1;
1849 options->proxy_use_fdpass = -1;
1850 options->ignored_unknown = NULL;
1851 options->num_canonical_domains = 0;
1852 options->num_permitted_cnames = 0;
1853 options->canonicalize_max_dots = -1;
1854 options->canonicalize_fallback_local = -1;
1855 options->canonicalize_hostname = -1;
1856 options->revoked_host_keys = NULL;
1857 options->fingerprint_hash = -1;
1858 options->update_hostkeys = -1;
1859 options->hostbased_key_types = NULL;
1860 options->pubkey_key_types = NULL;
1864 * A petite version of fill_default_options() that just fills the options
1865 * needed for hostname canonicalization to proceed.
1867 void
1868 fill_default_options_for_canonicalization(Options *options)
1870 if (options->canonicalize_max_dots == -1)
1871 options->canonicalize_max_dots = 1;
1872 if (options->canonicalize_fallback_local == -1)
1873 options->canonicalize_fallback_local = 1;
1874 if (options->canonicalize_hostname == -1)
1875 options->canonicalize_hostname = SSH_CANONICALISE_NO;
1879 * Called after processing other sources of option data, this fills those
1880 * options for which no value has been specified with their default values.
1882 void
1883 fill_default_options(Options * options)
1885 if (options->forward_agent == -1)
1886 options->forward_agent = 0;
1887 if (options->forward_x11 == -1)
1888 options->forward_x11 = 0;
1889 if (options->forward_x11_trusted == -1)
1890 options->forward_x11_trusted = 0;
1891 if (options->forward_x11_timeout == -1)
1892 options->forward_x11_timeout = 1200;
1894 * stdio forwarding (-W) changes the default for these but we defer
1895 * setting the values so they can be overridden.
1897 if (options->exit_on_forward_failure == -1)
1898 options->exit_on_forward_failure =
1899 options->stdio_forward_host != NULL ? 1 : 0;
1900 if (options->clear_forwardings == -1)
1901 options->clear_forwardings =
1902 options->stdio_forward_host != NULL ? 1 : 0;
1903 if (options->clear_forwardings == 1)
1904 clear_forwardings(options);
1906 if (options->xauth_location == NULL)
1907 options->xauth_location = _PATH_XAUTH;
1908 if (options->fwd_opts.gateway_ports == -1)
1909 options->fwd_opts.gateway_ports = 0;
1910 if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
1911 options->fwd_opts.streamlocal_bind_mask = 0177;
1912 if (options->fwd_opts.streamlocal_bind_unlink == -1)
1913 options->fwd_opts.streamlocal_bind_unlink = 0;
1914 if (options->use_privileged_port == -1)
1915 options->use_privileged_port = 0;
1916 if (options->rsa_authentication == -1)
1917 options->rsa_authentication = 1;
1918 if (options->pubkey_authentication == -1)
1919 options->pubkey_authentication = 1;
1920 if (options->challenge_response_authentication == -1)
1921 options->challenge_response_authentication = 1;
1922 if (options->gss_authentication == -1)
1923 options->gss_authentication = 0;
1924 if (options->gss_deleg_creds == -1)
1925 options->gss_deleg_creds = 0;
1926 if (options->password_authentication == -1)
1927 options->password_authentication = 1;
1928 if (options->kbd_interactive_authentication == -1)
1929 options->kbd_interactive_authentication = 1;
1930 if (options->rhosts_rsa_authentication == -1)
1931 options->rhosts_rsa_authentication = 0;
1932 if (options->hostbased_authentication == -1)
1933 options->hostbased_authentication = 0;
1934 if (options->batch_mode == -1)
1935 options->batch_mode = 0;
1936 if (options->check_host_ip == -1)
1937 options->check_host_ip = 1;
1938 if (options->strict_host_key_checking == -1)
1939 options->strict_host_key_checking = 2; /* 2 is default */
1940 if (options->compression == -1)
1941 options->compression = 0;
1942 if (options->tcp_keep_alive == -1)
1943 options->tcp_keep_alive = 1;
1944 if (options->compression_level == -1)
1945 options->compression_level = 6;
1946 if (options->port == -1)
1947 options->port = 0; /* Filled in ssh_connect. */
1948 if (options->address_family == -1)
1949 options->address_family = AF_UNSPEC;
1950 if (options->connection_attempts == -1)
1951 options->connection_attempts = 1;
1952 if (options->number_of_password_prompts == -1)
1953 options->number_of_password_prompts = 3;
1954 /* Selected in ssh_login(). */
1955 if (options->cipher == -1)
1956 options->cipher = SSH_CIPHER_NOT_SET;
1957 /* options->hostkeyalgorithms, default set in myproposals.h */
1958 if (options->protocol == SSH_PROTO_UNKNOWN)
1959 options->protocol = SSH_PROTO_2;
1960 if (options->add_keys_to_agent == -1)
1961 options->add_keys_to_agent = 0;
1962 if (options->num_identity_files == 0) {
1963 if (options->protocol & SSH_PROTO_1) {
1964 add_identity_file(options, "~/",
1965 _PATH_SSH_CLIENT_IDENTITY, 0);
1967 if (options->protocol & SSH_PROTO_2) {
1968 add_identity_file(options, "~/",
1969 _PATH_SSH_CLIENT_ID_RSA, 0);
1970 add_identity_file(options, "~/",
1971 _PATH_SSH_CLIENT_ID_DSA, 0);
1972 #ifdef OPENSSL_HAS_ECC
1973 add_identity_file(options, "~/",
1974 _PATH_SSH_CLIENT_ID_ECDSA, 0);
1975 #endif
1976 add_identity_file(options, "~/",
1977 _PATH_SSH_CLIENT_ID_ED25519, 0);
1980 if (options->escape_char == -1)
1981 options->escape_char = '~';
1982 if (options->num_system_hostfiles == 0) {
1983 options->system_hostfiles[options->num_system_hostfiles++] =
1984 xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
1985 options->system_hostfiles[options->num_system_hostfiles++] =
1986 xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
1988 if (options->num_user_hostfiles == 0) {
1989 options->user_hostfiles[options->num_user_hostfiles++] =
1990 xstrdup(_PATH_SSH_USER_HOSTFILE);
1991 options->user_hostfiles[options->num_user_hostfiles++] =
1992 xstrdup(_PATH_SSH_USER_HOSTFILE2);
1994 if (options->log_level == SYSLOG_LEVEL_NOT_SET)
1995 options->log_level = SYSLOG_LEVEL_INFO;
1996 if (options->no_host_authentication_for_localhost == - 1)
1997 options->no_host_authentication_for_localhost = 0;
1998 if (options->identities_only == -1)
1999 options->identities_only = 0;
2000 if (options->enable_ssh_keysign == -1)
2001 options->enable_ssh_keysign = 0;
2002 if (options->rekey_limit == -1)
2003 options->rekey_limit = 0;
2004 if (options->rekey_interval == -1)
2005 options->rekey_interval = 0;
2006 if (options->verify_host_key_dns == -1)
2007 options->verify_host_key_dns = 0;
2008 if (options->server_alive_interval == -1)
2009 options->server_alive_interval = 0;
2010 if (options->server_alive_count_max == -1)
2011 options->server_alive_count_max = 3;
2012 if (options->control_master == -1)
2013 options->control_master = 0;
2014 if (options->control_persist == -1) {
2015 options->control_persist = 0;
2016 options->control_persist_timeout = 0;
2018 if (options->hash_known_hosts == -1)
2019 options->hash_known_hosts = 0;
2020 if (options->tun_open == -1)
2021 options->tun_open = SSH_TUNMODE_NO;
2022 if (options->tun_local == -1)
2023 options->tun_local = SSH_TUNID_ANY;
2024 if (options->tun_remote == -1)
2025 options->tun_remote = SSH_TUNID_ANY;
2026 if (options->permit_local_command == -1)
2027 options->permit_local_command = 0;
2028 if (options->visual_host_key == -1)
2029 options->visual_host_key = 0;
2030 if (options->ip_qos_interactive == -1)
2031 options->ip_qos_interactive = IPTOS_LOWDELAY;
2032 if (options->ip_qos_bulk == -1)
2033 options->ip_qos_bulk = IPTOS_THROUGHPUT;
2034 if (options->request_tty == -1)
2035 options->request_tty = REQUEST_TTY_AUTO;
2036 if (options->proxy_use_fdpass == -1)
2037 options->proxy_use_fdpass = 0;
2038 if (options->canonicalize_max_dots == -1)
2039 options->canonicalize_max_dots = 1;
2040 if (options->canonicalize_fallback_local == -1)
2041 options->canonicalize_fallback_local = 1;
2042 if (options->canonicalize_hostname == -1)
2043 options->canonicalize_hostname = SSH_CANONICALISE_NO;
2044 if (options->fingerprint_hash == -1)
2045 options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
2046 if (options->update_hostkeys == -1)
2047 options->update_hostkeys = 0;
2048 if (kex_assemble_names(KEX_CLIENT_ENCRYPT, &options->ciphers) != 0 ||
2049 kex_assemble_names(KEX_CLIENT_MAC, &options->macs) != 0 ||
2050 kex_assemble_names(KEX_CLIENT_KEX, &options->kex_algorithms) != 0 ||
2051 kex_assemble_names(KEX_DEFAULT_PK_ALG,
2052 &options->hostbased_key_types) != 0 ||
2053 kex_assemble_names(KEX_DEFAULT_PK_ALG,
2054 &options->pubkey_key_types) != 0)
2055 fatal("%s: kex_assemble_names failed", __func__);
2057 #define CLEAR_ON_NONE(v) \
2058 do { \
2059 if (option_clear_or_none(v)) { \
2060 free(v); \
2061 v = NULL; \
2063 } while(0)
2064 CLEAR_ON_NONE(options->local_command);
2065 CLEAR_ON_NONE(options->proxy_command);
2066 CLEAR_ON_NONE(options->control_path);
2067 CLEAR_ON_NONE(options->revoked_host_keys);
2068 /* options->identity_agent distinguishes NULL from 'none' */
2069 /* options->user will be set in the main program if appropriate */
2070 /* options->hostname will be set in the main program if appropriate */
2071 /* options->host_key_alias should not be set by default */
2072 /* options->preferred_authentications will be set in ssh */
2075 struct fwdarg {
2076 char *arg;
2077 int ispath;
2081 * parse_fwd_field
2082 * parses the next field in a port forwarding specification.
2083 * sets fwd to the parsed field and advances p past the colon
2084 * or sets it to NULL at end of string.
2085 * returns 0 on success, else non-zero.
2087 static int
2088 parse_fwd_field(char **p, struct fwdarg *fwd)
2090 char *ep, *cp = *p;
2091 int ispath = 0;
2093 if (*cp == '\0') {
2094 *p = NULL;
2095 return -1; /* end of string */
2099 * A field escaped with square brackets is used literally.
2100 * XXX - allow ']' to be escaped via backslash?
2102 if (*cp == '[') {
2103 /* find matching ']' */
2104 for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
2105 if (*ep == '/')
2106 ispath = 1;
2108 /* no matching ']' or not at end of field. */
2109 if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
2110 return -1;
2111 /* NUL terminate the field and advance p past the colon */
2112 *ep++ = '\0';
2113 if (*ep != '\0')
2114 *ep++ = '\0';
2115 fwd->arg = cp + 1;
2116 fwd->ispath = ispath;
2117 *p = ep;
2118 return 0;
2121 for (cp = *p; *cp != '\0'; cp++) {
2122 switch (*cp) {
2123 case '\\':
2124 memmove(cp, cp + 1, strlen(cp + 1) + 1);
2125 if (*cp == '\0')
2126 return -1;
2127 break;
2128 case '/':
2129 ispath = 1;
2130 break;
2131 case ':':
2132 *cp++ = '\0';
2133 goto done;
2136 done:
2137 fwd->arg = *p;
2138 fwd->ispath = ispath;
2139 *p = cp;
2140 return 0;
2144 * parse_forward
2145 * parses a string containing a port forwarding specification of the form:
2146 * dynamicfwd == 0
2147 * [listenhost:]listenport|listenpath:connecthost:connectport|connectpath
2148 * listenpath:connectpath
2149 * dynamicfwd == 1
2150 * [listenhost:]listenport
2151 * returns number of arguments parsed or zero on error
2154 parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
2156 struct fwdarg fwdargs[4];
2157 char *p, *cp;
2158 int i;
2160 memset(fwd, 0, sizeof(*fwd));
2161 memset(fwdargs, 0, sizeof(fwdargs));
2163 cp = p = xstrdup(fwdspec);
2165 /* skip leading spaces */
2166 while (isspace((u_char)*cp))
2167 cp++;
2169 for (i = 0; i < 4; ++i) {
2170 if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
2171 break;
2174 /* Check for trailing garbage */
2175 if (cp != NULL && *cp != '\0') {
2176 i = 0; /* failure */
2179 switch (i) {
2180 case 1:
2181 if (fwdargs[0].ispath) {
2182 fwd->listen_path = xstrdup(fwdargs[0].arg);
2183 fwd->listen_port = PORT_STREAMLOCAL;
2184 } else {
2185 fwd->listen_host = NULL;
2186 fwd->listen_port = a2port(fwdargs[0].arg);
2188 fwd->connect_host = xstrdup("socks");
2189 break;
2191 case 2:
2192 if (fwdargs[0].ispath && fwdargs[1].ispath) {
2193 fwd->listen_path = xstrdup(fwdargs[0].arg);
2194 fwd->listen_port = PORT_STREAMLOCAL;
2195 fwd->connect_path = xstrdup(fwdargs[1].arg);
2196 fwd->connect_port = PORT_STREAMLOCAL;
2197 } else if (fwdargs[1].ispath) {
2198 fwd->listen_host = NULL;
2199 fwd->listen_port = a2port(fwdargs[0].arg);
2200 fwd->connect_path = xstrdup(fwdargs[1].arg);
2201 fwd->connect_port = PORT_STREAMLOCAL;
2202 } else {
2203 fwd->listen_host = xstrdup(fwdargs[0].arg);
2204 fwd->listen_port = a2port(fwdargs[1].arg);
2205 fwd->connect_host = xstrdup("socks");
2207 break;
2209 case 3:
2210 if (fwdargs[0].ispath) {
2211 fwd->listen_path = xstrdup(fwdargs[0].arg);
2212 fwd->listen_port = PORT_STREAMLOCAL;
2213 fwd->connect_host = xstrdup(fwdargs[1].arg);
2214 fwd->connect_port = a2port(fwdargs[2].arg);
2215 } else if (fwdargs[2].ispath) {
2216 fwd->listen_host = xstrdup(fwdargs[0].arg);
2217 fwd->listen_port = a2port(fwdargs[1].arg);
2218 fwd->connect_path = xstrdup(fwdargs[2].arg);
2219 fwd->connect_port = PORT_STREAMLOCAL;
2220 } else {
2221 fwd->listen_host = NULL;
2222 fwd->listen_port = a2port(fwdargs[0].arg);
2223 fwd->connect_host = xstrdup(fwdargs[1].arg);
2224 fwd->connect_port = a2port(fwdargs[2].arg);
2226 break;
2228 case 4:
2229 fwd->listen_host = xstrdup(fwdargs[0].arg);
2230 fwd->listen_port = a2port(fwdargs[1].arg);
2231 fwd->connect_host = xstrdup(fwdargs[2].arg);
2232 fwd->connect_port = a2port(fwdargs[3].arg);
2233 break;
2234 default:
2235 i = 0; /* failure */
2238 free(p);
2240 if (dynamicfwd) {
2241 if (!(i == 1 || i == 2))
2242 goto fail_free;
2243 } else {
2244 if (!(i == 3 || i == 4)) {
2245 if (fwd->connect_path == NULL &&
2246 fwd->listen_path == NULL)
2247 goto fail_free;
2249 if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
2250 goto fail_free;
2253 if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
2254 (!remotefwd && fwd->listen_port == 0))
2255 goto fail_free;
2256 if (fwd->connect_host != NULL &&
2257 strlen(fwd->connect_host) >= NI_MAXHOST)
2258 goto fail_free;
2259 /* XXX - if connecting to a remote socket, max sun len may not match this host */
2260 if (fwd->connect_path != NULL &&
2261 strlen(fwd->connect_path) >= PATH_MAX_SUN)
2262 goto fail_free;
2263 if (fwd->listen_host != NULL &&
2264 strlen(fwd->listen_host) >= NI_MAXHOST)
2265 goto fail_free;
2266 if (fwd->listen_path != NULL &&
2267 strlen(fwd->listen_path) >= PATH_MAX_SUN)
2268 goto fail_free;
2270 return (i);
2272 fail_free:
2273 free(fwd->connect_host);
2274 fwd->connect_host = NULL;
2275 free(fwd->connect_path);
2276 fwd->connect_path = NULL;
2277 free(fwd->listen_host);
2278 fwd->listen_host = NULL;
2279 free(fwd->listen_path);
2280 fwd->listen_path = NULL;
2281 return (0);
2285 parse_jump(const char *s, Options *o, int active)
2287 char *orig, *sdup, *cp;
2288 char *host = NULL, *user = NULL;
2289 int ret = -1, port = -1, first;
2291 active &= o->proxy_command == NULL && o->jump_host == NULL;
2293 orig = sdup = xstrdup(s);
2294 first = active;
2295 do {
2296 if ((cp = strrchr(sdup, ',')) == NULL)
2297 cp = sdup; /* last */
2298 else
2299 *cp++ = '\0';
2301 if (first) {
2302 /* First argument and configuration is active */
2303 if (parse_user_host_port(cp, &user, &host, &port) != 0)
2304 goto out;
2305 } else {
2306 /* Subsequent argument or inactive configuration */
2307 if (parse_user_host_port(cp, NULL, NULL, NULL) != 0)
2308 goto out;
2310 first = 0; /* only check syntax for subsequent hosts */
2311 } while (cp != sdup);
2312 /* success */
2313 if (active) {
2314 o->jump_user = user;
2315 o->jump_host = host;
2316 o->jump_port = port;
2317 o->proxy_command = xstrdup("none");
2318 user = host = NULL;
2319 if ((cp = strrchr(s, ',')) != NULL && cp != s) {
2320 o->jump_extra = xstrdup(s);
2321 o->jump_extra[cp - s] = '\0';
2324 ret = 0;
2325 out:
2326 free(orig);
2327 free(user);
2328 free(host);
2329 return ret;
2332 /* XXX the following is a near-vebatim copy from servconf.c; refactor */
2333 static const char *
2334 fmt_multistate_int(int val, const struct multistate *m)
2336 u_int i;
2338 for (i = 0; m[i].key != NULL; i++) {
2339 if (m[i].value == val)
2340 return m[i].key;
2342 return "UNKNOWN";
2345 static const char *
2346 fmt_intarg(OpCodes code, int val)
2348 if (val == -1)
2349 return "unset";
2350 switch (code) {
2351 case oAddressFamily:
2352 return fmt_multistate_int(val, multistate_addressfamily);
2353 case oVerifyHostKeyDNS:
2354 case oStrictHostKeyChecking:
2355 case oUpdateHostkeys:
2356 return fmt_multistate_int(val, multistate_yesnoask);
2357 case oControlMaster:
2358 return fmt_multistate_int(val, multistate_controlmaster);
2359 case oTunnel:
2360 return fmt_multistate_int(val, multistate_tunnel);
2361 case oRequestTTY:
2362 return fmt_multistate_int(val, multistate_requesttty);
2363 case oCanonicalizeHostname:
2364 return fmt_multistate_int(val, multistate_canonicalizehostname);
2365 case oFingerprintHash:
2366 return ssh_digest_alg_name(val);
2367 case oProtocol:
2368 switch (val) {
2369 case SSH_PROTO_1:
2370 return "1";
2371 case SSH_PROTO_2:
2372 return "2";
2373 case (SSH_PROTO_1|SSH_PROTO_2):
2374 return "2,1";
2375 default:
2376 return "UNKNOWN";
2378 default:
2379 switch (val) {
2380 case 0:
2381 return "no";
2382 case 1:
2383 return "yes";
2384 default:
2385 return "UNKNOWN";
2390 static const char *
2391 lookup_opcode_name(OpCodes code)
2393 u_int i;
2395 for (i = 0; keywords[i].name != NULL; i++)
2396 if (keywords[i].opcode == code)
2397 return(keywords[i].name);
2398 return "UNKNOWN";
2401 static void
2402 dump_cfg_int(OpCodes code, int val)
2404 printf("%s %d\n", lookup_opcode_name(code), val);
2407 static void
2408 dump_cfg_fmtint(OpCodes code, int val)
2410 printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
2413 static void
2414 dump_cfg_string(OpCodes code, const char *val)
2416 if (val == NULL)
2417 return;
2418 printf("%s %s\n", lookup_opcode_name(code), val);
2421 static void
2422 dump_cfg_strarray(OpCodes code, u_int count, char **vals)
2424 u_int i;
2426 for (i = 0; i < count; i++)
2427 printf("%s %s\n", lookup_opcode_name(code), vals[i]);
2430 static void
2431 dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
2433 u_int i;
2435 printf("%s", lookup_opcode_name(code));
2436 for (i = 0; i < count; i++)
2437 printf(" %s", vals[i]);
2438 printf("\n");
2441 static void
2442 dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
2444 const struct Forward *fwd;
2445 u_int i;
2447 /* oDynamicForward */
2448 for (i = 0; i < count; i++) {
2449 fwd = &fwds[i];
2450 if (code == oDynamicForward &&
2451 strcmp(fwd->connect_host, "socks") != 0)
2452 continue;
2453 if (code == oLocalForward &&
2454 strcmp(fwd->connect_host, "socks") == 0)
2455 continue;
2456 printf("%s", lookup_opcode_name(code));
2457 if (fwd->listen_port == PORT_STREAMLOCAL)
2458 printf(" %s", fwd->listen_path);
2459 else if (fwd->listen_host == NULL)
2460 printf(" %d", fwd->listen_port);
2461 else {
2462 printf(" [%s]:%d",
2463 fwd->listen_host, fwd->listen_port);
2465 if (code != oDynamicForward) {
2466 if (fwd->connect_port == PORT_STREAMLOCAL)
2467 printf(" %s", fwd->connect_path);
2468 else if (fwd->connect_host == NULL)
2469 printf(" %d", fwd->connect_port);
2470 else {
2471 printf(" [%s]:%d",
2472 fwd->connect_host, fwd->connect_port);
2475 printf("\n");
2479 void
2480 dump_client_config(Options *o, const char *host)
2482 int i;
2483 char buf[8];
2485 /* This is normally prepared in ssh_kex2 */
2486 if (kex_assemble_names(KEX_DEFAULT_PK_ALG, &o->hostkeyalgorithms) != 0)
2487 fatal("%s: kex_assemble_names failed", __func__);
2489 /* Most interesting options first: user, host, port */
2490 dump_cfg_string(oUser, o->user);
2491 dump_cfg_string(oHostName, host);
2492 dump_cfg_int(oPort, o->port);
2494 /* Flag options */
2495 dump_cfg_fmtint(oAddressFamily, o->address_family);
2496 dump_cfg_fmtint(oBatchMode, o->batch_mode);
2497 dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
2498 dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
2499 dump_cfg_fmtint(oChallengeResponseAuthentication, o->challenge_response_authentication);
2500 dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
2501 dump_cfg_fmtint(oCompression, o->compression);
2502 dump_cfg_fmtint(oControlMaster, o->control_master);
2503 dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
2504 dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
2505 dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
2506 dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
2507 dump_cfg_fmtint(oForwardAgent, o->forward_agent);
2508 dump_cfg_fmtint(oForwardX11, o->forward_x11);
2509 dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
2510 dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
2511 #ifdef GSSAPI
2512 dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
2513 dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
2514 #endif /* GSSAPI */
2515 dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
2516 dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
2517 dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
2518 dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
2519 dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
2520 dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
2521 dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
2522 dump_cfg_fmtint(oProtocol, o->protocol);
2523 dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
2524 dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
2525 dump_cfg_fmtint(oRequestTTY, o->request_tty);
2526 dump_cfg_fmtint(oRhostsRSAAuthentication, o->rhosts_rsa_authentication);
2527 dump_cfg_fmtint(oRSAAuthentication, o->rsa_authentication);
2528 dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
2529 dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
2530 dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
2531 dump_cfg_fmtint(oTunnel, o->tun_open);
2532 dump_cfg_fmtint(oUsePrivilegedPort, o->use_privileged_port);
2533 dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
2534 dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
2535 dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
2537 /* Integer options */
2538 dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
2539 dump_cfg_int(oCompressionLevel, o->compression_level);
2540 dump_cfg_int(oConnectionAttempts, o->connection_attempts);
2541 dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
2542 dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
2543 dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
2544 dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
2546 /* String options */
2547 dump_cfg_string(oBindAddress, o->bind_address);
2548 dump_cfg_string(oCiphers, o->ciphers ? o->ciphers : KEX_CLIENT_ENCRYPT);
2549 dump_cfg_string(oControlPath, o->control_path);
2550 dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
2551 dump_cfg_string(oHostKeyAlias, o->host_key_alias);
2552 dump_cfg_string(oHostbasedKeyTypes, o->hostbased_key_types);
2553 dump_cfg_string(oIdentityAgent, o->identity_agent);
2554 dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
2555 dump_cfg_string(oKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : KEX_CLIENT_KEX);
2556 dump_cfg_string(oLocalCommand, o->local_command);
2557 dump_cfg_string(oLogLevel, log_level_name(o->log_level));
2558 dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC);
2559 dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
2560 dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
2561 dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types);
2562 dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
2563 dump_cfg_string(oXAuthLocation, o->xauth_location);
2565 /* Forwards */
2566 dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
2567 dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
2568 dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
2570 /* String array options */
2571 dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
2572 dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
2573 dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
2574 dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
2575 dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
2577 /* Special cases */
2579 /* oConnectTimeout */
2580 if (o->connection_timeout == -1)
2581 printf("connecttimeout none\n");
2582 else
2583 dump_cfg_int(oConnectTimeout, o->connection_timeout);
2585 /* oTunnelDevice */
2586 printf("tunneldevice");
2587 if (o->tun_local == SSH_TUNID_ANY)
2588 printf(" any");
2589 else
2590 printf(" %d", o->tun_local);
2591 if (o->tun_remote == SSH_TUNID_ANY)
2592 printf(":any");
2593 else
2594 printf(":%d", o->tun_remote);
2595 printf("\n");
2597 /* oCanonicalizePermittedCNAMEs */
2598 if ( o->num_permitted_cnames > 0) {
2599 printf("canonicalizePermittedcnames");
2600 for (i = 0; i < o->num_permitted_cnames; i++) {
2601 printf(" %s:%s", o->permitted_cnames[i].source_list,
2602 o->permitted_cnames[i].target_list);
2604 printf("\n");
2607 /* oCipher */
2608 if (o->cipher != SSH_CIPHER_NOT_SET)
2609 printf("Cipher %s\n", cipher_name(o->cipher));
2611 /* oControlPersist */
2612 if (o->control_persist == 0 || o->control_persist_timeout == 0)
2613 dump_cfg_fmtint(oControlPersist, o->control_persist);
2614 else
2615 dump_cfg_int(oControlPersist, o->control_persist_timeout);
2617 /* oEscapeChar */
2618 if (o->escape_char == SSH_ESCAPECHAR_NONE)
2619 printf("escapechar none\n");
2620 else {
2621 vis(buf, o->escape_char, VIS_WHITE, 0);
2622 printf("escapechar %s\n", buf);
2625 /* oIPQoS */
2626 printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
2627 printf("%s\n", iptos2str(o->ip_qos_bulk));
2629 /* oRekeyLimit */
2630 printf("rekeylimit %llu %d\n",
2631 (unsigned long long)o->rekey_limit, o->rekey_interval);
2633 /* oStreamLocalBindMask */
2634 printf("streamlocalbindmask 0%o\n",
2635 o->fwd_opts.streamlocal_bind_mask);
2637 /* oProxyCommand / oProxyJump */
2638 if (o->jump_host == NULL)
2639 dump_cfg_string(oProxyCommand, o->proxy_command);
2640 else {
2641 /* Check for numeric addresses */
2642 i = strchr(o->jump_host, ':') != NULL ||
2643 strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
2644 snprintf(buf, sizeof(buf), "%d", o->jump_port);
2645 printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
2646 /* optional additional jump spec */
2647 o->jump_extra == NULL ? "" : o->jump_extra,
2648 o->jump_extra == NULL ? "" : ",",
2649 /* optional user */
2650 o->jump_user == NULL ? "" : o->jump_user,
2651 o->jump_user == NULL ? "" : "@",
2652 /* opening [ if hostname is numeric */
2653 i ? "[" : "",
2654 /* mandatory hostname */
2655 o->jump_host,
2656 /* closing ] if hostname is numeric */
2657 i ? "]" : "",
2658 /* optional port number */
2659 o->jump_port <= 0 ? "" : ":",
2660 o->jump_port <= 0 ? "" : buf);