inet6: only mark autoconf addresses tentative if detached
[dragonfly.git] / crypto / openssh / readconf.c
blob42be690b13d531fe44f8ef2453ad48e04f401e80
1 /* $OpenBSD: readconf.c,v 1.369 2022/09/17 10:33:18 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 <stdio.h>
39 #include <string.h>
40 #include <stdarg.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 "ssherr.h"
57 #include "compat.h"
58 #include "cipher.h"
59 #include "pathnames.h"
60 #include "log.h"
61 #include "sshkey.h"
62 #include "misc.h"
63 #include "readconf.h"
64 #include "match.h"
65 #include "kex.h"
66 #include "mac.h"
67 #include "uidswap.h"
68 #include "myproposal.h"
69 #include "digest.h"
71 /* Format of the configuration file:
73 # Configuration data is parsed as follows:
74 # 1. command line options
75 # 2. user-specific file
76 # 3. system-wide file
77 # Any configuration value is only changed the first time it is set.
78 # Thus, host-specific definitions should be at the beginning of the
79 # configuration file, and defaults at the end.
81 # Host-specific declarations. These may override anything above. A single
82 # host may match multiple declarations; these are processed in the order
83 # that they are given in.
85 Host *.ngs.fi ngs.fi
86 User foo
88 Host fake.com
89 Hostname another.host.name.real.org
90 User blaah
91 Port 34289
92 ForwardX11 no
93 ForwardAgent no
95 Host books.com
96 RemoteForward 9999 shadows.cs.hut.fi:9999
97 Ciphers 3des-cbc
99 Host fascist.blob.com
100 Port 23123
101 User tylonen
102 PasswordAuthentication no
104 Host puukko.hut.fi
105 User t35124p
106 ProxyCommand ssh-proxy %h %p
108 Host *.fr
109 PublicKeyAuthentication no
111 Host *.su
112 Ciphers aes128-ctr
113 PasswordAuthentication no
115 Host vpn.fake.com
116 Tunnel yes
117 TunnelDevice 3
119 # Defaults for various options
120 Host *
121 ForwardAgent no
122 ForwardX11 no
123 PasswordAuthentication yes
124 StrictHostKeyChecking yes
125 TcpKeepAlive no
126 IdentityFile ~/.ssh/identity
127 Port 22
128 EscapeChar ~
132 static int read_config_file_depth(const char *filename, struct passwd *pw,
133 const char *host, const char *original_host, Options *options,
134 int flags, int *activep, int *want_final_pass, int depth);
135 static int process_config_line_depth(Options *options, struct passwd *pw,
136 const char *host, const char *original_host, char *line,
137 const char *filename, int linenum, int *activep, int flags,
138 int *want_final_pass, int depth);
140 /* Keyword tokens. */
142 typedef enum {
143 oBadOption,
144 oHost, oMatch, oInclude,
145 oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
146 oGatewayPorts, oExitOnForwardFailure,
147 oPasswordAuthentication,
148 oXAuthLocation,
149 oIdentityFile, oHostname, oPort, oRemoteForward, oLocalForward,
150 oPermitRemoteOpen,
151 oCertificateFile, oAddKeysToAgent, oIdentityAgent,
152 oUser, oEscapeChar, oProxyCommand,
153 oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
154 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
155 oTCPKeepAlive, oNumberOfPasswordPrompts,
156 oLogFacility, oLogLevel, oLogVerbose, oCiphers, oMacs,
157 oPubkeyAuthentication,
158 oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
159 oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
160 oHostKeyAlgorithms, oBindAddress, oBindInterface, oPKCS11Provider,
161 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
162 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
163 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
164 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
165 oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist,
166 oHashKnownHosts,
167 oTunnel, oTunnelDevice,
168 oLocalCommand, oPermitLocalCommand, oRemoteCommand,
169 oVisualHostKey,
170 oKexAlgorithms, oIPQoS, oRequestTTY, oSessionType, oStdinNull,
171 oForkAfterAuthentication, oIgnoreUnknown, oProxyUseFdpass,
172 oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
173 oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
174 oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
175 oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
176 oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
177 oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize,
178 oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
179 } OpCodes;
181 /* Textual representations of the tokens. */
183 static struct {
184 const char *name;
185 OpCodes opcode;
186 } keywords[] = {
187 /* Deprecated options */
188 { "protocol", oIgnore }, /* NB. silently ignored */
189 { "cipher", oDeprecated },
190 { "fallbacktorsh", oDeprecated },
191 { "globalknownhostsfile2", oDeprecated },
192 { "rhostsauthentication", oDeprecated },
193 { "userknownhostsfile2", oDeprecated },
194 { "useroaming", oDeprecated },
195 { "usersh", oDeprecated },
196 { "useprivilegedport", oDeprecated },
198 /* Unsupported options */
199 { "afstokenpassing", oUnsupported },
200 { "kerberosauthentication", oUnsupported },
201 { "kerberostgtpassing", oUnsupported },
202 { "rsaauthentication", oUnsupported },
203 { "rhostsrsaauthentication", oUnsupported },
204 { "compressionlevel", oUnsupported },
206 /* Sometimes-unsupported options */
207 #if defined(GSSAPI)
208 { "gssapiauthentication", oGssAuthentication },
209 { "gssapidelegatecredentials", oGssDelegateCreds },
210 # else
211 { "gssapiauthentication", oUnsupported },
212 { "gssapidelegatecredentials", oUnsupported },
213 #endif
214 #ifdef ENABLE_PKCS11
215 { "pkcs11provider", oPKCS11Provider },
216 { "smartcarddevice", oPKCS11Provider },
217 # else
218 { "smartcarddevice", oUnsupported },
219 { "pkcs11provider", oUnsupported },
220 #endif
222 { "forwardagent", oForwardAgent },
223 { "forwardx11", oForwardX11 },
224 { "forwardx11trusted", oForwardX11Trusted },
225 { "forwardx11timeout", oForwardX11Timeout },
226 { "exitonforwardfailure", oExitOnForwardFailure },
227 { "xauthlocation", oXAuthLocation },
228 { "gatewayports", oGatewayPorts },
229 { "passwordauthentication", oPasswordAuthentication },
230 { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
231 { "kbdinteractivedevices", oKbdInteractiveDevices },
232 { "challengeresponseauthentication", oKbdInteractiveAuthentication }, /* alias */
233 { "skeyauthentication", oKbdInteractiveAuthentication }, /* alias */
234 { "tisauthentication", oKbdInteractiveAuthentication }, /* alias */
235 { "pubkeyauthentication", oPubkeyAuthentication },
236 { "dsaauthentication", oPubkeyAuthentication }, /* alias */
237 { "hostbasedauthentication", oHostbasedAuthentication },
238 { "identityfile", oIdentityFile },
239 { "identityfile2", oIdentityFile }, /* obsolete */
240 { "identitiesonly", oIdentitiesOnly },
241 { "certificatefile", oCertificateFile },
242 { "addkeystoagent", oAddKeysToAgent },
243 { "identityagent", oIdentityAgent },
244 { "hostname", oHostname },
245 { "hostkeyalias", oHostKeyAlias },
246 { "proxycommand", oProxyCommand },
247 { "port", oPort },
248 { "ciphers", oCiphers },
249 { "macs", oMacs },
250 { "remoteforward", oRemoteForward },
251 { "localforward", oLocalForward },
252 { "permitremoteopen", oPermitRemoteOpen },
253 { "user", oUser },
254 { "host", oHost },
255 { "match", oMatch },
256 { "escapechar", oEscapeChar },
257 { "globalknownhostsfile", oGlobalKnownHostsFile },
258 { "userknownhostsfile", oUserKnownHostsFile },
259 { "connectionattempts", oConnectionAttempts },
260 { "batchmode", oBatchMode },
261 { "checkhostip", oCheckHostIP },
262 { "stricthostkeychecking", oStrictHostKeyChecking },
263 { "compression", oCompression },
264 { "tcpkeepalive", oTCPKeepAlive },
265 { "keepalive", oTCPKeepAlive }, /* obsolete */
266 { "numberofpasswordprompts", oNumberOfPasswordPrompts },
267 { "syslogfacility", oLogFacility },
268 { "loglevel", oLogLevel },
269 { "logverbose", oLogVerbose },
270 { "dynamicforward", oDynamicForward },
271 { "preferredauthentications", oPreferredAuthentications },
272 { "hostkeyalgorithms", oHostKeyAlgorithms },
273 { "casignaturealgorithms", oCASignatureAlgorithms },
274 { "bindaddress", oBindAddress },
275 { "bindinterface", oBindInterface },
276 { "clearallforwardings", oClearAllForwardings },
277 { "enablesshkeysign", oEnableSSHKeysign },
278 { "verifyhostkeydns", oVerifyHostKeyDNS },
279 { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
280 { "rekeylimit", oRekeyLimit },
281 { "connecttimeout", oConnectTimeout },
282 { "addressfamily", oAddressFamily },
283 { "serveraliveinterval", oServerAliveInterval },
284 { "serveralivecountmax", oServerAliveCountMax },
285 { "sendenv", oSendEnv },
286 { "setenv", oSetEnv },
287 { "controlpath", oControlPath },
288 { "controlmaster", oControlMaster },
289 { "controlpersist", oControlPersist },
290 { "hashknownhosts", oHashKnownHosts },
291 { "include", oInclude },
292 { "tunnel", oTunnel },
293 { "tunneldevice", oTunnelDevice },
294 { "localcommand", oLocalCommand },
295 { "permitlocalcommand", oPermitLocalCommand },
296 { "remotecommand", oRemoteCommand },
297 { "visualhostkey", oVisualHostKey },
298 { "kexalgorithms", oKexAlgorithms },
299 { "ipqos", oIPQoS },
300 { "requesttty", oRequestTTY },
301 { "sessiontype", oSessionType },
302 { "stdinnull", oStdinNull },
303 { "forkafterauthentication", oForkAfterAuthentication },
304 { "proxyusefdpass", oProxyUseFdpass },
305 { "canonicaldomains", oCanonicalDomains },
306 { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
307 { "canonicalizehostname", oCanonicalizeHostname },
308 { "canonicalizemaxdots", oCanonicalizeMaxDots },
309 { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
310 { "streamlocalbindmask", oStreamLocalBindMask },
311 { "streamlocalbindunlink", oStreamLocalBindUnlink },
312 { "revokedhostkeys", oRevokedHostKeys },
313 { "fingerprinthash", oFingerprintHash },
314 { "updatehostkeys", oUpdateHostkeys },
315 { "hostbasedacceptedalgorithms", oHostbasedAcceptedAlgorithms },
316 { "hostbasedkeytypes", oHostbasedAcceptedAlgorithms }, /* obsolete */
317 { "pubkeyacceptedalgorithms", oPubkeyAcceptedAlgorithms },
318 { "pubkeyacceptedkeytypes", oPubkeyAcceptedAlgorithms }, /* obsolete */
319 { "ignoreunknown", oIgnoreUnknown },
320 { "proxyjump", oProxyJump },
321 { "securitykeyprovider", oSecurityKeyProvider },
322 { "knownhostscommand", oKnownHostsCommand },
323 { "requiredrsasize", oRequiredRSASize },
325 { NULL, oBadOption }
328 static const char *lookup_opcode_name(OpCodes code);
330 const char *
331 kex_default_pk_alg(void)
333 static char *pkalgs;
335 if (pkalgs == NULL) {
336 char *all_key;
338 all_key = sshkey_alg_list(0, 0, 1, ',');
339 pkalgs = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
340 free(all_key);
342 return pkalgs;
345 char *
346 ssh_connection_hash(const char *thishost, const char *host, const char *portstr,
347 const char *user)
349 struct ssh_digest_ctx *md;
350 u_char conn_hash[SSH_DIGEST_MAX_LENGTH];
352 if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL ||
353 ssh_digest_update(md, thishost, strlen(thishost)) < 0 ||
354 ssh_digest_update(md, host, strlen(host)) < 0 ||
355 ssh_digest_update(md, portstr, strlen(portstr)) < 0 ||
356 ssh_digest_update(md, user, strlen(user)) < 0 ||
357 ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0)
358 fatal_f("mux digest failed");
359 ssh_digest_free(md);
360 return tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1));
364 * Adds a local TCP/IP port forward to options. Never returns if there is an
365 * error.
368 void
369 add_local_forward(Options *options, const struct Forward *newfwd)
371 struct Forward *fwd;
372 int i;
374 /* Don't add duplicates */
375 for (i = 0; i < options->num_local_forwards; i++) {
376 if (forward_equals(newfwd, options->local_forwards + i))
377 return;
379 options->local_forwards = xreallocarray(options->local_forwards,
380 options->num_local_forwards + 1,
381 sizeof(*options->local_forwards));
382 fwd = &options->local_forwards[options->num_local_forwards++];
384 fwd->listen_host = newfwd->listen_host;
385 fwd->listen_port = newfwd->listen_port;
386 fwd->listen_path = newfwd->listen_path;
387 fwd->connect_host = newfwd->connect_host;
388 fwd->connect_port = newfwd->connect_port;
389 fwd->connect_path = newfwd->connect_path;
393 * Adds a remote TCP/IP port forward to options. Never returns if there is
394 * an error.
397 void
398 add_remote_forward(Options *options, const struct Forward *newfwd)
400 struct Forward *fwd;
401 int i;
403 /* Don't add duplicates */
404 for (i = 0; i < options->num_remote_forwards; i++) {
405 if (forward_equals(newfwd, options->remote_forwards + i))
406 return;
408 options->remote_forwards = xreallocarray(options->remote_forwards,
409 options->num_remote_forwards + 1,
410 sizeof(*options->remote_forwards));
411 fwd = &options->remote_forwards[options->num_remote_forwards++];
413 fwd->listen_host = newfwd->listen_host;
414 fwd->listen_port = newfwd->listen_port;
415 fwd->listen_path = newfwd->listen_path;
416 fwd->connect_host = newfwd->connect_host;
417 fwd->connect_port = newfwd->connect_port;
418 fwd->connect_path = newfwd->connect_path;
419 fwd->handle = newfwd->handle;
420 fwd->allocated_port = 0;
423 static void
424 clear_forwardings(Options *options)
426 int i;
428 for (i = 0; i < options->num_local_forwards; i++) {
429 free(options->local_forwards[i].listen_host);
430 free(options->local_forwards[i].listen_path);
431 free(options->local_forwards[i].connect_host);
432 free(options->local_forwards[i].connect_path);
434 if (options->num_local_forwards > 0) {
435 free(options->local_forwards);
436 options->local_forwards = NULL;
438 options->num_local_forwards = 0;
439 for (i = 0; i < options->num_remote_forwards; i++) {
440 free(options->remote_forwards[i].listen_host);
441 free(options->remote_forwards[i].listen_path);
442 free(options->remote_forwards[i].connect_host);
443 free(options->remote_forwards[i].connect_path);
445 if (options->num_remote_forwards > 0) {
446 free(options->remote_forwards);
447 options->remote_forwards = NULL;
449 options->num_remote_forwards = 0;
450 options->tun_open = SSH_TUNMODE_NO;
453 void
454 add_certificate_file(Options *options, const char *path, int userprovided)
456 int i;
458 if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
459 fatal("Too many certificate files specified (max %d)",
460 SSH_MAX_CERTIFICATE_FILES);
462 /* Avoid registering duplicates */
463 for (i = 0; i < options->num_certificate_files; i++) {
464 if (options->certificate_file_userprovided[i] == userprovided &&
465 strcmp(options->certificate_files[i], path) == 0) {
466 debug2_f("ignoring duplicate key %s", path);
467 return;
471 options->certificate_file_userprovided[options->num_certificate_files] =
472 userprovided;
473 options->certificate_files[options->num_certificate_files++] =
474 xstrdup(path);
477 void
478 add_identity_file(Options *options, const char *dir, const char *filename,
479 int userprovided)
481 char *path;
482 int i;
484 if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
485 fatal("Too many identity files specified (max %d)",
486 SSH_MAX_IDENTITY_FILES);
488 if (dir == NULL) /* no dir, filename is absolute */
489 path = xstrdup(filename);
490 else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX)
491 fatal("Identity file path %s too long", path);
493 /* Avoid registering duplicates */
494 for (i = 0; i < options->num_identity_files; i++) {
495 if (options->identity_file_userprovided[i] == userprovided &&
496 strcmp(options->identity_files[i], path) == 0) {
497 debug2_f("ignoring duplicate key %s", path);
498 free(path);
499 return;
503 options->identity_file_userprovided[options->num_identity_files] =
504 userprovided;
505 options->identity_files[options->num_identity_files++] = path;
509 default_ssh_port(void)
511 static int port;
512 struct servent *sp;
514 if (port == 0) {
515 sp = getservbyname(SSH_SERVICE_NAME, "tcp");
516 port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
518 return port;
522 * Execute a command in a shell.
523 * Return its exit status or -1 on abnormal exit.
525 static int
526 execute_in_shell(const char *cmd)
528 char *shell;
529 pid_t pid;
530 int status;
532 if ((shell = getenv("SHELL")) == NULL)
533 shell = _PATH_BSHELL;
535 if (access(shell, X_OK) == -1) {
536 fatal("Shell \"%s\" is not executable: %s",
537 shell, strerror(errno));
540 debug("Executing command: '%.500s'", cmd);
542 /* Fork and execute the command. */
543 if ((pid = fork()) == 0) {
544 char *argv[4];
546 if (stdfd_devnull(1, 1, 0) == -1)
547 fatal_f("stdfd_devnull failed");
548 closefrom(STDERR_FILENO + 1);
550 argv[0] = shell;
551 argv[1] = "-c";
552 argv[2] = xstrdup(cmd);
553 argv[3] = NULL;
555 execv(argv[0], argv);
556 error("Unable to execute '%.100s': %s", cmd, strerror(errno));
557 /* Die with signal to make this error apparent to parent. */
558 ssh_signal(SIGTERM, SIG_DFL);
559 kill(getpid(), SIGTERM);
560 _exit(1);
562 /* Parent. */
563 if (pid == -1)
564 fatal_f("fork: %.100s", strerror(errno));
566 while (waitpid(pid, &status, 0) == -1) {
567 if (errno != EINTR && errno != EAGAIN)
568 fatal_f("waitpid: %s", strerror(errno));
570 if (!WIFEXITED(status)) {
571 error("command '%.100s' exited abnormally", cmd);
572 return -1;
574 debug3("command returned status %d", WEXITSTATUS(status));
575 return WEXITSTATUS(status);
579 * Parse and execute a Match directive.
581 static int
582 match_cfg_line(Options *options, char **condition, struct passwd *pw,
583 const char *host_arg, const char *original_host, int final_pass,
584 int *want_final_pass, const char *filename, int linenum)
586 char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
587 const char *ruser;
588 int r, port, this_result, result = 1, attributes = 0, negate;
589 char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
590 char uidstr[32];
593 * Configuration is likely to be incomplete at this point so we
594 * must be prepared to use default values.
596 port = options->port <= 0 ? default_ssh_port() : options->port;
597 ruser = options->user == NULL ? pw->pw_name : options->user;
598 if (final_pass) {
599 host = xstrdup(options->hostname);
600 } else if (options->hostname != NULL) {
601 /* NB. Please keep in sync with ssh.c:main() */
602 host = percent_expand(options->hostname,
603 "h", host_arg, (char *)NULL);
604 } else {
605 host = xstrdup(host_arg);
608 debug2("checking match for '%s' host %s originally %s",
609 cp, host, original_host);
610 while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
611 /* Terminate on comment */
612 if (*attrib == '#') {
613 cp = NULL; /* mark all arguments consumed */
614 break;
616 arg = criteria = NULL;
617 this_result = 1;
618 if ((negate = attrib[0] == '!'))
619 attrib++;
620 /* Criterion "all" has no argument and must appear alone */
621 if (strcasecmp(attrib, "all") == 0) {
622 if (attributes > 1 || ((arg = strdelim(&cp)) != NULL &&
623 *arg != '\0' && *arg != '#')) {
624 error("%.200s line %d: '%s' cannot be combined "
625 "with other Match attributes",
626 filename, linenum, oattrib);
627 result = -1;
628 goto out;
630 if (arg != NULL && *arg == '#')
631 cp = NULL; /* mark all arguments consumed */
632 if (result)
633 result = negate ? 0 : 1;
634 goto out;
636 attributes++;
637 /* criteria "final" and "canonical" have no argument */
638 if (strcasecmp(attrib, "canonical") == 0 ||
639 strcasecmp(attrib, "final") == 0) {
641 * If the config requests "Match final" then remember
642 * this so we can perform a second pass later.
644 if (strcasecmp(attrib, "final") == 0 &&
645 want_final_pass != NULL)
646 *want_final_pass = 1;
647 r = !!final_pass; /* force bitmask member to boolean */
648 if (r == (negate ? 1 : 0))
649 this_result = result = 0;
650 debug3("%.200s line %d: %smatched '%s'",
651 filename, linenum,
652 this_result ? "" : "not ", oattrib);
653 continue;
655 /* All other criteria require an argument */
656 if ((arg = strdelim(&cp)) == NULL ||
657 *arg == '\0' || *arg == '#') {
658 error("Missing Match criteria for %s", attrib);
659 result = -1;
660 goto out;
662 if (strcasecmp(attrib, "host") == 0) {
663 criteria = xstrdup(host);
664 r = match_hostname(host, arg) == 1;
665 if (r == (negate ? 1 : 0))
666 this_result = result = 0;
667 } else if (strcasecmp(attrib, "originalhost") == 0) {
668 criteria = xstrdup(original_host);
669 r = match_hostname(original_host, arg) == 1;
670 if (r == (negate ? 1 : 0))
671 this_result = result = 0;
672 } else if (strcasecmp(attrib, "user") == 0) {
673 criteria = xstrdup(ruser);
674 r = match_pattern_list(ruser, arg, 0) == 1;
675 if (r == (negate ? 1 : 0))
676 this_result = result = 0;
677 } else if (strcasecmp(attrib, "localuser") == 0) {
678 criteria = xstrdup(pw->pw_name);
679 r = match_pattern_list(pw->pw_name, arg, 0) == 1;
680 if (r == (negate ? 1 : 0))
681 this_result = result = 0;
682 } else if (strcasecmp(attrib, "exec") == 0) {
683 char *conn_hash_hex, *keyalias;
685 if (gethostname(thishost, sizeof(thishost)) == -1)
686 fatal("gethostname: %s", strerror(errno));
687 strlcpy(shorthost, thishost, sizeof(shorthost));
688 shorthost[strcspn(thishost, ".")] = '\0';
689 snprintf(portstr, sizeof(portstr), "%d", port);
690 snprintf(uidstr, sizeof(uidstr), "%llu",
691 (unsigned long long)pw->pw_uid);
692 conn_hash_hex = ssh_connection_hash(thishost, host,
693 portstr, ruser);
694 keyalias = options->host_key_alias ?
695 options->host_key_alias : host;
697 cmd = percent_expand(arg,
698 "C", conn_hash_hex,
699 "L", shorthost,
700 "d", pw->pw_dir,
701 "h", host,
702 "k", keyalias,
703 "l", thishost,
704 "n", original_host,
705 "p", portstr,
706 "r", ruser,
707 "u", pw->pw_name,
708 "i", uidstr,
709 (char *)NULL);
710 free(conn_hash_hex);
711 if (result != 1) {
712 /* skip execution if prior predicate failed */
713 debug3("%.200s line %d: skipped exec "
714 "\"%.100s\"", filename, linenum, cmd);
715 free(cmd);
716 continue;
718 r = execute_in_shell(cmd);
719 if (r == -1) {
720 fatal("%.200s line %d: match exec "
721 "'%.100s' error", filename,
722 linenum, cmd);
724 criteria = xstrdup(cmd);
725 free(cmd);
726 /* Force exit status to boolean */
727 r = r == 0;
728 if (r == (negate ? 1 : 0))
729 this_result = result = 0;
730 } else {
731 error("Unsupported Match attribute %s", attrib);
732 result = -1;
733 goto out;
735 debug3("%.200s line %d: %smatched '%s \"%.100s\"' ",
736 filename, linenum, this_result ? "": "not ",
737 oattrib, criteria);
738 free(criteria);
740 if (attributes == 0) {
741 error("One or more attributes required for Match");
742 result = -1;
743 goto out;
745 out:
746 if (result != -1)
747 debug2("match %sfound", result ? "" : "not ");
748 *condition = cp;
749 free(host);
750 return result;
753 /* Remove environment variable by pattern */
754 static void
755 rm_env(Options *options, const char *arg, const char *filename, int linenum)
757 u_int i, j, onum_send_env = options->num_send_env;
759 /* Remove an environment variable */
760 for (i = 0; i < options->num_send_env; ) {
761 if (!match_pattern(options->send_env[i], arg + 1)) {
762 i++;
763 continue;
765 debug3("%s line %d: removing environment %s",
766 filename, linenum, options->send_env[i]);
767 free(options->send_env[i]);
768 options->send_env[i] = NULL;
769 for (j = i; j < options->num_send_env - 1; j++) {
770 options->send_env[j] = options->send_env[j + 1];
771 options->send_env[j + 1] = NULL;
773 options->num_send_env--;
774 /* NB. don't increment i */
776 if (onum_send_env != options->num_send_env) {
777 options->send_env = xrecallocarray(options->send_env,
778 onum_send_env, options->num_send_env,
779 sizeof(*options->send_env));
784 * Returns the number of the token pointed to by cp or oBadOption.
786 static OpCodes
787 parse_token(const char *cp, const char *filename, int linenum,
788 const char *ignored_unknown)
790 int i;
792 for (i = 0; keywords[i].name; i++)
793 if (strcmp(cp, keywords[i].name) == 0)
794 return keywords[i].opcode;
795 if (ignored_unknown != NULL &&
796 match_pattern_list(cp, ignored_unknown, 1) == 1)
797 return oIgnoredUnknownOption;
798 error("%s: line %d: Bad configuration option: %s",
799 filename, linenum, cp);
800 return oBadOption;
803 /* Multistate option parsing */
804 struct multistate {
805 char *key;
806 int value;
808 static const struct multistate multistate_flag[] = {
809 { "true", 1 },
810 { "false", 0 },
811 { "yes", 1 },
812 { "no", 0 },
813 { NULL, -1 }
815 static const struct multistate multistate_yesnoask[] = {
816 { "true", 1 },
817 { "false", 0 },
818 { "yes", 1 },
819 { "no", 0 },
820 { "ask", 2 },
821 { NULL, -1 }
823 static const struct multistate multistate_strict_hostkey[] = {
824 { "true", SSH_STRICT_HOSTKEY_YES },
825 { "false", SSH_STRICT_HOSTKEY_OFF },
826 { "yes", SSH_STRICT_HOSTKEY_YES },
827 { "no", SSH_STRICT_HOSTKEY_OFF },
828 { "ask", SSH_STRICT_HOSTKEY_ASK },
829 { "off", SSH_STRICT_HOSTKEY_OFF },
830 { "accept-new", SSH_STRICT_HOSTKEY_NEW },
831 { NULL, -1 }
833 static const struct multistate multistate_yesnoaskconfirm[] = {
834 { "true", 1 },
835 { "false", 0 },
836 { "yes", 1 },
837 { "no", 0 },
838 { "ask", 2 },
839 { "confirm", 3 },
840 { NULL, -1 }
842 static const struct multistate multistate_addressfamily[] = {
843 { "inet", AF_INET },
844 { "inet6", AF_INET6 },
845 { "any", AF_UNSPEC },
846 { NULL, -1 }
848 static const struct multistate multistate_controlmaster[] = {
849 { "true", SSHCTL_MASTER_YES },
850 { "yes", SSHCTL_MASTER_YES },
851 { "false", SSHCTL_MASTER_NO },
852 { "no", SSHCTL_MASTER_NO },
853 { "auto", SSHCTL_MASTER_AUTO },
854 { "ask", SSHCTL_MASTER_ASK },
855 { "autoask", SSHCTL_MASTER_AUTO_ASK },
856 { NULL, -1 }
858 static const struct multistate multistate_tunnel[] = {
859 { "ethernet", SSH_TUNMODE_ETHERNET },
860 { "point-to-point", SSH_TUNMODE_POINTOPOINT },
861 { "true", SSH_TUNMODE_DEFAULT },
862 { "yes", SSH_TUNMODE_DEFAULT },
863 { "false", SSH_TUNMODE_NO },
864 { "no", SSH_TUNMODE_NO },
865 { NULL, -1 }
867 static const struct multistate multistate_requesttty[] = {
868 { "true", REQUEST_TTY_YES },
869 { "yes", REQUEST_TTY_YES },
870 { "false", REQUEST_TTY_NO },
871 { "no", REQUEST_TTY_NO },
872 { "force", REQUEST_TTY_FORCE },
873 { "auto", REQUEST_TTY_AUTO },
874 { NULL, -1 }
876 static const struct multistate multistate_sessiontype[] = {
877 { "none", SESSION_TYPE_NONE },
878 { "subsystem", SESSION_TYPE_SUBSYSTEM },
879 { "default", SESSION_TYPE_DEFAULT },
880 { NULL, -1 }
882 static const struct multistate multistate_canonicalizehostname[] = {
883 { "true", SSH_CANONICALISE_YES },
884 { "false", SSH_CANONICALISE_NO },
885 { "yes", SSH_CANONICALISE_YES },
886 { "no", SSH_CANONICALISE_NO },
887 { "always", SSH_CANONICALISE_ALWAYS },
888 { NULL, -1 }
890 static const struct multistate multistate_pubkey_auth[] = {
891 { "true", SSH_PUBKEY_AUTH_ALL },
892 { "false", SSH_PUBKEY_AUTH_NO },
893 { "yes", SSH_PUBKEY_AUTH_ALL },
894 { "no", SSH_PUBKEY_AUTH_NO },
895 { "unbound", SSH_PUBKEY_AUTH_UNBOUND },
896 { "host-bound", SSH_PUBKEY_AUTH_HBOUND },
897 { NULL, -1 }
899 static const struct multistate multistate_compression[] = {
900 #ifdef WITH_ZLIB
901 { "yes", COMP_ZLIB },
902 #endif
903 { "no", COMP_NONE },
904 { NULL, -1 }
907 static int
908 parse_multistate_value(const char *arg, const char *filename, int linenum,
909 const struct multistate *multistate_ptr)
911 int i;
913 if (!arg || *arg == '\0') {
914 error("%s line %d: missing argument.", filename, linenum);
915 return -1;
917 for (i = 0; multistate_ptr[i].key != NULL; i++) {
918 if (strcasecmp(arg, multistate_ptr[i].key) == 0)
919 return multistate_ptr[i].value;
921 return -1;
925 * Processes a single option line as used in the configuration files. This
926 * only sets those values that have not already been set.
929 process_config_line(Options *options, struct passwd *pw, const char *host,
930 const char *original_host, char *line, const char *filename,
931 int linenum, int *activep, int flags)
933 return process_config_line_depth(options, pw, host, original_host,
934 line, filename, linenum, activep, flags, NULL, 0);
937 #define WHITESPACE " \t\r\n"
938 static int
939 process_config_line_depth(Options *options, struct passwd *pw, const char *host,
940 const char *original_host, char *line, const char *filename,
941 int linenum, int *activep, int flags, int *want_final_pass, int depth)
943 char *str, **charptr, *endofnumber, *keyword, *arg, *arg2, *p;
944 char **cpptr, ***cppptr, fwdarg[256];
945 u_int i, *uintptr, uvalue, max_entries = 0;
946 int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
947 int remotefwd, dynamicfwd;
948 LogLevel *log_level_ptr;
949 SyslogFacility *log_facility_ptr;
950 long long val64;
951 size_t len;
952 struct Forward fwd;
953 const struct multistate *multistate_ptr;
954 struct allowed_cname *cname;
955 glob_t gl;
956 const char *errstr;
957 char **oav = NULL, **av;
958 int oac = 0, ac;
959 int ret = -1;
961 if (activep == NULL) { /* We are processing a command line directive */
962 cmdline = 1;
963 activep = &cmdline;
966 /* Strip trailing whitespace. Allow \f (form feed) at EOL only */
967 if ((len = strlen(line)) == 0)
968 return 0;
969 for (len--; len > 0; len--) {
970 if (strchr(WHITESPACE "\f", line[len]) == NULL)
971 break;
972 line[len] = '\0';
975 str = line;
976 /* Get the keyword. (Each line is supposed to begin with a keyword). */
977 if ((keyword = strdelim(&str)) == NULL)
978 return 0;
979 /* Ignore leading whitespace. */
980 if (*keyword == '\0')
981 keyword = strdelim(&str);
982 if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
983 return 0;
984 /* Match lowercase keyword */
985 lowercase(keyword);
987 /* Prepare to parse remainder of line */
988 if (str != NULL)
989 str += strspn(str, WHITESPACE);
990 if (str == NULL || *str == '\0') {
991 error("%s line %d: no argument after keyword \"%s\"",
992 filename, linenum, keyword);
993 return -1;
995 opcode = parse_token(keyword, filename, linenum,
996 options->ignored_unknown);
997 if (argv_split(str, &oac, &oav, 1) != 0) {
998 error("%s line %d: invalid quotes", filename, linenum);
999 return -1;
1001 ac = oac;
1002 av = oav;
1004 switch (opcode) {
1005 case oBadOption:
1006 /* don't panic, but count bad options */
1007 goto out;
1008 case oIgnore:
1009 argv_consume(&ac);
1010 break;
1011 case oIgnoredUnknownOption:
1012 debug("%s line %d: Ignored unknown option \"%s\"",
1013 filename, linenum, keyword);
1014 argv_consume(&ac);
1015 break;
1016 case oConnectTimeout:
1017 intptr = &options->connection_timeout;
1018 parse_time:
1019 arg = argv_next(&ac, &av);
1020 if (!arg || *arg == '\0') {
1021 error("%s line %d: missing time value.",
1022 filename, linenum);
1023 goto out;
1025 if (strcmp(arg, "none") == 0)
1026 value = -1;
1027 else if ((value = convtime(arg)) == -1) {
1028 error("%s line %d: invalid time value.",
1029 filename, linenum);
1030 goto out;
1032 if (*activep && *intptr == -1)
1033 *intptr = value;
1034 break;
1036 case oForwardAgent:
1037 intptr = &options->forward_agent;
1039 arg = argv_next(&ac, &av);
1040 if (!arg || *arg == '\0') {
1041 error("%s line %d: missing argument.",
1042 filename, linenum);
1043 goto out;
1046 value = -1;
1047 multistate_ptr = multistate_flag;
1048 for (i = 0; multistate_ptr[i].key != NULL; i++) {
1049 if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
1050 value = multistate_ptr[i].value;
1051 break;
1054 if (value != -1) {
1055 if (*activep && *intptr == -1)
1056 *intptr = value;
1057 break;
1059 /* ForwardAgent wasn't 'yes' or 'no', assume a path */
1060 if (*activep && *intptr == -1)
1061 *intptr = 1;
1063 charptr = &options->forward_agent_sock_path;
1064 goto parse_agent_path;
1066 case oForwardX11:
1067 intptr = &options->forward_x11;
1068 parse_flag:
1069 multistate_ptr = multistate_flag;
1070 parse_multistate:
1071 arg = argv_next(&ac, &av);
1072 if ((value = parse_multistate_value(arg, filename, linenum,
1073 multistate_ptr)) == -1) {
1074 error("%s line %d: unsupported option \"%s\".",
1075 filename, linenum, arg);
1076 goto out;
1078 if (*activep && *intptr == -1)
1079 *intptr = value;
1080 break;
1082 case oForwardX11Trusted:
1083 intptr = &options->forward_x11_trusted;
1084 goto parse_flag;
1086 case oForwardX11Timeout:
1087 intptr = &options->forward_x11_timeout;
1088 goto parse_time;
1090 case oGatewayPorts:
1091 intptr = &options->fwd_opts.gateway_ports;
1092 goto parse_flag;
1094 case oExitOnForwardFailure:
1095 intptr = &options->exit_on_forward_failure;
1096 goto parse_flag;
1098 case oPasswordAuthentication:
1099 intptr = &options->password_authentication;
1100 goto parse_flag;
1102 case oKbdInteractiveAuthentication:
1103 intptr = &options->kbd_interactive_authentication;
1104 goto parse_flag;
1106 case oKbdInteractiveDevices:
1107 charptr = &options->kbd_interactive_devices;
1108 goto parse_string;
1110 case oPubkeyAuthentication:
1111 multistate_ptr = multistate_pubkey_auth;
1112 intptr = &options->pubkey_authentication;
1113 goto parse_multistate;
1115 case oHostbasedAuthentication:
1116 intptr = &options->hostbased_authentication;
1117 goto parse_flag;
1119 case oGssAuthentication:
1120 intptr = &options->gss_authentication;
1121 goto parse_flag;
1123 case oGssDelegateCreds:
1124 intptr = &options->gss_deleg_creds;
1125 goto parse_flag;
1127 case oBatchMode:
1128 intptr = &options->batch_mode;
1129 goto parse_flag;
1131 case oCheckHostIP:
1132 intptr = &options->check_host_ip;
1133 goto parse_flag;
1135 case oVerifyHostKeyDNS:
1136 intptr = &options->verify_host_key_dns;
1137 multistate_ptr = multistate_yesnoask;
1138 goto parse_multistate;
1140 case oStrictHostKeyChecking:
1141 intptr = &options->strict_host_key_checking;
1142 multistate_ptr = multistate_strict_hostkey;
1143 goto parse_multistate;
1145 case oCompression:
1146 intptr = &options->compression;
1147 multistate_ptr = multistate_compression;
1148 goto parse_multistate;
1150 case oTCPKeepAlive:
1151 intptr = &options->tcp_keep_alive;
1152 goto parse_flag;
1154 case oNoHostAuthenticationForLocalhost:
1155 intptr = &options->no_host_authentication_for_localhost;
1156 goto parse_flag;
1158 case oNumberOfPasswordPrompts:
1159 intptr = &options->number_of_password_prompts;
1160 goto parse_int;
1162 case oRekeyLimit:
1163 arg = argv_next(&ac, &av);
1164 if (!arg || *arg == '\0') {
1165 error("%.200s line %d: Missing argument.", filename,
1166 linenum);
1167 goto out;
1169 if (strcmp(arg, "default") == 0) {
1170 val64 = 0;
1171 } else {
1172 if (scan_scaled(arg, &val64) == -1) {
1173 error("%.200s line %d: Bad number '%s': %s",
1174 filename, linenum, arg, strerror(errno));
1175 goto out;
1177 if (val64 != 0 && val64 < 16) {
1178 error("%.200s line %d: RekeyLimit too small",
1179 filename, linenum);
1180 goto out;
1183 if (*activep && options->rekey_limit == -1)
1184 options->rekey_limit = val64;
1185 if (ac != 0) { /* optional rekey interval present */
1186 if (strcmp(av[0], "none") == 0) {
1187 (void)argv_next(&ac, &av); /* discard */
1188 break;
1190 intptr = &options->rekey_interval;
1191 goto parse_time;
1193 break;
1195 case oIdentityFile:
1196 arg = argv_next(&ac, &av);
1197 if (!arg || *arg == '\0') {
1198 error("%.200s line %d: Missing argument.",
1199 filename, linenum);
1200 goto out;
1202 if (*activep) {
1203 intptr = &options->num_identity_files;
1204 if (*intptr >= SSH_MAX_IDENTITY_FILES) {
1205 error("%.200s line %d: Too many identity files "
1206 "specified (max %d).", filename, linenum,
1207 SSH_MAX_IDENTITY_FILES);
1208 goto out;
1210 add_identity_file(options, NULL,
1211 arg, flags & SSHCONF_USERCONF);
1213 break;
1215 case oCertificateFile:
1216 arg = argv_next(&ac, &av);
1217 if (!arg || *arg == '\0') {
1218 error("%.200s line %d: Missing argument.",
1219 filename, linenum);
1220 goto out;
1222 if (*activep) {
1223 intptr = &options->num_certificate_files;
1224 if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
1225 error("%.200s line %d: Too many certificate "
1226 "files specified (max %d).",
1227 filename, linenum,
1228 SSH_MAX_CERTIFICATE_FILES);
1229 goto out;
1231 add_certificate_file(options, arg,
1232 flags & SSHCONF_USERCONF);
1234 break;
1236 case oXAuthLocation:
1237 charptr=&options->xauth_location;
1238 goto parse_string;
1240 case oUser:
1241 charptr = &options->user;
1242 parse_string:
1243 arg = argv_next(&ac, &av);
1244 if (!arg || *arg == '\0') {
1245 error("%.200s line %d: Missing argument.",
1246 filename, linenum);
1247 goto out;
1249 if (*activep && *charptr == NULL)
1250 *charptr = xstrdup(arg);
1251 break;
1253 case oGlobalKnownHostsFile:
1254 cpptr = (char **)&options->system_hostfiles;
1255 uintptr = &options->num_system_hostfiles;
1256 max_entries = SSH_MAX_HOSTS_FILES;
1257 parse_char_array:
1258 i = 0;
1259 value = *uintptr == 0; /* was array empty when we started? */
1260 while ((arg = argv_next(&ac, &av)) != NULL) {
1261 if (*arg == '\0') {
1262 error("%s line %d: keyword %s empty argument",
1263 filename, linenum, keyword);
1264 goto out;
1266 /* Allow "none" only in first position */
1267 if (strcasecmp(arg, "none") == 0) {
1268 if (i > 0 || ac > 0) {
1269 error("%s line %d: keyword %s \"none\" "
1270 "argument must appear alone.",
1271 filename, linenum, keyword);
1272 goto out;
1275 i++;
1276 if (*activep && value) {
1277 if ((*uintptr) >= max_entries) {
1278 error("%s line %d: too many %s "
1279 "entries.", filename, linenum,
1280 keyword);
1281 goto out;
1283 cpptr[(*uintptr)++] = xstrdup(arg);
1286 break;
1288 case oUserKnownHostsFile:
1289 cpptr = (char **)&options->user_hostfiles;
1290 uintptr = &options->num_user_hostfiles;
1291 max_entries = SSH_MAX_HOSTS_FILES;
1292 goto parse_char_array;
1294 case oHostname:
1295 charptr = &options->hostname;
1296 goto parse_string;
1298 case oHostKeyAlias:
1299 charptr = &options->host_key_alias;
1300 goto parse_string;
1302 case oPreferredAuthentications:
1303 charptr = &options->preferred_authentications;
1304 goto parse_string;
1306 case oBindAddress:
1307 charptr = &options->bind_address;
1308 goto parse_string;
1310 case oBindInterface:
1311 charptr = &options->bind_interface;
1312 goto parse_string;
1314 case oPKCS11Provider:
1315 charptr = &options->pkcs11_provider;
1316 goto parse_string;
1318 case oSecurityKeyProvider:
1319 charptr = &options->sk_provider;
1320 goto parse_string;
1322 case oKnownHostsCommand:
1323 charptr = &options->known_hosts_command;
1324 goto parse_command;
1326 case oProxyCommand:
1327 charptr = &options->proxy_command;
1328 /* Ignore ProxyCommand if ProxyJump already specified */
1329 if (options->jump_host != NULL)
1330 charptr = &options->jump_host; /* Skip below */
1331 parse_command:
1332 if (str == NULL) {
1333 error("%.200s line %d: Missing argument.",
1334 filename, linenum);
1335 goto out;
1337 len = strspn(str, WHITESPACE "=");
1338 if (*activep && *charptr == NULL)
1339 *charptr = xstrdup(str + len);
1340 argv_consume(&ac);
1341 break;
1343 case oProxyJump:
1344 if (str == NULL) {
1345 error("%.200s line %d: Missing argument.",
1346 filename, linenum);
1347 goto out;
1349 len = strspn(str, WHITESPACE "=");
1350 /* XXX use argv? */
1351 if (parse_jump(str + len, options, *activep) == -1) {
1352 error("%.200s line %d: Invalid ProxyJump \"%s\"",
1353 filename, linenum, str + len);
1354 goto out;
1356 argv_consume(&ac);
1357 break;
1359 case oPort:
1360 arg = argv_next(&ac, &av);
1361 if (!arg || *arg == '\0') {
1362 error("%.200s line %d: Missing argument.",
1363 filename, linenum);
1364 goto out;
1366 value = a2port(arg);
1367 if (value <= 0) {
1368 error("%.200s line %d: Bad port '%s'.",
1369 filename, linenum, arg);
1370 goto out;
1372 if (*activep && options->port == -1)
1373 options->port = value;
1374 break;
1376 case oConnectionAttempts:
1377 intptr = &options->connection_attempts;
1378 parse_int:
1379 arg = argv_next(&ac, &av);
1380 if ((errstr = atoi_err(arg, &value)) != NULL) {
1381 error("%s line %d: integer value %s.",
1382 filename, linenum, errstr);
1383 goto out;
1385 if (*activep && *intptr == -1)
1386 *intptr = value;
1387 break;
1389 case oCiphers:
1390 arg = argv_next(&ac, &av);
1391 if (!arg || *arg == '\0') {
1392 error("%.200s line %d: Missing argument.",
1393 filename, linenum);
1394 goto out;
1396 if (*arg != '-' &&
1397 !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)){
1398 error("%.200s line %d: Bad SSH2 cipher spec '%s'.",
1399 filename, linenum, arg ? arg : "<NONE>");
1400 goto out;
1402 if (*activep && options->ciphers == NULL)
1403 options->ciphers = xstrdup(arg);
1404 break;
1406 case oMacs:
1407 arg = argv_next(&ac, &av);
1408 if (!arg || *arg == '\0') {
1409 error("%.200s line %d: Missing argument.",
1410 filename, linenum);
1411 goto out;
1413 if (*arg != '-' &&
1414 !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)) {
1415 error("%.200s line %d: Bad SSH2 MAC spec '%s'.",
1416 filename, linenum, arg ? arg : "<NONE>");
1417 goto out;
1419 if (*activep && options->macs == NULL)
1420 options->macs = xstrdup(arg);
1421 break;
1423 case oKexAlgorithms:
1424 arg = argv_next(&ac, &av);
1425 if (!arg || *arg == '\0') {
1426 error("%.200s line %d: Missing argument.",
1427 filename, linenum);
1428 goto out;
1430 if (*arg != '-' &&
1431 !kex_names_valid(*arg == '+' || *arg == '^' ?
1432 arg + 1 : arg)) {
1433 error("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
1434 filename, linenum, arg ? arg : "<NONE>");
1435 goto out;
1437 if (*activep && options->kex_algorithms == NULL)
1438 options->kex_algorithms = xstrdup(arg);
1439 break;
1441 case oHostKeyAlgorithms:
1442 charptr = &options->hostkeyalgorithms;
1443 parse_pubkey_algos:
1444 arg = argv_next(&ac, &av);
1445 if (!arg || *arg == '\0') {
1446 error("%.200s line %d: Missing argument.",
1447 filename, linenum);
1448 goto out;
1450 if (*arg != '-' &&
1451 !sshkey_names_valid2(*arg == '+' || *arg == '^' ?
1452 arg + 1 : arg, 1)) {
1453 error("%s line %d: Bad key types '%s'.",
1454 filename, linenum, arg ? arg : "<NONE>");
1455 goto out;
1457 if (*activep && *charptr == NULL)
1458 *charptr = xstrdup(arg);
1459 break;
1461 case oCASignatureAlgorithms:
1462 charptr = &options->ca_sign_algorithms;
1463 goto parse_pubkey_algos;
1465 case oLogLevel:
1466 log_level_ptr = &options->log_level;
1467 arg = argv_next(&ac, &av);
1468 value = log_level_number(arg);
1469 if (value == SYSLOG_LEVEL_NOT_SET) {
1470 error("%.200s line %d: unsupported log level '%s'",
1471 filename, linenum, arg ? arg : "<NONE>");
1472 goto out;
1474 if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1475 *log_level_ptr = (LogLevel) value;
1476 break;
1478 case oLogFacility:
1479 log_facility_ptr = &options->log_facility;
1480 arg = argv_next(&ac, &av);
1481 value = log_facility_number(arg);
1482 if (value == SYSLOG_FACILITY_NOT_SET) {
1483 error("%.200s line %d: unsupported log facility '%s'",
1484 filename, linenum, arg ? arg : "<NONE>");
1485 goto out;
1487 if (*log_facility_ptr == -1)
1488 *log_facility_ptr = (SyslogFacility) value;
1489 break;
1491 case oLogVerbose:
1492 cppptr = &options->log_verbose;
1493 uintptr = &options->num_log_verbose;
1494 i = 0;
1495 while ((arg = argv_next(&ac, &av)) != NULL) {
1496 if (*arg == '\0') {
1497 error("%s line %d: keyword %s empty argument",
1498 filename, linenum, keyword);
1499 goto out;
1501 /* Allow "none" only in first position */
1502 if (strcasecmp(arg, "none") == 0) {
1503 if (i > 0 || ac > 0) {
1504 error("%s line %d: keyword %s \"none\" "
1505 "argument must appear alone.",
1506 filename, linenum, keyword);
1507 goto out;
1510 i++;
1511 if (*activep && *uintptr == 0) {
1512 *cppptr = xrecallocarray(*cppptr, *uintptr,
1513 *uintptr + 1, sizeof(**cppptr));
1514 (*cppptr)[(*uintptr)++] = xstrdup(arg);
1517 break;
1519 case oLocalForward:
1520 case oRemoteForward:
1521 case oDynamicForward:
1522 arg = argv_next(&ac, &av);
1523 if (!arg || *arg == '\0') {
1524 error("%.200s line %d: Missing argument.",
1525 filename, linenum);
1526 goto out;
1529 remotefwd = (opcode == oRemoteForward);
1530 dynamicfwd = (opcode == oDynamicForward);
1532 if (!dynamicfwd) {
1533 arg2 = argv_next(&ac, &av);
1534 if (arg2 == NULL || *arg2 == '\0') {
1535 if (remotefwd)
1536 dynamicfwd = 1;
1537 else {
1538 error("%.200s line %d: Missing target "
1539 "argument.", filename, linenum);
1540 goto out;
1542 } else {
1543 /* construct a string for parse_forward */
1544 snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg,
1545 arg2);
1548 if (dynamicfwd)
1549 strlcpy(fwdarg, arg, sizeof(fwdarg));
1551 if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0) {
1552 error("%.200s line %d: Bad forwarding specification.",
1553 filename, linenum);
1554 goto out;
1557 if (*activep) {
1558 if (remotefwd) {
1559 add_remote_forward(options, &fwd);
1560 } else {
1561 add_local_forward(options, &fwd);
1564 break;
1566 case oPermitRemoteOpen:
1567 uintptr = &options->num_permitted_remote_opens;
1568 cppptr = &options->permitted_remote_opens;
1569 arg = argv_next(&ac, &av);
1570 if (!arg || *arg == '\0')
1571 fatal("%s line %d: missing %s specification",
1572 filename, linenum, lookup_opcode_name(opcode));
1573 uvalue = *uintptr; /* modified later */
1574 if (strcmp(arg, "any") == 0 || strcmp(arg, "none") == 0) {
1575 if (*activep && uvalue == 0) {
1576 *uintptr = 1;
1577 *cppptr = xcalloc(1, sizeof(**cppptr));
1578 (*cppptr)[0] = xstrdup(arg);
1580 break;
1582 while ((arg = argv_next(&ac, &av)) != NULL) {
1583 arg2 = xstrdup(arg);
1584 p = hpdelim(&arg);
1585 if (p == NULL) {
1586 fatal("%s line %d: missing host in %s",
1587 filename, linenum,
1588 lookup_opcode_name(opcode));
1590 p = cleanhostname(p);
1592 * don't want to use permitopen_port to avoid
1593 * dependency on channels.[ch] here.
1595 if (arg == NULL ||
1596 (strcmp(arg, "*") != 0 && a2port(arg) <= 0)) {
1597 fatal("%s line %d: bad port number in %s",
1598 filename, linenum,
1599 lookup_opcode_name(opcode));
1601 if (*activep && uvalue == 0) {
1602 opt_array_append(filename, linenum,
1603 lookup_opcode_name(opcode),
1604 cppptr, uintptr, arg2);
1606 free(arg2);
1608 break;
1610 case oClearAllForwardings:
1611 intptr = &options->clear_forwardings;
1612 goto parse_flag;
1614 case oHost:
1615 if (cmdline) {
1616 error("Host directive not supported as a command-line "
1617 "option");
1618 goto out;
1620 *activep = 0;
1621 arg2 = NULL;
1622 while ((arg = argv_next(&ac, &av)) != NULL) {
1623 if (*arg == '\0') {
1624 error("%s line %d: keyword %s empty argument",
1625 filename, linenum, keyword);
1626 goto out;
1628 if ((flags & SSHCONF_NEVERMATCH) != 0) {
1629 argv_consume(&ac);
1630 break;
1632 negated = *arg == '!';
1633 if (negated)
1634 arg++;
1635 if (match_pattern(host, arg)) {
1636 if (negated) {
1637 debug("%.200s line %d: Skipping Host "
1638 "block because of negated match "
1639 "for %.100s", filename, linenum,
1640 arg);
1641 *activep = 0;
1642 argv_consume(&ac);
1643 break;
1645 if (!*activep)
1646 arg2 = arg; /* logged below */
1647 *activep = 1;
1650 if (*activep)
1651 debug("%.200s line %d: Applying options for %.100s",
1652 filename, linenum, arg2);
1653 break;
1655 case oMatch:
1656 if (cmdline) {
1657 error("Host directive not supported as a command-line "
1658 "option");
1659 goto out;
1661 value = match_cfg_line(options, &str, pw, host, original_host,
1662 flags & SSHCONF_FINAL, want_final_pass,
1663 filename, linenum);
1664 if (value < 0) {
1665 error("%.200s line %d: Bad Match condition", filename,
1666 linenum);
1667 goto out;
1669 *activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
1671 * If match_cfg_line() didn't consume all its arguments then
1672 * arrange for the extra arguments check below to fail.
1675 if (str == NULL || *str == '\0')
1676 argv_consume(&ac);
1677 break;
1679 case oEscapeChar:
1680 intptr = &options->escape_char;
1681 arg = argv_next(&ac, &av);
1682 if (!arg || *arg == '\0') {
1683 error("%.200s line %d: Missing argument.",
1684 filename, linenum);
1685 goto out;
1687 if (strcmp(arg, "none") == 0)
1688 value = SSH_ESCAPECHAR_NONE;
1689 else if (arg[1] == '\0')
1690 value = (u_char) arg[0];
1691 else if (arg[0] == '^' && arg[2] == 0 &&
1692 (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1693 value = (u_char) arg[1] & 31;
1694 else {
1695 error("%.200s line %d: Bad escape character.",
1696 filename, linenum);
1697 goto out;
1699 if (*activep && *intptr == -1)
1700 *intptr = value;
1701 break;
1703 case oAddressFamily:
1704 intptr = &options->address_family;
1705 multistate_ptr = multistate_addressfamily;
1706 goto parse_multistate;
1708 case oEnableSSHKeysign:
1709 intptr = &options->enable_ssh_keysign;
1710 goto parse_flag;
1712 case oIdentitiesOnly:
1713 intptr = &options->identities_only;
1714 goto parse_flag;
1716 case oServerAliveInterval:
1717 intptr = &options->server_alive_interval;
1718 goto parse_time;
1720 case oServerAliveCountMax:
1721 intptr = &options->server_alive_count_max;
1722 goto parse_int;
1724 case oSendEnv:
1725 while ((arg = argv_next(&ac, &av)) != NULL) {
1726 if (*arg == '\0' || strchr(arg, '=') != NULL) {
1727 error("%s line %d: Invalid environment name.",
1728 filename, linenum);
1729 goto out;
1731 if (!*activep)
1732 continue;
1733 if (*arg == '-') {
1734 /* Removing an env var */
1735 rm_env(options, arg, filename, linenum);
1736 continue;
1738 opt_array_append(filename, linenum,
1739 lookup_opcode_name(opcode),
1740 &options->send_env, &options->num_send_env, arg);
1742 break;
1744 case oSetEnv:
1745 value = options->num_setenv;
1746 while ((arg = argv_next(&ac, &av)) != NULL) {
1747 if (strchr(arg, '=') == NULL) {
1748 error("%s line %d: Invalid SetEnv.",
1749 filename, linenum);
1750 goto out;
1752 if (!*activep || value != 0)
1753 continue;
1754 if (lookup_setenv_in_list(arg, options->setenv,
1755 options->num_setenv) != NULL) {
1756 debug2("%s line %d: ignoring duplicate env "
1757 "name \"%.64s\"", filename, linenum, arg);
1758 continue;
1760 opt_array_append(filename, linenum,
1761 lookup_opcode_name(opcode),
1762 &options->setenv, &options->num_setenv, arg);
1764 break;
1766 case oControlPath:
1767 charptr = &options->control_path;
1768 goto parse_string;
1770 case oControlMaster:
1771 intptr = &options->control_master;
1772 multistate_ptr = multistate_controlmaster;
1773 goto parse_multistate;
1775 case oControlPersist:
1776 /* no/false/yes/true, or a time spec */
1777 intptr = &options->control_persist;
1778 arg = argv_next(&ac, &av);
1779 if (!arg || *arg == '\0') {
1780 error("%.200s line %d: Missing ControlPersist"
1781 " argument.", filename, linenum);
1782 goto out;
1784 value = 0;
1785 value2 = 0; /* timeout */
1786 if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1787 value = 0;
1788 else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1789 value = 1;
1790 else if ((value2 = convtime(arg)) >= 0)
1791 value = 1;
1792 else {
1793 error("%.200s line %d: Bad ControlPersist argument.",
1794 filename, linenum);
1795 goto out;
1797 if (*activep && *intptr == -1) {
1798 *intptr = value;
1799 options->control_persist_timeout = value2;
1801 break;
1803 case oHashKnownHosts:
1804 intptr = &options->hash_known_hosts;
1805 goto parse_flag;
1807 case oTunnel:
1808 intptr = &options->tun_open;
1809 multistate_ptr = multistate_tunnel;
1810 goto parse_multistate;
1812 case oTunnelDevice:
1813 arg = argv_next(&ac, &av);
1814 if (!arg || *arg == '\0') {
1815 error("%.200s line %d: Missing argument.",
1816 filename, linenum);
1817 goto out;
1819 value = a2tun(arg, &value2);
1820 if (value == SSH_TUNID_ERR) {
1821 error("%.200s line %d: Bad tun device.",
1822 filename, linenum);
1823 goto out;
1825 if (*activep && options->tun_local == -1) {
1826 options->tun_local = value;
1827 options->tun_remote = value2;
1829 break;
1831 case oLocalCommand:
1832 charptr = &options->local_command;
1833 goto parse_command;
1835 case oPermitLocalCommand:
1836 intptr = &options->permit_local_command;
1837 goto parse_flag;
1839 case oRemoteCommand:
1840 charptr = &options->remote_command;
1841 goto parse_command;
1843 case oVisualHostKey:
1844 intptr = &options->visual_host_key;
1845 goto parse_flag;
1847 case oInclude:
1848 if (cmdline) {
1849 error("Include directive not supported as a "
1850 "command-line option");
1851 goto out;
1853 value = 0;
1854 while ((arg = argv_next(&ac, &av)) != NULL) {
1855 if (*arg == '\0') {
1856 error("%s line %d: keyword %s empty argument",
1857 filename, linenum, keyword);
1858 goto out;
1861 * Ensure all paths are anchored. User configuration
1862 * files may begin with '~/' but system configurations
1863 * must not. If the path is relative, then treat it
1864 * as living in ~/.ssh for user configurations or
1865 * /etc/ssh for system ones.
1867 if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0) {
1868 error("%.200s line %d: bad include path %s.",
1869 filename, linenum, arg);
1870 goto out;
1872 if (!path_absolute(arg) && *arg != '~') {
1873 xasprintf(&arg2, "%s/%s",
1874 (flags & SSHCONF_USERCONF) ?
1875 "~/" _PATH_SSH_USER_DIR : SSHDIR, arg);
1876 } else
1877 arg2 = xstrdup(arg);
1878 memset(&gl, 0, sizeof(gl));
1879 r = glob(arg2, GLOB_TILDE, NULL, &gl);
1880 if (r == GLOB_NOMATCH) {
1881 debug("%.200s line %d: include %s matched no "
1882 "files",filename, linenum, arg2);
1883 free(arg2);
1884 continue;
1885 } else if (r != 0) {
1886 error("%.200s line %d: glob failed for %s.",
1887 filename, linenum, arg2);
1888 goto out;
1890 free(arg2);
1891 oactive = *activep;
1892 for (i = 0; i < gl.gl_pathc; i++) {
1893 debug3("%.200s line %d: Including file %s "
1894 "depth %d%s", filename, linenum,
1895 gl.gl_pathv[i], depth,
1896 oactive ? "" : " (parse only)");
1897 r = read_config_file_depth(gl.gl_pathv[i],
1898 pw, host, original_host, options,
1899 flags | SSHCONF_CHECKPERM |
1900 (oactive ? 0 : SSHCONF_NEVERMATCH),
1901 activep, want_final_pass, depth + 1);
1902 if (r != 1 && errno != ENOENT) {
1903 error("Can't open user config file "
1904 "%.100s: %.100s", gl.gl_pathv[i],
1905 strerror(errno));
1906 globfree(&gl);
1907 goto out;
1910 * don't let Match in includes clobber the
1911 * containing file's Match state.
1913 *activep = oactive;
1914 if (r != 1)
1915 value = -1;
1917 globfree(&gl);
1919 if (value != 0)
1920 ret = value;
1921 break;
1923 case oIPQoS:
1924 arg = argv_next(&ac, &av);
1925 if ((value = parse_ipqos(arg)) == -1) {
1926 error("%s line %d: Bad IPQoS value: %s",
1927 filename, linenum, arg);
1928 goto out;
1930 arg = argv_next(&ac, &av);
1931 if (arg == NULL)
1932 value2 = value;
1933 else if ((value2 = parse_ipqos(arg)) == -1) {
1934 error("%s line %d: Bad IPQoS value: %s",
1935 filename, linenum, arg);
1936 goto out;
1938 if (*activep && options->ip_qos_interactive == -1) {
1939 options->ip_qos_interactive = value;
1940 options->ip_qos_bulk = value2;
1942 break;
1944 case oRequestTTY:
1945 intptr = &options->request_tty;
1946 multistate_ptr = multistate_requesttty;
1947 goto parse_multistate;
1949 case oSessionType:
1950 intptr = &options->session_type;
1951 multistate_ptr = multistate_sessiontype;
1952 goto parse_multistate;
1954 case oStdinNull:
1955 intptr = &options->stdin_null;
1956 goto parse_flag;
1958 case oForkAfterAuthentication:
1959 intptr = &options->fork_after_authentication;
1960 goto parse_flag;
1962 case oIgnoreUnknown:
1963 charptr = &options->ignored_unknown;
1964 goto parse_string;
1966 case oProxyUseFdpass:
1967 intptr = &options->proxy_use_fdpass;
1968 goto parse_flag;
1970 case oCanonicalDomains:
1971 value = options->num_canonical_domains != 0;
1972 i = 0;
1973 while ((arg = argv_next(&ac, &av)) != NULL) {
1974 if (*arg == '\0') {
1975 error("%s line %d: keyword %s empty argument",
1976 filename, linenum, keyword);
1977 goto out;
1979 /* Allow "none" only in first position */
1980 if (strcasecmp(arg, "none") == 0) {
1981 if (i > 0 || ac > 0) {
1982 error("%s line %d: keyword %s \"none\" "
1983 "argument must appear alone.",
1984 filename, linenum, keyword);
1985 goto out;
1988 i++;
1989 if (!valid_domain(arg, 1, &errstr)) {
1990 error("%s line %d: %s", filename, linenum,
1991 errstr);
1992 goto out;
1994 if (!*activep || value)
1995 continue;
1996 if (options->num_canonical_domains >=
1997 MAX_CANON_DOMAINS) {
1998 error("%s line %d: too many hostname suffixes.",
1999 filename, linenum);
2000 goto out;
2002 options->canonical_domains[
2003 options->num_canonical_domains++] = xstrdup(arg);
2005 break;
2007 case oCanonicalizePermittedCNAMEs:
2008 value = options->num_permitted_cnames != 0;
2009 i = 0;
2010 while ((arg = argv_next(&ac, &av)) != NULL) {
2012 * Either 'none' (only in first position), '*' for
2013 * everything or 'list:list'
2015 if (strcasecmp(arg, "none") == 0) {
2016 if (i > 0 || ac > 0) {
2017 error("%s line %d: keyword %s \"none\" "
2018 "argument must appear alone.",
2019 filename, linenum, keyword);
2020 goto out;
2022 arg2 = "";
2023 } else if (strcmp(arg, "*") == 0) {
2024 arg2 = arg;
2025 } else {
2026 lowercase(arg);
2027 if ((arg2 = strchr(arg, ':')) == NULL ||
2028 arg2[1] == '\0') {
2029 error("%s line %d: "
2030 "Invalid permitted CNAME \"%s\"",
2031 filename, linenum, arg);
2032 goto out;
2034 *arg2 = '\0';
2035 arg2++;
2037 i++;
2038 if (!*activep || value)
2039 continue;
2040 if (options->num_permitted_cnames >=
2041 MAX_CANON_DOMAINS) {
2042 error("%s line %d: too many permitted CNAMEs.",
2043 filename, linenum);
2044 goto out;
2046 cname = options->permitted_cnames +
2047 options->num_permitted_cnames++;
2048 cname->source_list = xstrdup(arg);
2049 cname->target_list = xstrdup(arg2);
2051 break;
2053 case oCanonicalizeHostname:
2054 intptr = &options->canonicalize_hostname;
2055 multistate_ptr = multistate_canonicalizehostname;
2056 goto parse_multistate;
2058 case oCanonicalizeMaxDots:
2059 intptr = &options->canonicalize_max_dots;
2060 goto parse_int;
2062 case oCanonicalizeFallbackLocal:
2063 intptr = &options->canonicalize_fallback_local;
2064 goto parse_flag;
2066 case oStreamLocalBindMask:
2067 arg = argv_next(&ac, &av);
2068 if (!arg || *arg == '\0') {
2069 error("%.200s line %d: Missing StreamLocalBindMask "
2070 "argument.", filename, linenum);
2071 goto out;
2073 /* Parse mode in octal format */
2074 value = strtol(arg, &endofnumber, 8);
2075 if (arg == endofnumber || value < 0 || value > 0777) {
2076 error("%.200s line %d: Bad mask.", filename, linenum);
2077 goto out;
2079 options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
2080 break;
2082 case oStreamLocalBindUnlink:
2083 intptr = &options->fwd_opts.streamlocal_bind_unlink;
2084 goto parse_flag;
2086 case oRevokedHostKeys:
2087 charptr = &options->revoked_host_keys;
2088 goto parse_string;
2090 case oFingerprintHash:
2091 intptr = &options->fingerprint_hash;
2092 arg = argv_next(&ac, &av);
2093 if (!arg || *arg == '\0') {
2094 error("%.200s line %d: Missing argument.",
2095 filename, linenum);
2096 goto out;
2098 if ((value = ssh_digest_alg_by_name(arg)) == -1) {
2099 error("%.200s line %d: Invalid hash algorithm \"%s\".",
2100 filename, linenum, arg);
2101 goto out;
2103 if (*activep && *intptr == -1)
2104 *intptr = value;
2105 break;
2107 case oUpdateHostkeys:
2108 intptr = &options->update_hostkeys;
2109 multistate_ptr = multistate_yesnoask;
2110 goto parse_multistate;
2112 case oHostbasedAcceptedAlgorithms:
2113 charptr = &options->hostbased_accepted_algos;
2114 goto parse_pubkey_algos;
2116 case oPubkeyAcceptedAlgorithms:
2117 charptr = &options->pubkey_accepted_algos;
2118 goto parse_pubkey_algos;
2120 case oAddKeysToAgent:
2121 arg = argv_next(&ac, &av);
2122 arg2 = argv_next(&ac, &av);
2123 value = parse_multistate_value(arg, filename, linenum,
2124 multistate_yesnoaskconfirm);
2125 value2 = 0; /* unlimited lifespan by default */
2126 if (value == 3 && arg2 != NULL) {
2127 /* allow "AddKeysToAgent confirm 5m" */
2128 if ((value2 = convtime(arg2)) == -1 ||
2129 value2 > INT_MAX) {
2130 error("%s line %d: invalid time value.",
2131 filename, linenum);
2132 goto out;
2134 } else if (value == -1 && arg2 == NULL) {
2135 if ((value2 = convtime(arg)) == -1 ||
2136 value2 > INT_MAX) {
2137 error("%s line %d: unsupported option",
2138 filename, linenum);
2139 goto out;
2141 value = 1; /* yes */
2142 } else if (value == -1 || arg2 != NULL) {
2143 error("%s line %d: unsupported option",
2144 filename, linenum);
2145 goto out;
2147 if (*activep && options->add_keys_to_agent == -1) {
2148 options->add_keys_to_agent = value;
2149 options->add_keys_to_agent_lifespan = value2;
2151 break;
2153 case oIdentityAgent:
2154 charptr = &options->identity_agent;
2155 arg = argv_next(&ac, &av);
2156 if (!arg || *arg == '\0') {
2157 error("%.200s line %d: Missing argument.",
2158 filename, linenum);
2159 goto out;
2161 parse_agent_path:
2162 /* Extra validation if the string represents an env var. */
2163 if ((arg2 = dollar_expand(&r, arg)) == NULL || r) {
2164 error("%.200s line %d: Invalid environment expansion "
2165 "%s.", filename, linenum, arg);
2166 goto out;
2168 free(arg2);
2169 /* check for legacy environment format */
2170 if (arg[0] == '$' && arg[1] != '{' &&
2171 !valid_env_name(arg + 1)) {
2172 error("%.200s line %d: Invalid environment name %s.",
2173 filename, linenum, arg);
2174 goto out;
2176 if (*activep && *charptr == NULL)
2177 *charptr = xstrdup(arg);
2178 break;
2180 case oRequiredRSASize:
2181 intptr = &options->required_rsa_size;
2182 goto parse_int;
2184 case oDeprecated:
2185 debug("%s line %d: Deprecated option \"%s\"",
2186 filename, linenum, keyword);
2187 argv_consume(&ac);
2188 break;
2190 case oUnsupported:
2191 error("%s line %d: Unsupported option \"%s\"",
2192 filename, linenum, keyword);
2193 argv_consume(&ac);
2194 break;
2196 default:
2197 error("%s line %d: Unimplemented opcode %d",
2198 filename, linenum, opcode);
2199 goto out;
2202 /* Check that there is no garbage at end of line. */
2203 if (ac > 0) {
2204 error("%.200s line %d: keyword %s extra arguments "
2205 "at end of line", filename, linenum, keyword);
2206 goto out;
2209 /* success */
2210 ret = 0;
2211 out:
2212 argv_free(oav, oac);
2213 return ret;
2217 * Reads the config file and modifies the options accordingly. Options
2218 * should already be initialized before this call. This never returns if
2219 * there is an error. If the file does not exist, this returns 0.
2222 read_config_file(const char *filename, struct passwd *pw, const char *host,
2223 const char *original_host, Options *options, int flags,
2224 int *want_final_pass)
2226 int active = 1;
2228 return read_config_file_depth(filename, pw, host, original_host,
2229 options, flags, &active, want_final_pass, 0);
2232 #define READCONF_MAX_DEPTH 16
2233 static int
2234 read_config_file_depth(const char *filename, struct passwd *pw,
2235 const char *host, const char *original_host, Options *options,
2236 int flags, int *activep, int *want_final_pass, int depth)
2238 FILE *f;
2239 char *line = NULL;
2240 size_t linesize = 0;
2241 int linenum;
2242 int bad_options = 0;
2244 if (depth < 0 || depth > READCONF_MAX_DEPTH)
2245 fatal("Too many recursive configuration includes");
2247 if ((f = fopen(filename, "r")) == NULL)
2248 return 0;
2250 if (flags & SSHCONF_CHECKPERM) {
2251 struct stat sb;
2253 if (fstat(fileno(f), &sb) == -1)
2254 fatal("fstat %s: %s", filename, strerror(errno));
2255 if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
2256 (sb.st_mode & 022) != 0))
2257 fatal("Bad owner or permissions on %s", filename);
2260 debug("Reading configuration data %.200s", filename);
2263 * Mark that we are now processing the options. This flag is turned
2264 * on/off by Host specifications.
2266 linenum = 0;
2267 while (getline(&line, &linesize, f) != -1) {
2268 /* Update line number counter. */
2269 linenum++;
2271 * Trim out comments and strip whitespace.
2272 * NB - preserve newlines, they are needed to reproduce
2273 * line numbers later for error messages.
2275 if (process_config_line_depth(options, pw, host, original_host,
2276 line, filename, linenum, activep, flags, want_final_pass,
2277 depth) != 0)
2278 bad_options++;
2280 free(line);
2281 fclose(f);
2282 if (bad_options > 0)
2283 fatal("%s: terminating, %d bad configuration options",
2284 filename, bad_options);
2285 return 1;
2288 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
2290 option_clear_or_none(const char *o)
2292 return o == NULL || strcasecmp(o, "none") == 0;
2296 * Returns 1 if CanonicalizePermittedCNAMEs have been specified, 0 otherwise.
2297 * Allowed to be called on non-final configuration.
2300 config_has_permitted_cnames(Options *options)
2302 if (options->num_permitted_cnames == 1 &&
2303 strcasecmp(options->permitted_cnames[0].source_list, "none") == 0 &&
2304 strcmp(options->permitted_cnames[0].target_list, "") == 0)
2305 return 0;
2306 return options->num_permitted_cnames > 0;
2310 * Initializes options to special values that indicate that they have not yet
2311 * been set. Read_config_file will only set options with this value. Options
2312 * are processed in the following order: command line, user config file,
2313 * system config file. Last, fill_default_options is called.
2316 void
2317 initialize_options(Options * options)
2319 memset(options, 'X', sizeof(*options));
2320 options->forward_agent = -1;
2321 options->forward_agent_sock_path = NULL;
2322 options->forward_x11 = -1;
2323 options->forward_x11_trusted = -1;
2324 options->forward_x11_timeout = -1;
2325 options->stdio_forward_host = NULL;
2326 options->stdio_forward_port = 0;
2327 options->clear_forwardings = -1;
2328 options->exit_on_forward_failure = -1;
2329 options->xauth_location = NULL;
2330 options->fwd_opts.gateway_ports = -1;
2331 options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
2332 options->fwd_opts.streamlocal_bind_unlink = -1;
2333 options->pubkey_authentication = -1;
2334 options->gss_authentication = -1;
2335 options->gss_deleg_creds = -1;
2336 options->password_authentication = -1;
2337 options->kbd_interactive_authentication = -1;
2338 options->kbd_interactive_devices = NULL;
2339 options->hostbased_authentication = -1;
2340 options->batch_mode = -1;
2341 options->check_host_ip = -1;
2342 options->strict_host_key_checking = -1;
2343 options->compression = -1;
2344 options->tcp_keep_alive = -1;
2345 options->port = -1;
2346 options->address_family = -1;
2347 options->connection_attempts = -1;
2348 options->connection_timeout = -1;
2349 options->number_of_password_prompts = -1;
2350 options->ciphers = NULL;
2351 options->macs = NULL;
2352 options->kex_algorithms = NULL;
2353 options->hostkeyalgorithms = NULL;
2354 options->ca_sign_algorithms = NULL;
2355 options->num_identity_files = 0;
2356 memset(options->identity_keys, 0, sizeof(options->identity_keys));
2357 options->num_certificate_files = 0;
2358 memset(options->certificates, 0, sizeof(options->certificates));
2359 options->hostname = NULL;
2360 options->host_key_alias = NULL;
2361 options->proxy_command = NULL;
2362 options->jump_user = NULL;
2363 options->jump_host = NULL;
2364 options->jump_port = -1;
2365 options->jump_extra = NULL;
2366 options->user = NULL;
2367 options->escape_char = -1;
2368 options->num_system_hostfiles = 0;
2369 options->num_user_hostfiles = 0;
2370 options->local_forwards = NULL;
2371 options->num_local_forwards = 0;
2372 options->remote_forwards = NULL;
2373 options->num_remote_forwards = 0;
2374 options->permitted_remote_opens = NULL;
2375 options->num_permitted_remote_opens = 0;
2376 options->log_facility = SYSLOG_FACILITY_NOT_SET;
2377 options->log_level = SYSLOG_LEVEL_NOT_SET;
2378 options->num_log_verbose = 0;
2379 options->log_verbose = NULL;
2380 options->preferred_authentications = NULL;
2381 options->bind_address = NULL;
2382 options->bind_interface = NULL;
2383 options->pkcs11_provider = NULL;
2384 options->sk_provider = NULL;
2385 options->enable_ssh_keysign = - 1;
2386 options->no_host_authentication_for_localhost = - 1;
2387 options->identities_only = - 1;
2388 options->rekey_limit = - 1;
2389 options->rekey_interval = -1;
2390 options->verify_host_key_dns = -1;
2391 options->server_alive_interval = -1;
2392 options->server_alive_count_max = -1;
2393 options->send_env = NULL;
2394 options->num_send_env = 0;
2395 options->setenv = NULL;
2396 options->num_setenv = 0;
2397 options->control_path = NULL;
2398 options->control_master = -1;
2399 options->control_persist = -1;
2400 options->control_persist_timeout = 0;
2401 options->hash_known_hosts = -1;
2402 options->tun_open = -1;
2403 options->tun_local = -1;
2404 options->tun_remote = -1;
2405 options->local_command = NULL;
2406 options->permit_local_command = -1;
2407 options->remote_command = NULL;
2408 options->add_keys_to_agent = -1;
2409 options->add_keys_to_agent_lifespan = -1;
2410 options->identity_agent = NULL;
2411 options->visual_host_key = -1;
2412 options->ip_qos_interactive = -1;
2413 options->ip_qos_bulk = -1;
2414 options->request_tty = -1;
2415 options->session_type = -1;
2416 options->stdin_null = -1;
2417 options->fork_after_authentication = -1;
2418 options->proxy_use_fdpass = -1;
2419 options->ignored_unknown = NULL;
2420 options->num_canonical_domains = 0;
2421 options->num_permitted_cnames = 0;
2422 options->canonicalize_max_dots = -1;
2423 options->canonicalize_fallback_local = -1;
2424 options->canonicalize_hostname = -1;
2425 options->revoked_host_keys = NULL;
2426 options->fingerprint_hash = -1;
2427 options->update_hostkeys = -1;
2428 options->hostbased_accepted_algos = NULL;
2429 options->pubkey_accepted_algos = NULL;
2430 options->known_hosts_command = NULL;
2431 options->required_rsa_size = -1;
2435 * A petite version of fill_default_options() that just fills the options
2436 * needed for hostname canonicalization to proceed.
2438 void
2439 fill_default_options_for_canonicalization(Options *options)
2441 if (options->canonicalize_max_dots == -1)
2442 options->canonicalize_max_dots = 1;
2443 if (options->canonicalize_fallback_local == -1)
2444 options->canonicalize_fallback_local = 1;
2445 if (options->canonicalize_hostname == -1)
2446 options->canonicalize_hostname = SSH_CANONICALISE_NO;
2450 * Called after processing other sources of option data, this fills those
2451 * options for which no value has been specified with their default values.
2454 fill_default_options(Options * options)
2456 char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
2457 char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
2458 int ret = 0, r;
2460 if (options->forward_agent == -1)
2461 options->forward_agent = 0;
2462 if (options->forward_x11 == -1)
2463 options->forward_x11 = 0;
2464 if (options->forward_x11_trusted == -1)
2465 options->forward_x11_trusted = 0;
2466 if (options->forward_x11_timeout == -1)
2467 options->forward_x11_timeout = 1200;
2469 * stdio forwarding (-W) changes the default for these but we defer
2470 * setting the values so they can be overridden.
2472 if (options->exit_on_forward_failure == -1)
2473 options->exit_on_forward_failure =
2474 options->stdio_forward_host != NULL ? 1 : 0;
2475 if (options->clear_forwardings == -1)
2476 options->clear_forwardings =
2477 options->stdio_forward_host != NULL ? 1 : 0;
2478 if (options->clear_forwardings == 1)
2479 clear_forwardings(options);
2481 if (options->xauth_location == NULL)
2482 options->xauth_location = xstrdup(_PATH_XAUTH);
2483 if (options->fwd_opts.gateway_ports == -1)
2484 options->fwd_opts.gateway_ports = 0;
2485 if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
2486 options->fwd_opts.streamlocal_bind_mask = 0177;
2487 if (options->fwd_opts.streamlocal_bind_unlink == -1)
2488 options->fwd_opts.streamlocal_bind_unlink = 0;
2489 if (options->pubkey_authentication == -1)
2490 options->pubkey_authentication = SSH_PUBKEY_AUTH_ALL;
2491 if (options->gss_authentication == -1)
2492 options->gss_authentication = 0;
2493 if (options->gss_deleg_creds == -1)
2494 options->gss_deleg_creds = 0;
2495 if (options->password_authentication == -1)
2496 options->password_authentication = 1;
2497 if (options->kbd_interactive_authentication == -1)
2498 options->kbd_interactive_authentication = 1;
2499 if (options->hostbased_authentication == -1)
2500 options->hostbased_authentication = 0;
2501 if (options->batch_mode == -1)
2502 options->batch_mode = 0;
2503 if (options->check_host_ip == -1)
2504 options->check_host_ip = 0;
2505 if (options->strict_host_key_checking == -1)
2506 options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK;
2507 if (options->compression == -1)
2508 options->compression = 0;
2509 if (options->tcp_keep_alive == -1)
2510 options->tcp_keep_alive = 1;
2511 if (options->port == -1)
2512 options->port = 0; /* Filled in ssh_connect. */
2513 if (options->address_family == -1)
2514 options->address_family = AF_UNSPEC;
2515 if (options->connection_attempts == -1)
2516 options->connection_attempts = 1;
2517 if (options->number_of_password_prompts == -1)
2518 options->number_of_password_prompts = 3;
2519 /* options->hostkeyalgorithms, default set in myproposals.h */
2520 if (options->add_keys_to_agent == -1) {
2521 options->add_keys_to_agent = 0;
2522 options->add_keys_to_agent_lifespan = 0;
2524 if (options->num_identity_files == 0) {
2525 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0);
2526 #ifdef OPENSSL_HAS_ECC
2527 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0);
2528 add_identity_file(options, "~/",
2529 _PATH_SSH_CLIENT_ID_ECDSA_SK, 0);
2530 #endif
2531 add_identity_file(options, "~/",
2532 _PATH_SSH_CLIENT_ID_ED25519, 0);
2533 add_identity_file(options, "~/",
2534 _PATH_SSH_CLIENT_ID_ED25519_SK, 0);
2535 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0);
2536 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0);
2538 if (options->escape_char == -1)
2539 options->escape_char = '~';
2540 if (options->num_system_hostfiles == 0) {
2541 options->system_hostfiles[options->num_system_hostfiles++] =
2542 xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
2543 options->system_hostfiles[options->num_system_hostfiles++] =
2544 xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
2546 if (options->update_hostkeys == -1) {
2547 if (options->verify_host_key_dns <= 0 &&
2548 (options->num_user_hostfiles == 0 ||
2549 (options->num_user_hostfiles == 1 && strcmp(options->
2550 user_hostfiles[0], _PATH_SSH_USER_HOSTFILE) == 0)))
2551 options->update_hostkeys = SSH_UPDATE_HOSTKEYS_YES;
2552 else
2553 options->update_hostkeys = SSH_UPDATE_HOSTKEYS_NO;
2555 if (options->num_user_hostfiles == 0) {
2556 options->user_hostfiles[options->num_user_hostfiles++] =
2557 xstrdup(_PATH_SSH_USER_HOSTFILE);
2558 options->user_hostfiles[options->num_user_hostfiles++] =
2559 xstrdup(_PATH_SSH_USER_HOSTFILE2);
2561 if (options->log_level == SYSLOG_LEVEL_NOT_SET)
2562 options->log_level = SYSLOG_LEVEL_INFO;
2563 if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
2564 options->log_facility = SYSLOG_FACILITY_USER;
2565 if (options->no_host_authentication_for_localhost == - 1)
2566 options->no_host_authentication_for_localhost = 0;
2567 if (options->identities_only == -1)
2568 options->identities_only = 0;
2569 if (options->enable_ssh_keysign == -1)
2570 options->enable_ssh_keysign = 0;
2571 if (options->rekey_limit == -1)
2572 options->rekey_limit = 0;
2573 if (options->rekey_interval == -1)
2574 options->rekey_interval = 0;
2575 if (options->verify_host_key_dns == -1)
2576 options->verify_host_key_dns = 0;
2577 if (options->server_alive_interval == -1)
2578 options->server_alive_interval = 0;
2579 if (options->server_alive_count_max == -1)
2580 options->server_alive_count_max = 3;
2581 if (options->control_master == -1)
2582 options->control_master = 0;
2583 if (options->control_persist == -1) {
2584 options->control_persist = 0;
2585 options->control_persist_timeout = 0;
2587 if (options->hash_known_hosts == -1)
2588 options->hash_known_hosts = 0;
2589 if (options->tun_open == -1)
2590 options->tun_open = SSH_TUNMODE_NO;
2591 if (options->tun_local == -1)
2592 options->tun_local = SSH_TUNID_ANY;
2593 if (options->tun_remote == -1)
2594 options->tun_remote = SSH_TUNID_ANY;
2595 if (options->permit_local_command == -1)
2596 options->permit_local_command = 0;
2597 if (options->visual_host_key == -1)
2598 options->visual_host_key = 0;
2599 if (options->ip_qos_interactive == -1)
2600 options->ip_qos_interactive = IPTOS_DSCP_AF21;
2601 if (options->ip_qos_bulk == -1)
2602 options->ip_qos_bulk = IPTOS_DSCP_CS1;
2603 if (options->request_tty == -1)
2604 options->request_tty = REQUEST_TTY_AUTO;
2605 if (options->session_type == -1)
2606 options->session_type = SESSION_TYPE_DEFAULT;
2607 if (options->stdin_null == -1)
2608 options->stdin_null = 0;
2609 if (options->fork_after_authentication == -1)
2610 options->fork_after_authentication = 0;
2611 if (options->proxy_use_fdpass == -1)
2612 options->proxy_use_fdpass = 0;
2613 if (options->canonicalize_max_dots == -1)
2614 options->canonicalize_max_dots = 1;
2615 if (options->canonicalize_fallback_local == -1)
2616 options->canonicalize_fallback_local = 1;
2617 if (options->canonicalize_hostname == -1)
2618 options->canonicalize_hostname = SSH_CANONICALISE_NO;
2619 if (options->fingerprint_hash == -1)
2620 options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
2621 #ifdef ENABLE_SK_INTERNAL
2622 if (options->sk_provider == NULL)
2623 options->sk_provider = xstrdup("internal");
2624 #else
2625 if (options->sk_provider == NULL)
2626 options->sk_provider = xstrdup("$SSH_SK_PROVIDER");
2627 #endif
2628 if (options->required_rsa_size == -1)
2629 options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
2631 /* Expand KEX name lists */
2632 all_cipher = cipher_alg_list(',', 0);
2633 all_mac = mac_alg_list(',');
2634 all_kex = kex_alg_list(',');
2635 all_key = sshkey_alg_list(0, 0, 1, ',');
2636 all_sig = sshkey_alg_list(0, 1, 1, ',');
2637 /* remove unsupported algos from default lists */
2638 def_cipher = match_filter_allowlist(KEX_CLIENT_ENCRYPT, all_cipher);
2639 def_mac = match_filter_allowlist(KEX_CLIENT_MAC, all_mac);
2640 def_kex = match_filter_allowlist(KEX_CLIENT_KEX, all_kex);
2641 def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
2642 def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
2643 #define ASSEMBLE(what, defaults, all) \
2644 do { \
2645 if ((r = kex_assemble_names(&options->what, \
2646 defaults, all)) != 0) { \
2647 error_fr(r, "%s", #what); \
2648 goto fail; \
2650 } while (0)
2651 ASSEMBLE(ciphers, def_cipher, all_cipher);
2652 ASSEMBLE(macs, def_mac, all_mac);
2653 ASSEMBLE(kex_algorithms, def_kex, all_kex);
2654 ASSEMBLE(hostbased_accepted_algos, def_key, all_key);
2655 ASSEMBLE(pubkey_accepted_algos, def_key, all_key);
2656 ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
2657 #undef ASSEMBLE
2659 #define CLEAR_ON_NONE(v) \
2660 do { \
2661 if (option_clear_or_none(v)) { \
2662 free(v); \
2663 v = NULL; \
2665 } while(0)
2666 CLEAR_ON_NONE(options->local_command);
2667 CLEAR_ON_NONE(options->remote_command);
2668 CLEAR_ON_NONE(options->proxy_command);
2669 CLEAR_ON_NONE(options->control_path);
2670 CLEAR_ON_NONE(options->revoked_host_keys);
2671 CLEAR_ON_NONE(options->pkcs11_provider);
2672 CLEAR_ON_NONE(options->sk_provider);
2673 CLEAR_ON_NONE(options->known_hosts_command);
2674 if (options->jump_host != NULL &&
2675 strcmp(options->jump_host, "none") == 0 &&
2676 options->jump_port == 0 && options->jump_user == NULL) {
2677 free(options->jump_host);
2678 options->jump_host = NULL;
2680 if (options->num_permitted_cnames == 1 &&
2681 !config_has_permitted_cnames(options)) {
2682 /* clean up CanonicalizePermittedCNAMEs=none */
2683 free(options->permitted_cnames[0].source_list);
2684 free(options->permitted_cnames[0].target_list);
2685 memset(options->permitted_cnames, '\0',
2686 sizeof(*options->permitted_cnames));
2687 options->num_permitted_cnames = 0;
2689 /* options->identity_agent distinguishes NULL from 'none' */
2690 /* options->user will be set in the main program if appropriate */
2691 /* options->hostname will be set in the main program if appropriate */
2692 /* options->host_key_alias should not be set by default */
2693 /* options->preferred_authentications will be set in ssh */
2695 /* success */
2696 ret = 0;
2697 fail:
2698 free(all_cipher);
2699 free(all_mac);
2700 free(all_kex);
2701 free(all_key);
2702 free(all_sig);
2703 free(def_cipher);
2704 free(def_mac);
2705 free(def_kex);
2706 free(def_key);
2707 free(def_sig);
2708 return ret;
2711 void
2712 free_options(Options *o)
2714 int i;
2716 if (o == NULL)
2717 return;
2719 #define FREE_ARRAY(type, n, a) \
2720 do { \
2721 type _i; \
2722 for (_i = 0; _i < (n); _i++) \
2723 free((a)[_i]); \
2724 } while (0)
2726 free(o->forward_agent_sock_path);
2727 free(o->xauth_location);
2728 FREE_ARRAY(u_int, o->num_log_verbose, o->log_verbose);
2729 free(o->log_verbose);
2730 free(o->ciphers);
2731 free(o->macs);
2732 free(o->hostkeyalgorithms);
2733 free(o->kex_algorithms);
2734 free(o->ca_sign_algorithms);
2735 free(o->hostname);
2736 free(o->host_key_alias);
2737 free(o->proxy_command);
2738 free(o->user);
2739 FREE_ARRAY(u_int, o->num_system_hostfiles, o->system_hostfiles);
2740 FREE_ARRAY(u_int, o->num_user_hostfiles, o->user_hostfiles);
2741 free(o->preferred_authentications);
2742 free(o->bind_address);
2743 free(o->bind_interface);
2744 free(o->pkcs11_provider);
2745 free(o->sk_provider);
2746 for (i = 0; i < o->num_identity_files; i++) {
2747 free(o->identity_files[i]);
2748 sshkey_free(o->identity_keys[i]);
2750 for (i = 0; i < o->num_certificate_files; i++) {
2751 free(o->certificate_files[i]);
2752 sshkey_free(o->certificates[i]);
2754 free(o->identity_agent);
2755 for (i = 0; i < o->num_local_forwards; i++) {
2756 free(o->local_forwards[i].listen_host);
2757 free(o->local_forwards[i].listen_path);
2758 free(o->local_forwards[i].connect_host);
2759 free(o->local_forwards[i].connect_path);
2761 free(o->local_forwards);
2762 for (i = 0; i < o->num_remote_forwards; i++) {
2763 free(o->remote_forwards[i].listen_host);
2764 free(o->remote_forwards[i].listen_path);
2765 free(o->remote_forwards[i].connect_host);
2766 free(o->remote_forwards[i].connect_path);
2768 free(o->remote_forwards);
2769 free(o->stdio_forward_host);
2770 FREE_ARRAY(u_int, o->num_send_env, o->send_env);
2771 free(o->send_env);
2772 FREE_ARRAY(u_int, o->num_setenv, o->setenv);
2773 free(o->setenv);
2774 free(o->control_path);
2775 free(o->local_command);
2776 free(o->remote_command);
2777 FREE_ARRAY(int, o->num_canonical_domains, o->canonical_domains);
2778 for (i = 0; i < o->num_permitted_cnames; i++) {
2779 free(o->permitted_cnames[i].source_list);
2780 free(o->permitted_cnames[i].target_list);
2782 free(o->revoked_host_keys);
2783 free(o->hostbased_accepted_algos);
2784 free(o->pubkey_accepted_algos);
2785 free(o->jump_user);
2786 free(o->jump_host);
2787 free(o->jump_extra);
2788 free(o->ignored_unknown);
2789 explicit_bzero(o, sizeof(*o));
2790 #undef FREE_ARRAY
2793 struct fwdarg {
2794 char *arg;
2795 int ispath;
2799 * parse_fwd_field
2800 * parses the next field in a port forwarding specification.
2801 * sets fwd to the parsed field and advances p past the colon
2802 * or sets it to NULL at end of string.
2803 * returns 0 on success, else non-zero.
2805 static int
2806 parse_fwd_field(char **p, struct fwdarg *fwd)
2808 char *ep, *cp = *p;
2809 int ispath = 0;
2811 if (*cp == '\0') {
2812 *p = NULL;
2813 return -1; /* end of string */
2817 * A field escaped with square brackets is used literally.
2818 * XXX - allow ']' to be escaped via backslash?
2820 if (*cp == '[') {
2821 /* find matching ']' */
2822 for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
2823 if (*ep == '/')
2824 ispath = 1;
2826 /* no matching ']' or not at end of field. */
2827 if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
2828 return -1;
2829 /* NUL terminate the field and advance p past the colon */
2830 *ep++ = '\0';
2831 if (*ep != '\0')
2832 *ep++ = '\0';
2833 fwd->arg = cp + 1;
2834 fwd->ispath = ispath;
2835 *p = ep;
2836 return 0;
2839 for (cp = *p; *cp != '\0'; cp++) {
2840 switch (*cp) {
2841 case '\\':
2842 memmove(cp, cp + 1, strlen(cp + 1) + 1);
2843 if (*cp == '\0')
2844 return -1;
2845 break;
2846 case '/':
2847 ispath = 1;
2848 break;
2849 case ':':
2850 *cp++ = '\0';
2851 goto done;
2854 done:
2855 fwd->arg = *p;
2856 fwd->ispath = ispath;
2857 *p = cp;
2858 return 0;
2862 * parse_forward
2863 * parses a string containing a port forwarding specification of the form:
2864 * dynamicfwd == 0
2865 * [listenhost:]listenport|listenpath:connecthost:connectport|connectpath
2866 * listenpath:connectpath
2867 * dynamicfwd == 1
2868 * [listenhost:]listenport
2869 * returns number of arguments parsed or zero on error
2872 parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
2874 struct fwdarg fwdargs[4];
2875 char *p, *cp;
2876 int i, err;
2878 memset(fwd, 0, sizeof(*fwd));
2879 memset(fwdargs, 0, sizeof(fwdargs));
2882 * We expand environment variables before checking if we think they're
2883 * paths so that if ${VAR} expands to a fully qualified path it is
2884 * treated as a path.
2886 cp = p = dollar_expand(&err, fwdspec);
2887 if (p == NULL || err)
2888 return 0;
2890 /* skip leading spaces */
2891 while (isspace((u_char)*cp))
2892 cp++;
2894 for (i = 0; i < 4; ++i) {
2895 if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
2896 break;
2899 /* Check for trailing garbage */
2900 if (cp != NULL && *cp != '\0') {
2901 i = 0; /* failure */
2904 switch (i) {
2905 case 1:
2906 if (fwdargs[0].ispath) {
2907 fwd->listen_path = xstrdup(fwdargs[0].arg);
2908 fwd->listen_port = PORT_STREAMLOCAL;
2909 } else {
2910 fwd->listen_host = NULL;
2911 fwd->listen_port = a2port(fwdargs[0].arg);
2913 fwd->connect_host = xstrdup("socks");
2914 break;
2916 case 2:
2917 if (fwdargs[0].ispath && fwdargs[1].ispath) {
2918 fwd->listen_path = xstrdup(fwdargs[0].arg);
2919 fwd->listen_port = PORT_STREAMLOCAL;
2920 fwd->connect_path = xstrdup(fwdargs[1].arg);
2921 fwd->connect_port = PORT_STREAMLOCAL;
2922 } else if (fwdargs[1].ispath) {
2923 fwd->listen_host = NULL;
2924 fwd->listen_port = a2port(fwdargs[0].arg);
2925 fwd->connect_path = xstrdup(fwdargs[1].arg);
2926 fwd->connect_port = PORT_STREAMLOCAL;
2927 } else {
2928 fwd->listen_host = xstrdup(fwdargs[0].arg);
2929 fwd->listen_port = a2port(fwdargs[1].arg);
2930 fwd->connect_host = xstrdup("socks");
2932 break;
2934 case 3:
2935 if (fwdargs[0].ispath) {
2936 fwd->listen_path = xstrdup(fwdargs[0].arg);
2937 fwd->listen_port = PORT_STREAMLOCAL;
2938 fwd->connect_host = xstrdup(fwdargs[1].arg);
2939 fwd->connect_port = a2port(fwdargs[2].arg);
2940 } else if (fwdargs[2].ispath) {
2941 fwd->listen_host = xstrdup(fwdargs[0].arg);
2942 fwd->listen_port = a2port(fwdargs[1].arg);
2943 fwd->connect_path = xstrdup(fwdargs[2].arg);
2944 fwd->connect_port = PORT_STREAMLOCAL;
2945 } else {
2946 fwd->listen_host = NULL;
2947 fwd->listen_port = a2port(fwdargs[0].arg);
2948 fwd->connect_host = xstrdup(fwdargs[1].arg);
2949 fwd->connect_port = a2port(fwdargs[2].arg);
2951 break;
2953 case 4:
2954 fwd->listen_host = xstrdup(fwdargs[0].arg);
2955 fwd->listen_port = a2port(fwdargs[1].arg);
2956 fwd->connect_host = xstrdup(fwdargs[2].arg);
2957 fwd->connect_port = a2port(fwdargs[3].arg);
2958 break;
2959 default:
2960 i = 0; /* failure */
2963 free(p);
2965 if (dynamicfwd) {
2966 if (!(i == 1 || i == 2))
2967 goto fail_free;
2968 } else {
2969 if (!(i == 3 || i == 4)) {
2970 if (fwd->connect_path == NULL &&
2971 fwd->listen_path == NULL)
2972 goto fail_free;
2974 if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
2975 goto fail_free;
2978 if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
2979 (!remotefwd && fwd->listen_port == 0))
2980 goto fail_free;
2981 if (fwd->connect_host != NULL &&
2982 strlen(fwd->connect_host) >= NI_MAXHOST)
2983 goto fail_free;
2985 * XXX - if connecting to a remote socket, max sun len may not
2986 * match this host
2988 if (fwd->connect_path != NULL &&
2989 strlen(fwd->connect_path) >= PATH_MAX_SUN)
2990 goto fail_free;
2991 if (fwd->listen_host != NULL &&
2992 strlen(fwd->listen_host) >= NI_MAXHOST)
2993 goto fail_free;
2994 if (fwd->listen_path != NULL &&
2995 strlen(fwd->listen_path) >= PATH_MAX_SUN)
2996 goto fail_free;
2998 return (i);
3000 fail_free:
3001 free(fwd->connect_host);
3002 fwd->connect_host = NULL;
3003 free(fwd->connect_path);
3004 fwd->connect_path = NULL;
3005 free(fwd->listen_host);
3006 fwd->listen_host = NULL;
3007 free(fwd->listen_path);
3008 fwd->listen_path = NULL;
3009 return (0);
3013 parse_jump(const char *s, Options *o, int active)
3015 char *orig, *sdup, *cp;
3016 char *host = NULL, *user = NULL;
3017 int r, ret = -1, port = -1, first;
3019 active &= o->proxy_command == NULL && o->jump_host == NULL;
3021 orig = sdup = xstrdup(s);
3023 /* Remove comment and trailing whitespace */
3024 if ((cp = strchr(orig, '#')) != NULL)
3025 *cp = '\0';
3026 rtrim(orig);
3028 first = active;
3029 do {
3030 if (strcasecmp(s, "none") == 0)
3031 break;
3032 if ((cp = strrchr(sdup, ',')) == NULL)
3033 cp = sdup; /* last */
3034 else
3035 *cp++ = '\0';
3037 if (first) {
3038 /* First argument and configuration is active */
3039 r = parse_ssh_uri(cp, &user, &host, &port);
3040 if (r == -1 || (r == 1 &&
3041 parse_user_host_port(cp, &user, &host, &port) != 0))
3042 goto out;
3043 } else {
3044 /* Subsequent argument or inactive configuration */
3045 r = parse_ssh_uri(cp, NULL, NULL, NULL);
3046 if (r == -1 || (r == 1 &&
3047 parse_user_host_port(cp, NULL, NULL, NULL) != 0))
3048 goto out;
3050 first = 0; /* only check syntax for subsequent hosts */
3051 } while (cp != sdup);
3052 /* success */
3053 if (active) {
3054 if (strcasecmp(s, "none") == 0) {
3055 o->jump_host = xstrdup("none");
3056 o->jump_port = 0;
3057 } else {
3058 o->jump_user = user;
3059 o->jump_host = host;
3060 o->jump_port = port;
3061 o->proxy_command = xstrdup("none");
3062 user = host = NULL;
3063 if ((cp = strrchr(s, ',')) != NULL && cp != s) {
3064 o->jump_extra = xstrdup(s);
3065 o->jump_extra[cp - s] = '\0';
3069 ret = 0;
3070 out:
3071 free(orig);
3072 free(user);
3073 free(host);
3074 return ret;
3078 parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp)
3080 char *user = NULL, *host = NULL, *path = NULL;
3081 int r, port;
3083 r = parse_uri("ssh", uri, &user, &host, &port, &path);
3084 if (r == 0 && path != NULL)
3085 r = -1; /* path not allowed */
3086 if (r == 0) {
3087 if (userp != NULL) {
3088 *userp = user;
3089 user = NULL;
3091 if (hostp != NULL) {
3092 *hostp = host;
3093 host = NULL;
3095 if (portp != NULL)
3096 *portp = port;
3098 free(user);
3099 free(host);
3100 free(path);
3101 return r;
3104 /* XXX the following is a near-vebatim copy from servconf.c; refactor */
3105 static const char *
3106 fmt_multistate_int(int val, const struct multistate *m)
3108 u_int i;
3110 for (i = 0; m[i].key != NULL; i++) {
3111 if (m[i].value == val)
3112 return m[i].key;
3114 return "UNKNOWN";
3117 static const char *
3118 fmt_intarg(OpCodes code, int val)
3120 if (val == -1)
3121 return "unset";
3122 switch (code) {
3123 case oAddressFamily:
3124 return fmt_multistate_int(val, multistate_addressfamily);
3125 case oVerifyHostKeyDNS:
3126 case oUpdateHostkeys:
3127 return fmt_multistate_int(val, multistate_yesnoask);
3128 case oStrictHostKeyChecking:
3129 return fmt_multistate_int(val, multistate_strict_hostkey);
3130 case oControlMaster:
3131 return fmt_multistate_int(val, multistate_controlmaster);
3132 case oTunnel:
3133 return fmt_multistate_int(val, multistate_tunnel);
3134 case oRequestTTY:
3135 return fmt_multistate_int(val, multistate_requesttty);
3136 case oSessionType:
3137 return fmt_multistate_int(val, multistate_sessiontype);
3138 case oCanonicalizeHostname:
3139 return fmt_multistate_int(val, multistate_canonicalizehostname);
3140 case oAddKeysToAgent:
3141 return fmt_multistate_int(val, multistate_yesnoaskconfirm);
3142 case oPubkeyAuthentication:
3143 return fmt_multistate_int(val, multistate_pubkey_auth);
3144 case oFingerprintHash:
3145 return ssh_digest_alg_name(val);
3146 default:
3147 switch (val) {
3148 case 0:
3149 return "no";
3150 case 1:
3151 return "yes";
3152 default:
3153 return "UNKNOWN";
3158 static const char *
3159 lookup_opcode_name(OpCodes code)
3161 u_int i;
3163 for (i = 0; keywords[i].name != NULL; i++)
3164 if (keywords[i].opcode == code)
3165 return(keywords[i].name);
3166 return "UNKNOWN";
3169 static void
3170 dump_cfg_int(OpCodes code, int val)
3172 printf("%s %d\n", lookup_opcode_name(code), val);
3175 static void
3176 dump_cfg_fmtint(OpCodes code, int val)
3178 printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
3181 static void
3182 dump_cfg_string(OpCodes code, const char *val)
3184 if (val == NULL)
3185 return;
3186 printf("%s %s\n", lookup_opcode_name(code), val);
3189 static void
3190 dump_cfg_strarray(OpCodes code, u_int count, char **vals)
3192 u_int i;
3194 for (i = 0; i < count; i++)
3195 printf("%s %s\n", lookup_opcode_name(code), vals[i]);
3198 static void
3199 dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
3201 u_int i;
3203 printf("%s", lookup_opcode_name(code));
3204 if (count == 0)
3205 printf(" none");
3206 for (i = 0; i < count; i++)
3207 printf(" %s", vals[i]);
3208 printf("\n");
3211 static void
3212 dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
3214 const struct Forward *fwd;
3215 u_int i;
3217 /* oDynamicForward */
3218 for (i = 0; i < count; i++) {
3219 fwd = &fwds[i];
3220 if (code == oDynamicForward && fwd->connect_host != NULL &&
3221 strcmp(fwd->connect_host, "socks") != 0)
3222 continue;
3223 if (code == oLocalForward && fwd->connect_host != NULL &&
3224 strcmp(fwd->connect_host, "socks") == 0)
3225 continue;
3226 printf("%s", lookup_opcode_name(code));
3227 if (fwd->listen_port == PORT_STREAMLOCAL)
3228 printf(" %s", fwd->listen_path);
3229 else if (fwd->listen_host == NULL)
3230 printf(" %d", fwd->listen_port);
3231 else {
3232 printf(" [%s]:%d",
3233 fwd->listen_host, fwd->listen_port);
3235 if (code != oDynamicForward) {
3236 if (fwd->connect_port == PORT_STREAMLOCAL)
3237 printf(" %s", fwd->connect_path);
3238 else if (fwd->connect_host == NULL)
3239 printf(" %d", fwd->connect_port);
3240 else {
3241 printf(" [%s]:%d",
3242 fwd->connect_host, fwd->connect_port);
3245 printf("\n");
3249 void
3250 dump_client_config(Options *o, const char *host)
3252 int i, r;
3253 char buf[8], *all_key;
3256 * Expand HostKeyAlgorithms name lists. This isn't handled in
3257 * fill_default_options() like the other algorithm lists because
3258 * the host key algorithms are by default dynamically chosen based
3259 * on the host's keys found in known_hosts.
3261 all_key = sshkey_alg_list(0, 0, 1, ',');
3262 if ((r = kex_assemble_names(&o->hostkeyalgorithms, kex_default_pk_alg(),
3263 all_key)) != 0)
3264 fatal_fr(r, "expand HostKeyAlgorithms");
3265 free(all_key);
3267 /* Most interesting options first: user, host, port */
3268 dump_cfg_string(oUser, o->user);
3269 dump_cfg_string(oHostname, host);
3270 dump_cfg_int(oPort, o->port);
3272 /* Flag options */
3273 dump_cfg_fmtint(oAddressFamily, o->address_family);
3274 dump_cfg_fmtint(oBatchMode, o->batch_mode);
3275 dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
3276 dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
3277 dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
3278 dump_cfg_fmtint(oCompression, o->compression);
3279 dump_cfg_fmtint(oControlMaster, o->control_master);
3280 dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
3281 dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
3282 dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
3283 dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
3284 dump_cfg_fmtint(oForwardX11, o->forward_x11);
3285 dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
3286 dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
3287 #ifdef GSSAPI
3288 dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
3289 dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
3290 #endif /* GSSAPI */
3291 dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
3292 dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
3293 dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
3294 dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
3295 dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
3296 dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
3297 dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
3298 dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
3299 dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
3300 dump_cfg_fmtint(oRequestTTY, o->request_tty);
3301 dump_cfg_fmtint(oSessionType, o->session_type);
3302 dump_cfg_fmtint(oStdinNull, o->stdin_null);
3303 dump_cfg_fmtint(oForkAfterAuthentication, o->fork_after_authentication);
3304 dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
3305 dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
3306 dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
3307 dump_cfg_fmtint(oTunnel, o->tun_open);
3308 dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
3309 dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
3310 dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
3312 /* Integer options */
3313 dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
3314 dump_cfg_int(oConnectionAttempts, o->connection_attempts);
3315 dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
3316 dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
3317 dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
3318 dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
3319 dump_cfg_int(oRequiredRSASize, o->required_rsa_size);
3321 /* String options */
3322 dump_cfg_string(oBindAddress, o->bind_address);
3323 dump_cfg_string(oBindInterface, o->bind_interface);
3324 dump_cfg_string(oCiphers, o->ciphers);
3325 dump_cfg_string(oControlPath, o->control_path);
3326 dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
3327 dump_cfg_string(oHostKeyAlias, o->host_key_alias);
3328 dump_cfg_string(oHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
3329 dump_cfg_string(oIdentityAgent, o->identity_agent);
3330 dump_cfg_string(oIgnoreUnknown, o->ignored_unknown);
3331 dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
3332 dump_cfg_string(oKexAlgorithms, o->kex_algorithms);
3333 dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms);
3334 dump_cfg_string(oLocalCommand, o->local_command);
3335 dump_cfg_string(oRemoteCommand, o->remote_command);
3336 dump_cfg_string(oLogLevel, log_level_name(o->log_level));
3337 dump_cfg_string(oMacs, o->macs);
3338 #ifdef ENABLE_PKCS11
3339 dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
3340 #endif
3341 dump_cfg_string(oSecurityKeyProvider, o->sk_provider);
3342 dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
3343 dump_cfg_string(oPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
3344 dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
3345 dump_cfg_string(oXAuthLocation, o->xauth_location);
3346 dump_cfg_string(oKnownHostsCommand, o->known_hosts_command);
3348 /* Forwards */
3349 dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
3350 dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
3351 dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
3353 /* String array options */
3354 dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
3355 dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
3356 dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files);
3357 dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
3358 dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
3359 dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
3360 dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv);
3361 dump_cfg_strarray_oneline(oLogVerbose,
3362 o->num_log_verbose, o->log_verbose);
3364 /* Special cases */
3366 /* PermitRemoteOpen */
3367 if (o->num_permitted_remote_opens == 0)
3368 printf("%s any\n", lookup_opcode_name(oPermitRemoteOpen));
3369 else
3370 dump_cfg_strarray_oneline(oPermitRemoteOpen,
3371 o->num_permitted_remote_opens, o->permitted_remote_opens);
3373 /* AddKeysToAgent */
3374 if (o->add_keys_to_agent_lifespan <= 0)
3375 dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent);
3376 else {
3377 printf("addkeystoagent%s %d\n",
3378 o->add_keys_to_agent == 3 ? " confirm" : "",
3379 o->add_keys_to_agent_lifespan);
3382 /* oForwardAgent */
3383 if (o->forward_agent_sock_path == NULL)
3384 dump_cfg_fmtint(oForwardAgent, o->forward_agent);
3385 else
3386 dump_cfg_string(oForwardAgent, o->forward_agent_sock_path);
3388 /* oConnectTimeout */
3389 if (o->connection_timeout == -1)
3390 printf("connecttimeout none\n");
3391 else
3392 dump_cfg_int(oConnectTimeout, o->connection_timeout);
3394 /* oTunnelDevice */
3395 printf("tunneldevice");
3396 if (o->tun_local == SSH_TUNID_ANY)
3397 printf(" any");
3398 else
3399 printf(" %d", o->tun_local);
3400 if (o->tun_remote == SSH_TUNID_ANY)
3401 printf(":any");
3402 else
3403 printf(":%d", o->tun_remote);
3404 printf("\n");
3406 /* oCanonicalizePermittedCNAMEs */
3407 printf("canonicalizePermittedcnames");
3408 if (o->num_permitted_cnames == 0)
3409 printf(" none");
3410 for (i = 0; i < o->num_permitted_cnames; i++) {
3411 printf(" %s:%s", o->permitted_cnames[i].source_list,
3412 o->permitted_cnames[i].target_list);
3414 printf("\n");
3416 /* oControlPersist */
3417 if (o->control_persist == 0 || o->control_persist_timeout == 0)
3418 dump_cfg_fmtint(oControlPersist, o->control_persist);
3419 else
3420 dump_cfg_int(oControlPersist, o->control_persist_timeout);
3422 /* oEscapeChar */
3423 if (o->escape_char == SSH_ESCAPECHAR_NONE)
3424 printf("escapechar none\n");
3425 else {
3426 vis(buf, o->escape_char, VIS_WHITE, 0);
3427 printf("escapechar %s\n", buf);
3430 /* oIPQoS */
3431 printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
3432 printf("%s\n", iptos2str(o->ip_qos_bulk));
3434 /* oRekeyLimit */
3435 printf("rekeylimit %llu %d\n",
3436 (unsigned long long)o->rekey_limit, o->rekey_interval);
3438 /* oStreamLocalBindMask */
3439 printf("streamlocalbindmask 0%o\n",
3440 o->fwd_opts.streamlocal_bind_mask);
3442 /* oLogFacility */
3443 printf("syslogfacility %s\n", log_facility_name(o->log_facility));
3445 /* oProxyCommand / oProxyJump */
3446 if (o->jump_host == NULL)
3447 dump_cfg_string(oProxyCommand, o->proxy_command);
3448 else {
3449 /* Check for numeric addresses */
3450 i = strchr(o->jump_host, ':') != NULL ||
3451 strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
3452 snprintf(buf, sizeof(buf), "%d", o->jump_port);
3453 printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
3454 /* optional additional jump spec */
3455 o->jump_extra == NULL ? "" : o->jump_extra,
3456 o->jump_extra == NULL ? "" : ",",
3457 /* optional user */
3458 o->jump_user == NULL ? "" : o->jump_user,
3459 o->jump_user == NULL ? "" : "@",
3460 /* opening [ if hostname is numeric */
3461 i ? "[" : "",
3462 /* mandatory hostname */
3463 o->jump_host,
3464 /* closing ] if hostname is numeric */
3465 i ? "]" : "",
3466 /* optional port number */
3467 o->jump_port <= 0 ? "" : ":",
3468 o->jump_port <= 0 ? "" : buf);