1 /* $OpenBSD: readconf.c,v 1.361 2021/07/23 04:04:52 djm Exp $ */
3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
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".
18 #include <sys/types.h>
20 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <netinet/in_systm.h>
26 #include <netinet/ip.h>
27 #include <arpa/inet.h>
43 #ifdef USE_SYSTEM_GLOB
46 # include "openbsd-compat/glob.h"
51 #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
60 #include "pathnames.h"
69 #include "myproposal.h"
73 /* Format of the configuration file:
75 # Configuration data is parsed as follows:
76 # 1. command line options
77 # 2. user-specific file
79 # Any configuration value is only changed the first time it is set.
80 # Thus, host-specific definitions should be at the beginning of the
81 # configuration file, and defaults at the end.
83 # Host-specific declarations. These may override anything above. A single
84 # host may match multiple declarations; these are processed in the order
85 # that they are given in.
91 Hostname another.host.name.real.org
98 RemoteForward 9999 shadows.cs.hut.fi:9999
101 Host fascist.blob.com
104 PasswordAuthentication no
108 ProxyCommand ssh-proxy %h %p
111 PublicKeyAuthentication no
115 PasswordAuthentication no
121 # Defaults for various options
125 PasswordAuthentication yes
126 StrictHostKeyChecking yes
128 IdentityFile ~/.ssh/identity
134 static int read_config_file_depth(const char *filename, struct passwd *pw,
135 const char *host, const char *original_host, Options *options,
136 int flags, int *activep, int *want_final_pass, int depth);
137 static int process_config_line_depth(Options *options, struct passwd *pw,
138 const char *host, const char *original_host, char *line,
139 const char *filename, int linenum, int *activep, int flags,
140 int *want_final_pass, int depth);
142 /* Keyword tokens. */
147 oHost, oMatch, oInclude,
148 oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
149 oGatewayPorts, oExitOnForwardFailure,
150 oPasswordAuthentication,
152 oIdentityFile, oHostname, oPort, oRemoteForward, oLocalForward,
154 oCertificateFile, oAddKeysToAgent, oIdentityAgent,
155 oUser, oEscapeChar, oProxyCommand,
156 oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
157 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
158 oTCPKeepAlive, oNumberOfPasswordPrompts,
159 oLogFacility, oLogLevel, oLogVerbose, oCiphers, oMacs,
160 oPubkeyAuthentication,
161 oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
162 oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
163 oHostKeyAlgorithms, oBindAddress, oBindInterface, oPKCS11Provider,
164 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
165 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
166 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
167 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
168 oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist,
170 oTunnel, oTunnelDevice,
171 oLocalCommand, oPermitLocalCommand, oRemoteCommand,
173 oKexAlgorithms, oIPQoS, oRequestTTY, oSessionType, oStdinNull,
174 oForkAfterAuthentication, oIgnoreUnknown, oProxyUseFdpass,
175 oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
176 oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
177 oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
178 oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
179 oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
180 oSecurityKeyProvider, oKnownHostsCommand,
181 oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
184 /* Textual representations of the tokens. */
190 /* Deprecated options */
191 { "protocol", oIgnore }, /* NB. silently ignored */
192 { "cipher", oDeprecated },
193 { "fallbacktorsh", oDeprecated },
194 { "globalknownhostsfile2", oDeprecated },
195 { "rhostsauthentication", oDeprecated },
196 { "userknownhostsfile2", oDeprecated },
197 { "useroaming", oDeprecated },
198 { "usersh", oDeprecated },
199 { "useprivilegedport", oDeprecated },
201 /* Unsupported options */
202 { "afstokenpassing", oUnsupported },
203 { "kerberosauthentication", oUnsupported },
204 { "kerberostgtpassing", oUnsupported },
205 { "rsaauthentication", oUnsupported },
206 { "rhostsrsaauthentication", oUnsupported },
207 { "compressionlevel", oUnsupported },
209 /* Sometimes-unsupported options */
211 { "gssapiauthentication", oGssAuthentication },
212 { "gssapidelegatecredentials", oGssDelegateCreds },
214 { "gssapiauthentication", oUnsupported },
215 { "gssapidelegatecredentials", oUnsupported },
218 { "pkcs11provider", oPKCS11Provider },
219 { "smartcarddevice", oPKCS11Provider },
221 { "smartcarddevice", oUnsupported },
222 { "pkcs11provider", oUnsupported },
225 { "forwardagent", oForwardAgent },
226 { "forwardx11", oForwardX11 },
227 { "forwardx11trusted", oForwardX11Trusted },
228 { "forwardx11timeout", oForwardX11Timeout },
229 { "exitonforwardfailure", oExitOnForwardFailure },
230 { "xauthlocation", oXAuthLocation },
231 { "gatewayports", oGatewayPorts },
232 { "passwordauthentication", oPasswordAuthentication },
233 { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
234 { "kbdinteractivedevices", oKbdInteractiveDevices },
235 { "challengeresponseauthentication", oKbdInteractiveAuthentication }, /* alias */
236 { "skeyauthentication", oKbdInteractiveAuthentication }, /* alias */
237 { "tisauthentication", oKbdInteractiveAuthentication }, /* alias */
238 { "pubkeyauthentication", oPubkeyAuthentication },
239 { "dsaauthentication", oPubkeyAuthentication }, /* alias */
240 { "hostbasedauthentication", oHostbasedAuthentication },
241 { "identityfile", oIdentityFile },
242 { "identityfile2", oIdentityFile }, /* obsolete */
243 { "identitiesonly", oIdentitiesOnly },
244 { "certificatefile", oCertificateFile },
245 { "addkeystoagent", oAddKeysToAgent },
246 { "identityagent", oIdentityAgent },
247 { "hostname", oHostname },
248 { "hostkeyalias", oHostKeyAlias },
249 { "proxycommand", oProxyCommand },
251 { "ciphers", oCiphers },
253 { "remoteforward", oRemoteForward },
254 { "localforward", oLocalForward },
255 { "permitremoteopen", oPermitRemoteOpen },
259 { "escapechar", oEscapeChar },
260 { "globalknownhostsfile", oGlobalKnownHostsFile },
261 { "userknownhostsfile", oUserKnownHostsFile },
262 { "connectionattempts", oConnectionAttempts },
263 { "batchmode", oBatchMode },
264 { "checkhostip", oCheckHostIP },
265 { "stricthostkeychecking", oStrictHostKeyChecking },
266 { "compression", oCompression },
267 { "tcpkeepalive", oTCPKeepAlive },
268 { "keepalive", oTCPKeepAlive }, /* obsolete */
269 { "numberofpasswordprompts", oNumberOfPasswordPrompts },
270 { "syslogfacility", oLogFacility },
271 { "loglevel", oLogLevel },
272 { "logverbose", oLogVerbose },
273 { "dynamicforward", oDynamicForward },
274 { "preferredauthentications", oPreferredAuthentications },
275 { "hostkeyalgorithms", oHostKeyAlgorithms },
276 { "casignaturealgorithms", oCASignatureAlgorithms },
277 { "bindaddress", oBindAddress },
278 { "bindinterface", oBindInterface },
279 { "clearallforwardings", oClearAllForwardings },
280 { "enablesshkeysign", oEnableSSHKeysign },
281 { "verifyhostkeydns", oVerifyHostKeyDNS },
282 { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
283 { "rekeylimit", oRekeyLimit },
284 { "connecttimeout", oConnectTimeout },
285 { "addressfamily", oAddressFamily },
286 { "serveraliveinterval", oServerAliveInterval },
287 { "serveralivecountmax", oServerAliveCountMax },
288 { "sendenv", oSendEnv },
289 { "setenv", oSetEnv },
290 { "controlpath", oControlPath },
291 { "controlmaster", oControlMaster },
292 { "controlpersist", oControlPersist },
293 { "hashknownhosts", oHashKnownHosts },
294 { "include", oInclude },
295 { "tunnel", oTunnel },
296 { "tunneldevice", oTunnelDevice },
297 { "localcommand", oLocalCommand },
298 { "permitlocalcommand", oPermitLocalCommand },
299 { "remotecommand", oRemoteCommand },
300 { "visualhostkey", oVisualHostKey },
301 { "kexalgorithms", oKexAlgorithms },
303 { "requesttty", oRequestTTY },
304 { "sessiontype", oSessionType },
305 { "stdinnull", oStdinNull },
306 { "forkafterauthentication", oForkAfterAuthentication },
307 { "proxyusefdpass", oProxyUseFdpass },
308 { "canonicaldomains", oCanonicalDomains },
309 { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
310 { "canonicalizehostname", oCanonicalizeHostname },
311 { "canonicalizemaxdots", oCanonicalizeMaxDots },
312 { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
313 { "streamlocalbindmask", oStreamLocalBindMask },
314 { "streamlocalbindunlink", oStreamLocalBindUnlink },
315 { "revokedhostkeys", oRevokedHostKeys },
316 { "fingerprinthash", oFingerprintHash },
317 { "updatehostkeys", oUpdateHostkeys },
318 { "hostbasedacceptedalgorithms", oHostbasedAcceptedAlgorithms },
319 { "hostbasedkeytypes", oHostbasedAcceptedAlgorithms }, /* obsolete */
320 { "pubkeyacceptedalgorithms", oPubkeyAcceptedAlgorithms },
321 { "pubkeyacceptedkeytypes", oPubkeyAcceptedAlgorithms }, /* obsolete */
322 { "ignoreunknown", oIgnoreUnknown },
323 { "proxyjump", oProxyJump },
324 { "securitykeyprovider", oSecurityKeyProvider },
325 { "knownhostscommand", oKnownHostsCommand },
327 { "hpndisabled", oDeprecated },
328 { "hpnbuffersize", oDeprecated },
329 { "tcprcvbufpoll", oDeprecated },
330 { "tcprcvbuf", oDeprecated },
331 { "noneenabled", oUnsupported },
332 { "noneswitch", oUnsupported },
333 { "versionaddendum", oVersionAddendum },
338 static const char *lookup_opcode_name(OpCodes code);
341 kex_default_pk_alg(void)
345 if (pkalgs == NULL) {
348 all_key = sshkey_alg_list(0, 0, 1, ',');
349 pkalgs = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
356 ssh_connection_hash(const char *thishost, const char *host, const char *portstr,
359 struct ssh_digest_ctx *md;
360 u_char conn_hash[SSH_DIGEST_MAX_LENGTH];
362 if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL ||
363 ssh_digest_update(md, thishost, strlen(thishost)) < 0 ||
364 ssh_digest_update(md, host, strlen(host)) < 0 ||
365 ssh_digest_update(md, portstr, strlen(portstr)) < 0 ||
366 ssh_digest_update(md, user, strlen(user)) < 0 ||
367 ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0)
368 fatal_f("mux digest failed");
370 return tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1));
374 * Adds a local TCP/IP port forward to options. Never returns if there is an
379 add_local_forward(Options *options, const struct Forward *newfwd)
384 /* Don't add duplicates */
385 for (i = 0; i < options->num_local_forwards; i++) {
386 if (forward_equals(newfwd, options->local_forwards + i))
389 options->local_forwards = xreallocarray(options->local_forwards,
390 options->num_local_forwards + 1,
391 sizeof(*options->local_forwards));
392 fwd = &options->local_forwards[options->num_local_forwards++];
394 fwd->listen_host = newfwd->listen_host;
395 fwd->listen_port = newfwd->listen_port;
396 fwd->listen_path = newfwd->listen_path;
397 fwd->connect_host = newfwd->connect_host;
398 fwd->connect_port = newfwd->connect_port;
399 fwd->connect_path = newfwd->connect_path;
403 * Adds a remote TCP/IP port forward to options. Never returns if there is
408 add_remote_forward(Options *options, const struct Forward *newfwd)
413 /* Don't add duplicates */
414 for (i = 0; i < options->num_remote_forwards; i++) {
415 if (forward_equals(newfwd, options->remote_forwards + i))
418 options->remote_forwards = xreallocarray(options->remote_forwards,
419 options->num_remote_forwards + 1,
420 sizeof(*options->remote_forwards));
421 fwd = &options->remote_forwards[options->num_remote_forwards++];
423 fwd->listen_host = newfwd->listen_host;
424 fwd->listen_port = newfwd->listen_port;
425 fwd->listen_path = newfwd->listen_path;
426 fwd->connect_host = newfwd->connect_host;
427 fwd->connect_port = newfwd->connect_port;
428 fwd->connect_path = newfwd->connect_path;
429 fwd->handle = newfwd->handle;
430 fwd->allocated_port = 0;
434 clear_forwardings(Options *options)
438 for (i = 0; i < options->num_local_forwards; i++) {
439 free(options->local_forwards[i].listen_host);
440 free(options->local_forwards[i].listen_path);
441 free(options->local_forwards[i].connect_host);
442 free(options->local_forwards[i].connect_path);
444 if (options->num_local_forwards > 0) {
445 free(options->local_forwards);
446 options->local_forwards = NULL;
448 options->num_local_forwards = 0;
449 for (i = 0; i < options->num_remote_forwards; i++) {
450 free(options->remote_forwards[i].listen_host);
451 free(options->remote_forwards[i].listen_path);
452 free(options->remote_forwards[i].connect_host);
453 free(options->remote_forwards[i].connect_path);
455 if (options->num_remote_forwards > 0) {
456 free(options->remote_forwards);
457 options->remote_forwards = NULL;
459 options->num_remote_forwards = 0;
460 options->tun_open = SSH_TUNMODE_NO;
464 add_certificate_file(Options *options, const char *path, int userprovided)
468 if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
469 fatal("Too many certificate files specified (max %d)",
470 SSH_MAX_CERTIFICATE_FILES);
472 /* Avoid registering duplicates */
473 for (i = 0; i < options->num_certificate_files; i++) {
474 if (options->certificate_file_userprovided[i] == userprovided &&
475 strcmp(options->certificate_files[i], path) == 0) {
476 debug2_f("ignoring duplicate key %s", path);
481 options->certificate_file_userprovided[options->num_certificate_files] =
483 options->certificate_files[options->num_certificate_files++] =
488 add_identity_file(Options *options, const char *dir, const char *filename,
494 if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
495 fatal("Too many identity files specified (max %d)",
496 SSH_MAX_IDENTITY_FILES);
498 if (dir == NULL) /* no dir, filename is absolute */
499 path = xstrdup(filename);
500 else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX)
501 fatal("Identity file path %s too long", path);
503 /* Avoid registering duplicates */
504 for (i = 0; i < options->num_identity_files; i++) {
505 if (options->identity_file_userprovided[i] == userprovided &&
506 strcmp(options->identity_files[i], path) == 0) {
507 debug2_f("ignoring duplicate key %s", path);
513 options->identity_file_userprovided[options->num_identity_files] =
515 options->identity_files[options->num_identity_files++] = path;
519 default_ssh_port(void)
525 sp = getservbyname(SSH_SERVICE_NAME, "tcp");
526 port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
532 * Execute a command in a shell.
533 * Return its exit status or -1 on abnormal exit.
536 execute_in_shell(const char *cmd)
542 if ((shell = getenv("SHELL")) == NULL)
543 shell = _PATH_BSHELL;
545 if (access(shell, X_OK) == -1) {
546 fatal("Shell \"%s\" is not executable: %s",
547 shell, strerror(errno));
550 debug("Executing command: '%.500s'", cmd);
552 /* Fork and execute the command. */
553 if ((pid = fork()) == 0) {
556 if (stdfd_devnull(1, 1, 0) == -1)
557 fatal_f("stdfd_devnull failed");
558 closefrom(STDERR_FILENO + 1);
562 argv[2] = xstrdup(cmd);
565 execv(argv[0], argv);
566 error("Unable to execute '%.100s': %s", cmd, strerror(errno));
567 /* Die with signal to make this error apparent to parent. */
568 ssh_signal(SIGTERM, SIG_DFL);
569 kill(getpid(), SIGTERM);
574 fatal_f("fork: %.100s", strerror(errno));
576 while (waitpid(pid, &status, 0) == -1) {
577 if (errno != EINTR && errno != EAGAIN)
578 fatal_f("waitpid: %s", strerror(errno));
580 if (!WIFEXITED(status)) {
581 error("command '%.100s' exited abnormally", cmd);
584 debug3("command returned status %d", WEXITSTATUS(status));
585 return WEXITSTATUS(status);
589 * Parse and execute a Match directive.
592 match_cfg_line(Options *options, char **condition, struct passwd *pw,
593 const char *host_arg, const char *original_host, int final_pass,
594 int *want_final_pass, const char *filename, int linenum)
596 char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
598 int r, port, this_result, result = 1, attributes = 0, negate;
599 char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
603 * Configuration is likely to be incomplete at this point so we
604 * must be prepared to use default values.
606 port = options->port <= 0 ? default_ssh_port() : options->port;
607 ruser = options->user == NULL ? pw->pw_name : options->user;
609 host = xstrdup(options->hostname);
610 } else if (options->hostname != NULL) {
611 /* NB. Please keep in sync with ssh.c:main() */
612 host = percent_expand(options->hostname,
613 "h", host_arg, (char *)NULL);
615 host = xstrdup(host_arg);
618 debug2("checking match for '%s' host %s originally %s",
619 cp, host, original_host);
620 while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
621 /* Terminate on comment */
622 if (*attrib == '#') {
623 cp = NULL; /* mark all arguments consumed */
626 arg = criteria = NULL;
628 if ((negate = attrib[0] == '!'))
630 /* Criterion "all" has no argument and must appear alone */
631 if (strcasecmp(attrib, "all") == 0) {
632 if (attributes > 1 || ((arg = strdelim(&cp)) != NULL &&
633 *arg != '\0' && *arg != '#')) {
634 error("%.200s line %d: '%s' cannot be combined "
635 "with other Match attributes",
636 filename, linenum, oattrib);
640 if (arg != NULL && *arg == '#')
641 cp = NULL; /* mark all arguments consumed */
643 result = negate ? 0 : 1;
647 /* criteria "final" and "canonical" have no argument */
648 if (strcasecmp(attrib, "canonical") == 0 ||
649 strcasecmp(attrib, "final") == 0) {
651 * If the config requests "Match final" then remember
652 * this so we can perform a second pass later.
654 if (strcasecmp(attrib, "final") == 0 &&
655 want_final_pass != NULL)
656 *want_final_pass = 1;
657 r = !!final_pass; /* force bitmask member to boolean */
658 if (r == (negate ? 1 : 0))
659 this_result = result = 0;
660 debug3("%.200s line %d: %smatched '%s'",
662 this_result ? "" : "not ", oattrib);
665 /* All other criteria require an argument */
666 if ((arg = strdelim(&cp)) == NULL ||
667 *arg == '\0' || *arg == '#') {
668 error("Missing Match criteria for %s", attrib);
672 if (strcasecmp(attrib, "host") == 0) {
673 criteria = xstrdup(host);
674 r = match_hostname(host, arg) == 1;
675 if (r == (negate ? 1 : 0))
676 this_result = result = 0;
677 } else if (strcasecmp(attrib, "originalhost") == 0) {
678 criteria = xstrdup(original_host);
679 r = match_hostname(original_host, arg) == 1;
680 if (r == (negate ? 1 : 0))
681 this_result = result = 0;
682 } else if (strcasecmp(attrib, "user") == 0) {
683 criteria = xstrdup(ruser);
684 r = match_pattern_list(ruser, arg, 0) == 1;
685 if (r == (negate ? 1 : 0))
686 this_result = result = 0;
687 } else if (strcasecmp(attrib, "localuser") == 0) {
688 criteria = xstrdup(pw->pw_name);
689 r = match_pattern_list(pw->pw_name, arg, 0) == 1;
690 if (r == (negate ? 1 : 0))
691 this_result = result = 0;
692 } else if (strcasecmp(attrib, "exec") == 0) {
693 char *conn_hash_hex, *keyalias;
695 if (gethostname(thishost, sizeof(thishost)) == -1)
696 fatal("gethostname: %s", strerror(errno));
697 strlcpy(shorthost, thishost, sizeof(shorthost));
698 shorthost[strcspn(thishost, ".")] = '\0';
699 snprintf(portstr, sizeof(portstr), "%d", port);
700 snprintf(uidstr, sizeof(uidstr), "%llu",
701 (unsigned long long)pw->pw_uid);
702 conn_hash_hex = ssh_connection_hash(thishost, host,
704 keyalias = options->host_key_alias ?
705 options->host_key_alias : host;
707 cmd = percent_expand(arg,
722 /* skip execution if prior predicate failed */
723 debug3("%.200s line %d: skipped exec "
724 "\"%.100s\"", filename, linenum, cmd);
728 r = execute_in_shell(cmd);
730 fatal("%.200s line %d: match exec "
731 "'%.100s' error", filename,
734 criteria = xstrdup(cmd);
736 /* Force exit status to boolean */
738 if (r == (negate ? 1 : 0))
739 this_result = result = 0;
741 error("Unsupported Match attribute %s", attrib);
745 debug3("%.200s line %d: %smatched '%s \"%.100s\"' ",
746 filename, linenum, this_result ? "": "not ",
750 if (attributes == 0) {
751 error("One or more attributes required for Match");
757 debug2("match %sfound", result ? "" : "not ");
763 /* Remove environment variable by pattern */
765 rm_env(Options *options, const char *arg, const char *filename, int linenum)
767 int i, j, onum_send_env = options->num_send_env;
770 /* Remove an environment variable */
771 for (i = 0; i < options->num_send_env; ) {
772 cp = xstrdup(options->send_env[i]);
773 if (!match_pattern(cp, arg + 1)) {
778 debug3("%s line %d: removing environment %s",
779 filename, linenum, cp);
781 free(options->send_env[i]);
782 options->send_env[i] = NULL;
783 for (j = i; j < options->num_send_env - 1; j++) {
784 options->send_env[j] = options->send_env[j + 1];
785 options->send_env[j + 1] = NULL;
787 options->num_send_env--;
788 /* NB. don't increment i */
790 if (onum_send_env != options->num_send_env) {
791 options->send_env = xrecallocarray(options->send_env,
792 onum_send_env, options->num_send_env,
793 sizeof(*options->send_env));
798 * Returns the number of the token pointed to by cp or oBadOption.
801 parse_token(const char *cp, const char *filename, int linenum,
802 const char *ignored_unknown)
806 for (i = 0; keywords[i].name; i++)
807 if (strcmp(cp, keywords[i].name) == 0)
808 return keywords[i].opcode;
809 if (ignored_unknown != NULL &&
810 match_pattern_list(cp, ignored_unknown, 1) == 1)
811 return oIgnoredUnknownOption;
812 error("%s: line %d: Bad configuration option: %s",
813 filename, linenum, cp);
817 /* Multistate option parsing */
822 static const struct multistate multistate_flag[] = {
829 static const struct multistate multistate_yesnoask[] = {
837 static const struct multistate multistate_strict_hostkey[] = {
838 { "true", SSH_STRICT_HOSTKEY_YES },
839 { "false", SSH_STRICT_HOSTKEY_OFF },
840 { "yes", SSH_STRICT_HOSTKEY_YES },
841 { "no", SSH_STRICT_HOSTKEY_OFF },
842 { "ask", SSH_STRICT_HOSTKEY_ASK },
843 { "off", SSH_STRICT_HOSTKEY_OFF },
844 { "accept-new", SSH_STRICT_HOSTKEY_NEW },
847 static const struct multistate multistate_yesnoaskconfirm[] = {
856 static const struct multistate multistate_addressfamily[] = {
858 { "inet6", AF_INET6 },
859 { "any", AF_UNSPEC },
862 static const struct multistate multistate_controlmaster[] = {
863 { "true", SSHCTL_MASTER_YES },
864 { "yes", SSHCTL_MASTER_YES },
865 { "false", SSHCTL_MASTER_NO },
866 { "no", SSHCTL_MASTER_NO },
867 { "auto", SSHCTL_MASTER_AUTO },
868 { "ask", SSHCTL_MASTER_ASK },
869 { "autoask", SSHCTL_MASTER_AUTO_ASK },
872 static const struct multistate multistate_tunnel[] = {
873 { "ethernet", SSH_TUNMODE_ETHERNET },
874 { "point-to-point", SSH_TUNMODE_POINTOPOINT },
875 { "true", SSH_TUNMODE_DEFAULT },
876 { "yes", SSH_TUNMODE_DEFAULT },
877 { "false", SSH_TUNMODE_NO },
878 { "no", SSH_TUNMODE_NO },
881 static const struct multistate multistate_requesttty[] = {
882 { "true", REQUEST_TTY_YES },
883 { "yes", REQUEST_TTY_YES },
884 { "false", REQUEST_TTY_NO },
885 { "no", REQUEST_TTY_NO },
886 { "force", REQUEST_TTY_FORCE },
887 { "auto", REQUEST_TTY_AUTO },
890 static const struct multistate multistate_sessiontype[] = {
891 { "none", SESSION_TYPE_NONE },
892 { "subsystem", SESSION_TYPE_SUBSYSTEM },
893 { "default", SESSION_TYPE_DEFAULT },
896 static const struct multistate multistate_canonicalizehostname[] = {
897 { "true", SSH_CANONICALISE_YES },
898 { "false", SSH_CANONICALISE_NO },
899 { "yes", SSH_CANONICALISE_YES },
900 { "no", SSH_CANONICALISE_NO },
901 { "always", SSH_CANONICALISE_ALWAYS },
904 static const struct multistate multistate_compression[] = {
906 { "yes", COMP_ZLIB },
913 parse_multistate_value(const char *arg, const char *filename, int linenum,
914 const struct multistate *multistate_ptr)
918 if (!arg || *arg == '\0') {
919 error("%s line %d: missing argument.", filename, linenum);
922 for (i = 0; multistate_ptr[i].key != NULL; i++) {
923 if (strcasecmp(arg, multistate_ptr[i].key) == 0)
924 return multistate_ptr[i].value;
930 * Processes a single option line as used in the configuration files. This
931 * only sets those values that have not already been set.
934 process_config_line(Options *options, struct passwd *pw, const char *host,
935 const char *original_host, char *line, const char *filename,
936 int linenum, int *activep, int flags)
938 return process_config_line_depth(options, pw, host, original_host,
939 line, filename, linenum, activep, flags, NULL, 0);
942 #define WHITESPACE " \t\r\n"
944 process_config_line_depth(Options *options, struct passwd *pw, const char *host,
945 const char *original_host, char *line, const char *filename,
946 int linenum, int *activep, int flags, int *want_final_pass, int depth)
948 char *str, **charptr, *endofnumber, *keyword, *arg, *arg2, *p, ch;
949 char **cpptr, ***cppptr, fwdarg[256];
950 u_int i, *uintptr, uvalue, max_entries = 0;
951 int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
952 int remotefwd, dynamicfwd;
953 LogLevel *log_level_ptr;
954 SyslogFacility *log_facility_ptr;
958 const struct multistate *multistate_ptr;
959 struct allowed_cname *cname;
962 char **oav = NULL, **av;
966 if (activep == NULL) { /* We are processing a command line directive */
971 /* Strip trailing whitespace. Allow \f (form feed) at EOL only */
972 if ((len = strlen(line)) == 0)
974 for (len--; len > 0; len--) {
975 if (strchr(WHITESPACE "\f", line[len]) == NULL)
981 /* Get the keyword. (Each line is supposed to begin with a keyword). */
982 if ((keyword = strdelim(&str)) == NULL)
984 /* Ignore leading whitespace. */
985 if (*keyword == '\0')
986 keyword = strdelim(&str);
987 if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
989 /* Match lowercase keyword */
992 /* Prepare to parse remainder of line */
994 str += strspn(str, WHITESPACE);
995 if (str == NULL || *str == '\0') {
996 error("%s line %d: no argument after keyword \"%s\"",
997 filename, linenum, keyword);
1000 opcode = parse_token(keyword, filename, linenum,
1001 options->ignored_unknown);
1002 if (argv_split(str, &oac, &oav, 1) != 0) {
1003 error("%s line %d: invalid quotes", filename, linenum);
1011 /* don't panic, but count bad options */
1016 case oIgnoredUnknownOption:
1017 debug("%s line %d: Ignored unknown option \"%s\"",
1018 filename, linenum, keyword);
1021 case oConnectTimeout:
1022 intptr = &options->connection_timeout;
1024 arg = argv_next(&ac, &av);
1025 if (!arg || *arg == '\0') {
1026 error("%s line %d: missing time value.",
1030 if (strcmp(arg, "none") == 0)
1032 else if ((value = convtime(arg)) == -1) {
1033 error("%s line %d: invalid time value.",
1037 if (*activep && *intptr == -1)
1042 intptr = &options->forward_agent;
1044 arg = argv_next(&ac, &av);
1045 if (!arg || *arg == '\0') {
1046 error("%s line %d: missing argument.",
1052 multistate_ptr = multistate_flag;
1053 for (i = 0; multistate_ptr[i].key != NULL; i++) {
1054 if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
1055 value = multistate_ptr[i].value;
1060 if (*activep && *intptr == -1)
1064 /* ForwardAgent wasn't 'yes' or 'no', assume a path */
1065 if (*activep && *intptr == -1)
1068 charptr = &options->forward_agent_sock_path;
1069 goto parse_agent_path;
1072 intptr = &options->forward_x11;
1074 multistate_ptr = multistate_flag;
1076 arg = argv_next(&ac, &av);
1077 if ((value = parse_multistate_value(arg, filename, linenum,
1078 multistate_ptr)) == -1) {
1079 error("%s line %d: unsupported option \"%s\".",
1080 filename, linenum, arg);
1083 if (*activep && *intptr == -1)
1087 case oForwardX11Trusted:
1088 intptr = &options->forward_x11_trusted;
1091 case oForwardX11Timeout:
1092 intptr = &options->forward_x11_timeout;
1096 intptr = &options->fwd_opts.gateway_ports;
1099 case oExitOnForwardFailure:
1100 intptr = &options->exit_on_forward_failure;
1103 case oPasswordAuthentication:
1104 intptr = &options->password_authentication;
1107 case oKbdInteractiveAuthentication:
1108 intptr = &options->kbd_interactive_authentication;
1111 case oKbdInteractiveDevices:
1112 charptr = &options->kbd_interactive_devices;
1115 case oPubkeyAuthentication:
1116 intptr = &options->pubkey_authentication;
1119 case oHostbasedAuthentication:
1120 intptr = &options->hostbased_authentication;
1123 case oGssAuthentication:
1124 intptr = &options->gss_authentication;
1127 case oGssDelegateCreds:
1128 intptr = &options->gss_deleg_creds;
1132 intptr = &options->batch_mode;
1136 intptr = &options->check_host_ip;
1139 case oVerifyHostKeyDNS:
1140 intptr = &options->verify_host_key_dns;
1141 multistate_ptr = multistate_yesnoask;
1142 goto parse_multistate;
1144 case oStrictHostKeyChecking:
1145 intptr = &options->strict_host_key_checking;
1146 multistate_ptr = multistate_strict_hostkey;
1147 goto parse_multistate;
1150 intptr = &options->compression;
1151 multistate_ptr = multistate_compression;
1152 goto parse_multistate;
1155 intptr = &options->tcp_keep_alive;
1158 case oNoHostAuthenticationForLocalhost:
1159 intptr = &options->no_host_authentication_for_localhost;
1162 case oNumberOfPasswordPrompts:
1163 intptr = &options->number_of_password_prompts;
1167 arg = argv_next(&ac, &av);
1168 if (!arg || *arg == '\0') {
1169 error("%.200s line %d: Missing argument.", filename,
1173 if (strcmp(arg, "default") == 0) {
1176 if (scan_scaled(arg, &val64) == -1) {
1177 error("%.200s line %d: Bad number '%s': %s",
1178 filename, linenum, arg, strerror(errno));
1181 if (val64 != 0 && val64 < 16) {
1182 error("%.200s line %d: RekeyLimit too small",
1187 if (*activep && options->rekey_limit == -1)
1188 options->rekey_limit = val64;
1189 if (ac != 0) { /* optional rekey interval present */
1190 if (strcmp(av[0], "none") == 0) {
1191 (void)argv_next(&ac, &av); /* discard */
1194 intptr = &options->rekey_interval;
1200 arg = argv_next(&ac, &av);
1201 if (!arg || *arg == '\0') {
1202 error("%.200s line %d: Missing argument.",
1207 intptr = &options->num_identity_files;
1208 if (*intptr >= SSH_MAX_IDENTITY_FILES) {
1209 error("%.200s line %d: Too many identity files "
1210 "specified (max %d).", filename, linenum,
1211 SSH_MAX_IDENTITY_FILES);
1214 add_identity_file(options, NULL,
1215 arg, flags & SSHCONF_USERCONF);
1219 case oCertificateFile:
1220 arg = argv_next(&ac, &av);
1221 if (!arg || *arg == '\0') {
1222 error("%.200s line %d: Missing argument.",
1227 intptr = &options->num_certificate_files;
1228 if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
1229 error("%.200s line %d: Too many certificate "
1230 "files specified (max %d).",
1232 SSH_MAX_CERTIFICATE_FILES);
1235 add_certificate_file(options, arg,
1236 flags & SSHCONF_USERCONF);
1240 case oXAuthLocation:
1241 charptr=&options->xauth_location;
1245 charptr = &options->user;
1247 arg = argv_next(&ac, &av);
1248 if (!arg || *arg == '\0') {
1249 error("%.200s line %d: Missing argument.",
1253 if (*activep && *charptr == NULL)
1254 *charptr = xstrdup(arg);
1257 case oGlobalKnownHostsFile:
1258 cpptr = (char **)&options->system_hostfiles;
1259 uintptr = &options->num_system_hostfiles;
1260 max_entries = SSH_MAX_HOSTS_FILES;
1263 value = *uintptr == 0; /* was array empty when we started? */
1264 while ((arg = argv_next(&ac, &av)) != NULL) {
1266 error("%s line %d: keyword %s empty argument",
1267 filename, linenum, keyword);
1270 /* Allow "none" only in first position */
1271 if (strcasecmp(arg, "none") == 0) {
1272 if (i > 0 || ac > 0) {
1273 error("%s line %d: keyword %s \"none\" "
1274 "argument must appear alone.",
1275 filename, linenum, keyword);
1280 if (*activep && value) {
1281 if ((*uintptr) >= max_entries) {
1282 error("%s line %d: too many %s "
1283 "entries.", filename, linenum,
1287 cpptr[(*uintptr)++] = xstrdup(arg);
1292 case oUserKnownHostsFile:
1293 cpptr = (char **)&options->user_hostfiles;
1294 uintptr = &options->num_user_hostfiles;
1295 max_entries = SSH_MAX_HOSTS_FILES;
1296 goto parse_char_array;
1299 charptr = &options->hostname;
1303 charptr = &options->host_key_alias;
1306 case oPreferredAuthentications:
1307 charptr = &options->preferred_authentications;
1311 charptr = &options->bind_address;
1314 case oBindInterface:
1315 charptr = &options->bind_interface;
1318 case oPKCS11Provider:
1319 charptr = &options->pkcs11_provider;
1322 case oSecurityKeyProvider:
1323 charptr = &options->sk_provider;
1326 case oKnownHostsCommand:
1327 charptr = &options->known_hosts_command;
1331 charptr = &options->proxy_command;
1332 /* Ignore ProxyCommand if ProxyJump already specified */
1333 if (options->jump_host != NULL)
1334 charptr = &options->jump_host; /* Skip below */
1337 error("%.200s line %d: Missing argument.",
1341 len = strspn(str, WHITESPACE "=");
1342 if (*activep && *charptr == NULL)
1343 *charptr = xstrdup(str + len);
1349 error("%.200s line %d: Missing argument.",
1353 len = strspn(str, WHITESPACE "=");
1355 if (parse_jump(str + len, options, *activep) == -1) {
1356 error("%.200s line %d: Invalid ProxyJump \"%s\"",
1357 filename, linenum, str + len);
1364 arg = argv_next(&ac, &av);
1365 if (!arg || *arg == '\0') {
1366 error("%.200s line %d: Missing argument.",
1370 value = a2port(arg);
1372 error("%.200s line %d: Bad port '%s'.",
1373 filename, linenum, arg);
1376 if (*activep && options->port == -1)
1377 options->port = value;
1380 case oConnectionAttempts:
1381 intptr = &options->connection_attempts;
1383 arg = argv_next(&ac, &av);
1384 if ((errstr = atoi_err(arg, &value)) != NULL) {
1385 error("%s line %d: integer value %s.",
1386 filename, linenum, errstr);
1389 if (*activep && *intptr == -1)
1394 arg = argv_next(&ac, &av);
1395 if (!arg || *arg == '\0') {
1396 error("%.200s line %d: Missing argument.",
1401 !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)){
1402 error("%.200s line %d: Bad SSH2 cipher spec '%s'.",
1403 filename, linenum, arg ? arg : "<NONE>");
1406 if (*activep && options->ciphers == NULL)
1407 options->ciphers = xstrdup(arg);
1411 arg = argv_next(&ac, &av);
1412 if (!arg || *arg == '\0') {
1413 error("%.200s line %d: Missing argument.",
1418 !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)) {
1419 error("%.200s line %d: Bad SSH2 MAC spec '%s'.",
1420 filename, linenum, arg ? arg : "<NONE>");
1423 if (*activep && options->macs == NULL)
1424 options->macs = xstrdup(arg);
1427 case oKexAlgorithms:
1428 arg = argv_next(&ac, &av);
1429 if (!arg || *arg == '\0') {
1430 error("%.200s line %d: Missing argument.",
1435 !kex_names_valid(*arg == '+' || *arg == '^' ?
1437 error("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
1438 filename, linenum, arg ? arg : "<NONE>");
1441 if (*activep && options->kex_algorithms == NULL)
1442 options->kex_algorithms = xstrdup(arg);
1445 case oHostKeyAlgorithms:
1446 charptr = &options->hostkeyalgorithms;
1448 arg = argv_next(&ac, &av);
1449 if (!arg || *arg == '\0') {
1450 error("%.200s line %d: Missing argument.",
1455 !sshkey_names_valid2(*arg == '+' || *arg == '^' ?
1456 arg + 1 : arg, 1)) {
1457 error("%s line %d: Bad key types '%s'.",
1458 filename, linenum, arg ? arg : "<NONE>");
1461 if (*activep && *charptr == NULL)
1462 *charptr = xstrdup(arg);
1465 case oCASignatureAlgorithms:
1466 charptr = &options->ca_sign_algorithms;
1467 goto parse_pubkey_algos;
1470 log_level_ptr = &options->log_level;
1471 arg = argv_next(&ac, &av);
1472 value = log_level_number(arg);
1473 if (value == SYSLOG_LEVEL_NOT_SET) {
1474 error("%.200s line %d: unsupported log level '%s'",
1475 filename, linenum, arg ? arg : "<NONE>");
1478 if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1479 *log_level_ptr = (LogLevel) value;
1483 log_facility_ptr = &options->log_facility;
1484 arg = argv_next(&ac, &av);
1485 value = log_facility_number(arg);
1486 if (value == SYSLOG_FACILITY_NOT_SET) {
1487 error("%.200s line %d: unsupported log facility '%s'",
1488 filename, linenum, arg ? arg : "<NONE>");
1491 if (*log_facility_ptr == -1)
1492 *log_facility_ptr = (SyslogFacility) value;
1496 cppptr = &options->log_verbose;
1497 uintptr = &options->num_log_verbose;
1499 while ((arg = argv_next(&ac, &av)) != NULL) {
1501 error("%s line %d: keyword %s empty argument",
1502 filename, linenum, keyword);
1505 /* Allow "none" only in first position */
1506 if (strcasecmp(arg, "none") == 0) {
1507 if (i > 0 || ac > 0) {
1508 error("%s line %d: keyword %s \"none\" "
1509 "argument must appear alone.",
1510 filename, linenum, keyword);
1515 if (*activep && *uintptr == 0) {
1516 *cppptr = xrecallocarray(*cppptr, *uintptr,
1517 *uintptr + 1, sizeof(**cppptr));
1518 (*cppptr)[(*uintptr)++] = xstrdup(arg);
1524 case oRemoteForward:
1525 case oDynamicForward:
1526 arg = argv_next(&ac, &av);
1527 if (!arg || *arg == '\0') {
1528 error("%.200s line %d: Missing argument.",
1533 remotefwd = (opcode == oRemoteForward);
1534 dynamicfwd = (opcode == oDynamicForward);
1537 arg2 = argv_next(&ac, &av);
1538 if (arg2 == NULL || *arg2 == '\0') {
1542 error("%.200s line %d: Missing target "
1543 "argument.", filename, linenum);
1547 /* construct a string for parse_forward */
1548 snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg,
1553 strlcpy(fwdarg, arg, sizeof(fwdarg));
1555 if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0) {
1556 error("%.200s line %d: Bad forwarding specification.",
1563 add_remote_forward(options, &fwd);
1565 add_local_forward(options, &fwd);
1570 case oPermitRemoteOpen:
1571 uintptr = &options->num_permitted_remote_opens;
1572 cppptr = &options->permitted_remote_opens;
1573 arg = argv_next(&ac, &av);
1574 if (!arg || *arg == '\0')
1575 fatal("%s line %d: missing %s specification",
1576 filename, linenum, lookup_opcode_name(opcode));
1577 uvalue = *uintptr; /* modified later */
1578 if (strcmp(arg, "any") == 0 || strcmp(arg, "none") == 0) {
1579 if (*activep && uvalue == 0) {
1581 *cppptr = xcalloc(1, sizeof(**cppptr));
1582 (*cppptr)[0] = xstrdup(arg);
1586 while ((arg = argv_next(&ac, &av)) != NULL) {
1587 arg2 = xstrdup(arg);
1589 p = hpdelim2(&arg, &ch);
1590 if (p == NULL || ch == '/') {
1591 fatal("%s line %d: missing host in %s",
1593 lookup_opcode_name(opcode));
1595 p = cleanhostname(p);
1597 * don't want to use permitopen_port to avoid
1598 * dependency on channels.[ch] here.
1601 (strcmp(arg, "*") != 0 && a2port(arg) <= 0)) {
1602 fatal("%s line %d: bad port number in %s",
1604 lookup_opcode_name(opcode));
1606 if (*activep && uvalue == 0) {
1607 opt_array_append(filename, linenum,
1608 lookup_opcode_name(opcode),
1609 cppptr, uintptr, arg2);
1615 case oClearAllForwardings:
1616 intptr = &options->clear_forwardings;
1621 error("Host directive not supported as a command-line "
1627 while ((arg = argv_next(&ac, &av)) != NULL) {
1629 error("%s line %d: keyword %s empty argument",
1630 filename, linenum, keyword);
1633 if ((flags & SSHCONF_NEVERMATCH) != 0) {
1637 negated = *arg == '!';
1640 if (match_pattern(host, arg)) {
1642 debug("%.200s line %d: Skipping Host "
1643 "block because of negated match "
1644 "for %.100s", filename, linenum,
1651 arg2 = arg; /* logged below */
1656 debug("%.200s line %d: Applying options for %.100s",
1657 filename, linenum, arg2);
1662 error("Host directive not supported as a command-line "
1666 value = match_cfg_line(options, &str, pw, host, original_host,
1667 flags & SSHCONF_FINAL, want_final_pass,
1670 error("%.200s line %d: Bad Match condition", filename,
1674 *activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
1676 * If match_cfg_line() didn't consume all its arguments then
1677 * arrange for the extra arguments check below to fail.
1680 if (str == NULL || *str == '\0')
1685 intptr = &options->escape_char;
1686 arg = argv_next(&ac, &av);
1687 if (!arg || *arg == '\0') {
1688 error("%.200s line %d: Missing argument.",
1692 if (strcmp(arg, "none") == 0)
1693 value = SSH_ESCAPECHAR_NONE;
1694 else if (arg[1] == '\0')
1695 value = (u_char) arg[0];
1696 else if (arg[0] == '^' && arg[2] == 0 &&
1697 (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1698 value = (u_char) arg[1] & 31;
1700 error("%.200s line %d: Bad escape character.",
1704 if (*activep && *intptr == -1)
1708 case oAddressFamily:
1709 intptr = &options->address_family;
1710 multistate_ptr = multistate_addressfamily;
1711 goto parse_multistate;
1713 case oEnableSSHKeysign:
1714 intptr = &options->enable_ssh_keysign;
1717 case oIdentitiesOnly:
1718 intptr = &options->identities_only;
1721 case oServerAliveInterval:
1722 intptr = &options->server_alive_interval;
1725 case oServerAliveCountMax:
1726 intptr = &options->server_alive_count_max;
1730 while ((arg = argv_next(&ac, &av)) != NULL) {
1731 if (*arg == '\0' || strchr(arg, '=') != NULL) {
1732 error("%s line %d: Invalid environment name.",
1739 /* Removing an env var */
1740 rm_env(options, arg, filename, linenum);
1743 /* Adding an env var */
1744 if (options->num_send_env >= INT_MAX) {
1745 error("%s line %d: too many send env.",
1749 options->send_env = xrecallocarray(
1750 options->send_env, options->num_send_env,
1751 options->num_send_env + 1,
1752 sizeof(*options->send_env));
1753 options->send_env[options->num_send_env++] =
1760 value = options->num_setenv;
1761 while ((arg = argv_next(&ac, &av)) != NULL) {
1762 if (strchr(arg, '=') == NULL) {
1763 error("%s line %d: Invalid SetEnv.",
1767 if (!*activep || value != 0)
1769 /* Adding a setenv var */
1770 if (options->num_setenv >= INT_MAX) {
1771 error("%s line %d: too many SetEnv.",
1775 options->setenv = xrecallocarray(
1776 options->setenv, options->num_setenv,
1777 options->num_setenv + 1, sizeof(*options->setenv));
1778 options->setenv[options->num_setenv++] = xstrdup(arg);
1783 charptr = &options->control_path;
1786 case oControlMaster:
1787 intptr = &options->control_master;
1788 multistate_ptr = multistate_controlmaster;
1789 goto parse_multistate;
1791 case oControlPersist:
1792 /* no/false/yes/true, or a time spec */
1793 intptr = &options->control_persist;
1794 arg = argv_next(&ac, &av);
1795 if (!arg || *arg == '\0') {
1796 error("%.200s line %d: Missing ControlPersist"
1797 " argument.", filename, linenum);
1801 value2 = 0; /* timeout */
1802 if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1804 else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1806 else if ((value2 = convtime(arg)) >= 0)
1809 error("%.200s line %d: Bad ControlPersist argument.",
1813 if (*activep && *intptr == -1) {
1815 options->control_persist_timeout = value2;
1819 case oHashKnownHosts:
1820 intptr = &options->hash_known_hosts;
1824 intptr = &options->tun_open;
1825 multistate_ptr = multistate_tunnel;
1826 goto parse_multistate;
1829 arg = argv_next(&ac, &av);
1830 if (!arg || *arg == '\0') {
1831 error("%.200s line %d: Missing argument.",
1835 value = a2tun(arg, &value2);
1836 if (value == SSH_TUNID_ERR) {
1837 error("%.200s line %d: Bad tun device.",
1841 if (*activep && options->tun_local == -1) {
1842 options->tun_local = value;
1843 options->tun_remote = value2;
1848 charptr = &options->local_command;
1851 case oPermitLocalCommand:
1852 intptr = &options->permit_local_command;
1855 case oRemoteCommand:
1856 charptr = &options->remote_command;
1859 case oVisualHostKey:
1860 intptr = &options->visual_host_key;
1865 error("Include directive not supported as a "
1866 "command-line option");
1870 while ((arg = argv_next(&ac, &av)) != NULL) {
1872 error("%s line %d: keyword %s empty argument",
1873 filename, linenum, keyword);
1877 * Ensure all paths are anchored. User configuration
1878 * files may begin with '~/' but system configurations
1879 * must not. If the path is relative, then treat it
1880 * as living in ~/.ssh for user configurations or
1881 * /etc/ssh for system ones.
1883 if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0) {
1884 error("%.200s line %d: bad include path %s.",
1885 filename, linenum, arg);
1888 if (!path_absolute(arg) && *arg != '~') {
1889 xasprintf(&arg2, "%s/%s",
1890 (flags & SSHCONF_USERCONF) ?
1891 "~/" _PATH_SSH_USER_DIR : SSHDIR, arg);
1893 arg2 = xstrdup(arg);
1894 memset(&gl, 0, sizeof(gl));
1895 r = glob(arg2, GLOB_TILDE, NULL, &gl);
1896 if (r == GLOB_NOMATCH) {
1897 debug("%.200s line %d: include %s matched no "
1898 "files",filename, linenum, arg2);
1901 } else if (r != 0) {
1902 error("%.200s line %d: glob failed for %s.",
1903 filename, linenum, arg2);
1908 for (i = 0; i < gl.gl_pathc; i++) {
1909 debug3("%.200s line %d: Including file %s "
1910 "depth %d%s", filename, linenum,
1911 gl.gl_pathv[i], depth,
1912 oactive ? "" : " (parse only)");
1913 r = read_config_file_depth(gl.gl_pathv[i],
1914 pw, host, original_host, options,
1915 flags | SSHCONF_CHECKPERM |
1916 (oactive ? 0 : SSHCONF_NEVERMATCH),
1917 activep, want_final_pass, depth + 1);
1918 if (r != 1 && errno != ENOENT) {
1919 error("Can't open user config file "
1920 "%.100s: %.100s", gl.gl_pathv[i],
1926 * don't let Match in includes clobber the
1927 * containing file's Match state.
1940 arg = argv_next(&ac, &av);
1941 if ((value = parse_ipqos(arg)) == -1) {
1942 error("%s line %d: Bad IPQoS value: %s",
1943 filename, linenum, arg);
1946 arg = argv_next(&ac, &av);
1949 else if ((value2 = parse_ipqos(arg)) == -1) {
1950 error("%s line %d: Bad IPQoS value: %s",
1951 filename, linenum, arg);
1954 if (*activep && options->ip_qos_interactive == -1) {
1955 options->ip_qos_interactive = value;
1956 options->ip_qos_bulk = value2;
1961 intptr = &options->request_tty;
1962 multistate_ptr = multistate_requesttty;
1963 goto parse_multistate;
1966 intptr = &options->session_type;
1967 multistate_ptr = multistate_sessiontype;
1968 goto parse_multistate;
1971 intptr = &options->stdin_null;
1974 case oForkAfterAuthentication:
1975 intptr = &options->fork_after_authentication;
1978 case oVersionAddendum:
1980 fatal("%.200s line %d: Missing argument.", filename,
1982 len = strspn(str, WHITESPACE);
1983 if (*activep && options->version_addendum == NULL) {
1984 if (strcasecmp(str + len, "none") == 0)
1985 options->version_addendum = xstrdup("");
1986 else if (strchr(str + len, '\r') != NULL)
1987 fatal("%.200s line %d: Invalid argument",
1990 options->version_addendum = xstrdup(str + len);
1994 case oIgnoreUnknown:
1995 charptr = &options->ignored_unknown;
1998 case oProxyUseFdpass:
1999 intptr = &options->proxy_use_fdpass;
2002 case oCanonicalDomains:
2003 value = options->num_canonical_domains != 0;
2005 while ((arg = argv_next(&ac, &av)) != NULL) {
2007 error("%s line %d: keyword %s empty argument",
2008 filename, linenum, keyword);
2011 /* Allow "none" only in first position */
2012 if (strcasecmp(arg, "none") == 0) {
2013 if (i > 0 || ac > 0) {
2014 error("%s line %d: keyword %s \"none\" "
2015 "argument must appear alone.",
2016 filename, linenum, keyword);
2021 if (!valid_domain(arg, 1, &errstr)) {
2022 error("%s line %d: %s", filename, linenum,
2026 if (!*activep || value)
2028 if (options->num_canonical_domains >=
2029 MAX_CANON_DOMAINS) {
2030 error("%s line %d: too many hostname suffixes.",
2034 options->canonical_domains[
2035 options->num_canonical_domains++] = xstrdup(arg);
2039 case oCanonicalizePermittedCNAMEs:
2040 value = options->num_permitted_cnames != 0;
2041 while ((arg = argv_next(&ac, &av)) != NULL) {
2042 /* Either '*' for everything or 'list:list' */
2043 if (strcmp(arg, "*") == 0)
2047 if ((arg2 = strchr(arg, ':')) == NULL ||
2049 error("%s line %d: "
2050 "Invalid permitted CNAME \"%s\"",
2051 filename, linenum, arg);
2057 if (!*activep || value)
2059 if (options->num_permitted_cnames >=
2060 MAX_CANON_DOMAINS) {
2061 error("%s line %d: too many permitted CNAMEs.",
2065 cname = options->permitted_cnames +
2066 options->num_permitted_cnames++;
2067 cname->source_list = xstrdup(arg);
2068 cname->target_list = xstrdup(arg2);
2072 case oCanonicalizeHostname:
2073 intptr = &options->canonicalize_hostname;
2074 multistate_ptr = multistate_canonicalizehostname;
2075 goto parse_multistate;
2077 case oCanonicalizeMaxDots:
2078 intptr = &options->canonicalize_max_dots;
2081 case oCanonicalizeFallbackLocal:
2082 intptr = &options->canonicalize_fallback_local;
2085 case oStreamLocalBindMask:
2086 arg = argv_next(&ac, &av);
2087 if (!arg || *arg == '\0') {
2088 error("%.200s line %d: Missing StreamLocalBindMask "
2089 "argument.", filename, linenum);
2092 /* Parse mode in octal format */
2093 value = strtol(arg, &endofnumber, 8);
2094 if (arg == endofnumber || value < 0 || value > 0777) {
2095 error("%.200s line %d: Bad mask.", filename, linenum);
2098 options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
2101 case oStreamLocalBindUnlink:
2102 intptr = &options->fwd_opts.streamlocal_bind_unlink;
2105 case oRevokedHostKeys:
2106 charptr = &options->revoked_host_keys;
2109 case oFingerprintHash:
2110 intptr = &options->fingerprint_hash;
2111 arg = argv_next(&ac, &av);
2112 if (!arg || *arg == '\0') {
2113 error("%.200s line %d: Missing argument.",
2117 if ((value = ssh_digest_alg_by_name(arg)) == -1) {
2118 error("%.200s line %d: Invalid hash algorithm \"%s\".",
2119 filename, linenum, arg);
2122 if (*activep && *intptr == -1)
2126 case oUpdateHostkeys:
2127 intptr = &options->update_hostkeys;
2128 multistate_ptr = multistate_yesnoask;
2129 goto parse_multistate;
2131 case oHostbasedAcceptedAlgorithms:
2132 charptr = &options->hostbased_accepted_algos;
2133 goto parse_pubkey_algos;
2135 case oPubkeyAcceptedAlgorithms:
2136 charptr = &options->pubkey_accepted_algos;
2137 goto parse_pubkey_algos;
2139 case oAddKeysToAgent:
2140 arg = argv_next(&ac, &av);
2141 arg2 = argv_next(&ac, &av);
2142 value = parse_multistate_value(arg, filename, linenum,
2143 multistate_yesnoaskconfirm);
2144 value2 = 0; /* unlimited lifespan by default */
2145 if (value == 3 && arg2 != NULL) {
2146 /* allow "AddKeysToAgent confirm 5m" */
2147 if ((value2 = convtime(arg2)) == -1 ||
2149 error("%s line %d: invalid time value.",
2153 } else if (value == -1 && arg2 == NULL) {
2154 if ((value2 = convtime(arg)) == -1 ||
2156 error("%s line %d: unsupported option",
2160 value = 1; /* yes */
2161 } else if (value == -1 || arg2 != NULL) {
2162 error("%s line %d: unsupported option",
2166 if (*activep && options->add_keys_to_agent == -1) {
2167 options->add_keys_to_agent = value;
2168 options->add_keys_to_agent_lifespan = value2;
2172 case oIdentityAgent:
2173 charptr = &options->identity_agent;
2174 arg = argv_next(&ac, &av);
2175 if (!arg || *arg == '\0') {
2176 error("%.200s line %d: Missing argument.",
2181 /* Extra validation if the string represents an env var. */
2182 if ((arg2 = dollar_expand(&r, arg)) == NULL || r) {
2183 error("%.200s line %d: Invalid environment expansion "
2184 "%s.", filename, linenum, arg);
2188 /* check for legacy environment format */
2189 if (arg[0] == '$' && arg[1] != '{' &&
2190 !valid_env_name(arg + 1)) {
2191 error("%.200s line %d: Invalid environment name %s.",
2192 filename, linenum, arg);
2195 if (*activep && *charptr == NULL)
2196 *charptr = xstrdup(arg);
2200 debug("%s line %d: Deprecated option \"%s\"",
2201 filename, linenum, keyword);
2206 error("%s line %d: Unsupported option \"%s\"",
2207 filename, linenum, keyword);
2212 error("%s line %d: Unimplemented opcode %d",
2213 filename, linenum, opcode);
2217 /* Check that there is no garbage at end of line. */
2219 error("%.200s line %d: keyword %s extra arguments "
2220 "at end of line", filename, linenum, keyword);
2227 argv_free(oav, oac);
2232 * Reads the config file and modifies the options accordingly. Options
2233 * should already be initialized before this call. This never returns if
2234 * there is an error. If the file does not exist, this returns 0.
2237 read_config_file(const char *filename, struct passwd *pw, const char *host,
2238 const char *original_host, Options *options, int flags,
2239 int *want_final_pass)
2243 return read_config_file_depth(filename, pw, host, original_host,
2244 options, flags, &active, want_final_pass, 0);
2247 #define READCONF_MAX_DEPTH 16
2249 read_config_file_depth(const char *filename, struct passwd *pw,
2250 const char *host, const char *original_host, Options *options,
2251 int flags, int *activep, int *want_final_pass, int depth)
2255 size_t linesize = 0;
2257 int bad_options = 0;
2259 if (depth < 0 || depth > READCONF_MAX_DEPTH)
2260 fatal("Too many recursive configuration includes");
2262 if ((f = fopen(filename, "r")) == NULL)
2265 if (flags & SSHCONF_CHECKPERM) {
2268 if (fstat(fileno(f), &sb) == -1)
2269 fatal("fstat %s: %s", filename, strerror(errno));
2270 if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
2271 (sb.st_mode & 022) != 0))
2272 fatal("Bad owner or permissions on %s", filename);
2275 debug("Reading configuration data %.200s", filename);
2278 * Mark that we are now processing the options. This flag is turned
2279 * on/off by Host specifications.
2282 while (getline(&line, &linesize, f) != -1) {
2283 /* Update line number counter. */
2286 * Trim out comments and strip whitespace.
2287 * NB - preserve newlines, they are needed to reproduce
2288 * line numbers later for error messages.
2290 if (process_config_line_depth(options, pw, host, original_host,
2291 line, filename, linenum, activep, flags, want_final_pass,
2297 if (bad_options > 0)
2298 fatal("%s: terminating, %d bad configuration options",
2299 filename, bad_options);
2303 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
2305 option_clear_or_none(const char *o)
2307 return o == NULL || strcasecmp(o, "none") == 0;
2311 * Initializes options to special values that indicate that they have not yet
2312 * been set. Read_config_file will only set options with this value. Options
2313 * are processed in the following order: command line, user config file,
2314 * system config file. Last, fill_default_options is called.
2318 initialize_options(Options * options)
2320 memset(options, 'X', sizeof(*options));
2321 options->version_addendum = NULL;
2322 options->forward_agent = -1;
2323 options->forward_agent_sock_path = NULL;
2324 options->forward_x11 = -1;
2325 options->forward_x11_trusted = -1;
2326 options->forward_x11_timeout = -1;
2327 options->stdio_forward_host = NULL;
2328 options->stdio_forward_port = 0;
2329 options->clear_forwardings = -1;
2330 options->exit_on_forward_failure = -1;
2331 options->xauth_location = NULL;
2332 options->fwd_opts.gateway_ports = -1;
2333 options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
2334 options->fwd_opts.streamlocal_bind_unlink = -1;
2335 options->pubkey_authentication = -1;
2336 options->gss_authentication = -1;
2337 options->gss_deleg_creds = -1;
2338 options->password_authentication = -1;
2339 options->kbd_interactive_authentication = -1;
2340 options->kbd_interactive_devices = NULL;
2341 options->hostbased_authentication = -1;
2342 options->batch_mode = -1;
2343 options->check_host_ip = -1;
2344 options->strict_host_key_checking = -1;
2345 options->compression = -1;
2346 options->tcp_keep_alive = -1;
2348 options->address_family = -1;
2349 options->connection_attempts = -1;
2350 options->connection_timeout = -1;
2351 options->number_of_password_prompts = -1;
2352 options->ciphers = NULL;
2353 options->macs = NULL;
2354 options->kex_algorithms = NULL;
2355 options->hostkeyalgorithms = NULL;
2356 options->ca_sign_algorithms = NULL;
2357 options->num_identity_files = 0;
2358 memset(options->identity_keys, 0, sizeof(options->identity_keys));
2359 options->num_certificate_files = 0;
2360 memset(options->certificates, 0, sizeof(options->certificates));
2361 options->hostname = NULL;
2362 options->host_key_alias = NULL;
2363 options->proxy_command = NULL;
2364 options->jump_user = NULL;
2365 options->jump_host = NULL;
2366 options->jump_port = -1;
2367 options->jump_extra = NULL;
2368 options->user = NULL;
2369 options->escape_char = -1;
2370 options->num_system_hostfiles = 0;
2371 options->num_user_hostfiles = 0;
2372 options->local_forwards = NULL;
2373 options->num_local_forwards = 0;
2374 options->remote_forwards = NULL;
2375 options->num_remote_forwards = 0;
2376 options->permitted_remote_opens = NULL;
2377 options->num_permitted_remote_opens = 0;
2378 options->log_facility = SYSLOG_FACILITY_NOT_SET;
2379 options->log_level = SYSLOG_LEVEL_NOT_SET;
2380 options->num_log_verbose = 0;
2381 options->log_verbose = NULL;
2382 options->preferred_authentications = NULL;
2383 options->bind_address = NULL;
2384 options->bind_interface = NULL;
2385 options->pkcs11_provider = NULL;
2386 options->sk_provider = NULL;
2387 options->enable_ssh_keysign = - 1;
2388 options->no_host_authentication_for_localhost = - 1;
2389 options->identities_only = - 1;
2390 options->rekey_limit = - 1;
2391 options->rekey_interval = -1;
2392 options->verify_host_key_dns = -1;
2393 options->server_alive_interval = -1;
2394 options->server_alive_count_max = -1;
2395 options->send_env = NULL;
2396 options->num_send_env = 0;
2397 options->setenv = NULL;
2398 options->num_setenv = 0;
2399 options->control_path = NULL;
2400 options->control_master = -1;
2401 options->control_persist = -1;
2402 options->control_persist_timeout = 0;
2403 options->hash_known_hosts = -1;
2404 options->tun_open = -1;
2405 options->tun_local = -1;
2406 options->tun_remote = -1;
2407 options->local_command = NULL;
2408 options->permit_local_command = -1;
2409 options->remote_command = NULL;
2410 options->add_keys_to_agent = -1;
2411 options->add_keys_to_agent_lifespan = -1;
2412 options->identity_agent = NULL;
2413 options->visual_host_key = -1;
2414 options->ip_qos_interactive = -1;
2415 options->ip_qos_bulk = -1;
2416 options->request_tty = -1;
2417 options->session_type = -1;
2418 options->stdin_null = -1;
2419 options->fork_after_authentication = -1;
2420 options->proxy_use_fdpass = -1;
2421 options->ignored_unknown = NULL;
2422 options->num_canonical_domains = 0;
2423 options->num_permitted_cnames = 0;
2424 options->canonicalize_max_dots = -1;
2425 options->canonicalize_fallback_local = -1;
2426 options->canonicalize_hostname = -1;
2427 options->revoked_host_keys = NULL;
2428 options->fingerprint_hash = -1;
2429 options->update_hostkeys = -1;
2430 options->hostbased_accepted_algos = NULL;
2431 options->pubkey_accepted_algos = NULL;
2432 options->known_hosts_command = NULL;
2436 * A petite version of fill_default_options() that just fills the options
2437 * needed for hostname canonicalization to proceed.
2440 fill_default_options_for_canonicalization(Options *options)
2442 if (options->canonicalize_max_dots == -1)
2443 options->canonicalize_max_dots = 1;
2444 if (options->canonicalize_fallback_local == -1)
2445 options->canonicalize_fallback_local = 1;
2446 if (options->canonicalize_hostname == -1)
2447 options->canonicalize_hostname = SSH_CANONICALISE_NO;
2451 * Called after processing other sources of option data, this fills those
2452 * options for which no value has been specified with their default values.
2455 fill_default_options(Options * options)
2457 char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
2458 char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
2461 if (options->forward_agent == -1)
2462 options->forward_agent = 0;
2463 if (options->forward_x11 == -1)
2464 options->forward_x11 = 0;
2465 if (options->forward_x11_trusted == -1)
2466 options->forward_x11_trusted = 0;
2467 if (options->forward_x11_timeout == -1)
2468 options->forward_x11_timeout = 1200;
2470 * stdio forwarding (-W) changes the default for these but we defer
2471 * setting the values so they can be overridden.
2473 if (options->exit_on_forward_failure == -1)
2474 options->exit_on_forward_failure =
2475 options->stdio_forward_host != NULL ? 1 : 0;
2476 if (options->clear_forwardings == -1)
2477 options->clear_forwardings =
2478 options->stdio_forward_host != NULL ? 1 : 0;
2479 if (options->clear_forwardings == 1)
2480 clear_forwardings(options);
2482 if (options->xauth_location == NULL)
2483 options->xauth_location = xstrdup(_PATH_XAUTH);
2484 if (options->fwd_opts.gateway_ports == -1)
2485 options->fwd_opts.gateway_ports = 0;
2486 if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
2487 options->fwd_opts.streamlocal_bind_mask = 0177;
2488 if (options->fwd_opts.streamlocal_bind_unlink == -1)
2489 options->fwd_opts.streamlocal_bind_unlink = 0;
2490 if (options->pubkey_authentication == -1)
2491 options->pubkey_authentication = 1;
2492 if (options->gss_authentication == -1)
2493 options->gss_authentication = 0;
2494 if (options->gss_deleg_creds == -1)
2495 options->gss_deleg_creds = 0;
2496 if (options->password_authentication == -1)
2497 options->password_authentication = 1;
2498 if (options->kbd_interactive_authentication == -1)
2499 options->kbd_interactive_authentication = 1;
2500 if (options->hostbased_authentication == -1)
2501 options->hostbased_authentication = 0;
2502 if (options->batch_mode == -1)
2503 options->batch_mode = 0;
2504 if (options->check_host_ip == -1)
2505 options->check_host_ip = 0;
2506 if (options->strict_host_key_checking == -1)
2507 options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK;
2508 if (options->compression == -1)
2509 options->compression = 0;
2510 if (options->tcp_keep_alive == -1)
2511 options->tcp_keep_alive = 1;
2512 if (options->port == -1)
2513 options->port = 0; /* Filled in ssh_connect. */
2514 if (options->address_family == -1)
2515 options->address_family = AF_UNSPEC;
2516 if (options->connection_attempts == -1)
2517 options->connection_attempts = 1;
2518 if (options->number_of_password_prompts == -1)
2519 options->number_of_password_prompts = 3;
2520 /* options->hostkeyalgorithms, default set in myproposals.h */
2521 if (options->add_keys_to_agent == -1) {
2522 options->add_keys_to_agent = 0;
2523 options->add_keys_to_agent_lifespan = 0;
2525 if (options->num_identity_files == 0) {
2526 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0);
2527 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0);
2528 #ifdef OPENSSL_HAS_ECC
2529 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0);
2530 add_identity_file(options, "~/",
2531 _PATH_SSH_CLIENT_ID_ECDSA_SK, 0);
2533 add_identity_file(options, "~/",
2534 _PATH_SSH_CLIENT_ID_ED25519, 0);
2535 add_identity_file(options, "~/",
2536 _PATH_SSH_CLIENT_ID_ED25519_SK, 0);
2537 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0);
2539 if (options->escape_char == -1)
2540 options->escape_char = '~';
2541 if (options->num_system_hostfiles == 0) {
2542 options->system_hostfiles[options->num_system_hostfiles++] =
2543 xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
2544 options->system_hostfiles[options->num_system_hostfiles++] =
2545 xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
2547 if (options->update_hostkeys == -1) {
2548 if (options->verify_host_key_dns <= 0 &&
2549 (options->num_user_hostfiles == 0 ||
2550 (options->num_user_hostfiles == 1 && strcmp(options->
2551 user_hostfiles[0], _PATH_SSH_USER_HOSTFILE) == 0)))
2552 options->update_hostkeys = SSH_UPDATE_HOSTKEYS_YES;
2554 options->update_hostkeys = SSH_UPDATE_HOSTKEYS_NO;
2556 if (options->num_user_hostfiles == 0) {
2557 options->user_hostfiles[options->num_user_hostfiles++] =
2558 xstrdup(_PATH_SSH_USER_HOSTFILE);
2559 options->user_hostfiles[options->num_user_hostfiles++] =
2560 xstrdup(_PATH_SSH_USER_HOSTFILE2);
2562 if (options->log_level == SYSLOG_LEVEL_NOT_SET)
2563 options->log_level = SYSLOG_LEVEL_INFO;
2564 if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
2565 options->log_facility = SYSLOG_FACILITY_USER;
2566 if (options->no_host_authentication_for_localhost == - 1)
2567 options->no_host_authentication_for_localhost = 0;
2568 if (options->identities_only == -1)
2569 options->identities_only = 0;
2570 if (options->enable_ssh_keysign == -1)
2571 options->enable_ssh_keysign = 0;
2572 if (options->rekey_limit == -1)
2573 options->rekey_limit = 0;
2574 if (options->rekey_interval == -1)
2575 options->rekey_interval = 0;
2577 if (options->verify_host_key_dns == -1)
2578 /* automatically trust a verified SSHFP record */
2579 options->verify_host_key_dns = 1;
2581 if (options->verify_host_key_dns == -1)
2582 options->verify_host_key_dns = 0;
2584 if (options->server_alive_interval == -1)
2585 options->server_alive_interval = 0;
2586 if (options->server_alive_count_max == -1)
2587 options->server_alive_count_max = 3;
2588 if (options->control_master == -1)
2589 options->control_master = 0;
2590 if (options->control_persist == -1) {
2591 options->control_persist = 0;
2592 options->control_persist_timeout = 0;
2594 if (options->hash_known_hosts == -1)
2595 options->hash_known_hosts = 0;
2596 if (options->tun_open == -1)
2597 options->tun_open = SSH_TUNMODE_NO;
2598 if (options->tun_local == -1)
2599 options->tun_local = SSH_TUNID_ANY;
2600 if (options->tun_remote == -1)
2601 options->tun_remote = SSH_TUNID_ANY;
2602 if (options->permit_local_command == -1)
2603 options->permit_local_command = 0;
2604 if (options->visual_host_key == -1)
2605 options->visual_host_key = 0;
2606 if (options->ip_qos_interactive == -1)
2607 options->ip_qos_interactive = IPTOS_DSCP_AF21;
2608 if (options->ip_qos_bulk == -1)
2609 options->ip_qos_bulk = IPTOS_DSCP_CS1;
2610 if (options->request_tty == -1)
2611 options->request_tty = REQUEST_TTY_AUTO;
2612 if (options->session_type == -1)
2613 options->session_type = SESSION_TYPE_DEFAULT;
2614 if (options->stdin_null == -1)
2615 options->stdin_null = 0;
2616 if (options->fork_after_authentication == -1)
2617 options->fork_after_authentication = 0;
2618 if (options->proxy_use_fdpass == -1)
2619 options->proxy_use_fdpass = 0;
2620 if (options->canonicalize_max_dots == -1)
2621 options->canonicalize_max_dots = 1;
2622 if (options->canonicalize_fallback_local == -1)
2623 options->canonicalize_fallback_local = 1;
2624 if (options->canonicalize_hostname == -1)
2625 options->canonicalize_hostname = SSH_CANONICALISE_NO;
2626 if (options->fingerprint_hash == -1)
2627 options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
2628 #ifdef ENABLE_SK_INTERNAL
2629 if (options->sk_provider == NULL)
2630 options->sk_provider = xstrdup("internal");
2632 if (options->sk_provider == NULL)
2633 options->sk_provider = xstrdup("$SSH_SK_PROVIDER");
2636 /* Expand KEX name lists */
2637 all_cipher = cipher_alg_list(',', 0);
2638 all_mac = mac_alg_list(',');
2639 all_kex = kex_alg_list(',');
2640 all_key = sshkey_alg_list(0, 0, 1, ',');
2641 all_sig = sshkey_alg_list(0, 1, 1, ',');
2642 /* remove unsupported algos from default lists */
2643 def_cipher = match_filter_allowlist(KEX_CLIENT_ENCRYPT, all_cipher);
2644 def_mac = match_filter_allowlist(KEX_CLIENT_MAC, all_mac);
2645 def_kex = match_filter_allowlist(KEX_CLIENT_KEX, all_kex);
2646 def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
2647 def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
2648 #define ASSEMBLE(what, defaults, all) \
2650 if ((r = kex_assemble_names(&options->what, \
2651 defaults, all)) != 0) { \
2652 error_fr(r, "%s", #what); \
2656 ASSEMBLE(ciphers, def_cipher, all_cipher);
2657 ASSEMBLE(macs, def_mac, all_mac);
2658 ASSEMBLE(kex_algorithms, def_kex, all_kex);
2659 ASSEMBLE(hostbased_accepted_algos, def_key, all_key);
2660 ASSEMBLE(pubkey_accepted_algos, def_key, all_key);
2661 ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
2664 #define CLEAR_ON_NONE(v) \
2666 if (option_clear_or_none(v)) { \
2671 CLEAR_ON_NONE(options->local_command);
2672 CLEAR_ON_NONE(options->remote_command);
2673 CLEAR_ON_NONE(options->proxy_command);
2674 CLEAR_ON_NONE(options->control_path);
2675 CLEAR_ON_NONE(options->revoked_host_keys);
2676 CLEAR_ON_NONE(options->pkcs11_provider);
2677 CLEAR_ON_NONE(options->sk_provider);
2678 CLEAR_ON_NONE(options->known_hosts_command);
2679 if (options->jump_host != NULL &&
2680 strcmp(options->jump_host, "none") == 0 &&
2681 options->jump_port == 0 && options->jump_user == NULL) {
2682 free(options->jump_host);
2683 options->jump_host = NULL;
2685 /* options->identity_agent distinguishes NULL from 'none' */
2686 /* options->user will be set in the main program if appropriate */
2687 /* options->hostname will be set in the main program if appropriate */
2688 /* options->host_key_alias should not be set by default */
2689 /* options->preferred_authentications will be set in ssh */
2690 if (options->version_addendum == NULL)
2691 options->version_addendum = xstrdup(SSH_VERSION_FREEBSD);
2710 free_options(Options *o)
2717 #define FREE_ARRAY(type, n, a) \
2720 for (_i = 0; _i < (n); _i++) \
2724 free(o->forward_agent_sock_path);
2725 free(o->xauth_location);
2726 FREE_ARRAY(u_int, o->num_log_verbose, o->log_verbose);
2727 free(o->log_verbose);
2730 free(o->hostkeyalgorithms);
2731 free(o->kex_algorithms);
2732 free(o->ca_sign_algorithms);
2734 free(o->host_key_alias);
2735 free(o->proxy_command);
2737 FREE_ARRAY(u_int, o->num_system_hostfiles, o->system_hostfiles);
2738 FREE_ARRAY(u_int, o->num_user_hostfiles, o->user_hostfiles);
2739 free(o->preferred_authentications);
2740 free(o->bind_address);
2741 free(o->bind_interface);
2742 free(o->pkcs11_provider);
2743 free(o->sk_provider);
2744 for (i = 0; i < o->num_identity_files; i++) {
2745 free(o->identity_files[i]);
2746 sshkey_free(o->identity_keys[i]);
2748 for (i = 0; i < o->num_certificate_files; i++) {
2749 free(o->certificate_files[i]);
2750 sshkey_free(o->certificates[i]);
2752 free(o->identity_agent);
2753 for (i = 0; i < o->num_local_forwards; i++) {
2754 free(o->local_forwards[i].listen_host);
2755 free(o->local_forwards[i].listen_path);
2756 free(o->local_forwards[i].connect_host);
2757 free(o->local_forwards[i].connect_path);
2759 free(o->local_forwards);
2760 for (i = 0; i < o->num_remote_forwards; i++) {
2761 free(o->remote_forwards[i].listen_host);
2762 free(o->remote_forwards[i].listen_path);
2763 free(o->remote_forwards[i].connect_host);
2764 free(o->remote_forwards[i].connect_path);
2766 free(o->remote_forwards);
2767 free(o->stdio_forward_host);
2768 FREE_ARRAY(int, o->num_send_env, o->send_env);
2770 FREE_ARRAY(int, o->num_setenv, o->setenv);
2772 free(o->control_path);
2773 free(o->local_command);
2774 free(o->remote_command);
2775 FREE_ARRAY(int, o->num_canonical_domains, o->canonical_domains);
2776 for (i = 0; i < o->num_permitted_cnames; i++) {
2777 free(o->permitted_cnames[i].source_list);
2778 free(o->permitted_cnames[i].target_list);
2780 free(o->revoked_host_keys);
2781 free(o->hostbased_accepted_algos);
2782 free(o->pubkey_accepted_algos);
2785 free(o->jump_extra);
2786 free(o->ignored_unknown);
2787 explicit_bzero(o, sizeof(*o));
2798 * parses the next field in a port forwarding specification.
2799 * sets fwd to the parsed field and advances p past the colon
2800 * or sets it to NULL at end of string.
2801 * returns 0 on success, else non-zero.
2804 parse_fwd_field(char **p, struct fwdarg *fwd)
2811 return -1; /* end of string */
2815 * A field escaped with square brackets is used literally.
2816 * XXX - allow ']' to be escaped via backslash?
2819 /* find matching ']' */
2820 for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
2824 /* no matching ']' or not at end of field. */
2825 if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
2827 /* NUL terminate the field and advance p past the colon */
2832 fwd->ispath = ispath;
2837 for (cp = *p; *cp != '\0'; cp++) {
2840 memmove(cp, cp + 1, strlen(cp + 1) + 1);
2854 fwd->ispath = ispath;
2861 * parses a string containing a port forwarding specification of the form:
2863 * [listenhost:]listenport|listenpath:connecthost:connectport|connectpath
2864 * listenpath:connectpath
2866 * [listenhost:]listenport
2867 * returns number of arguments parsed or zero on error
2870 parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
2872 struct fwdarg fwdargs[4];
2876 memset(fwd, 0, sizeof(*fwd));
2877 memset(fwdargs, 0, sizeof(fwdargs));
2880 * We expand environment variables before checking if we think they're
2881 * paths so that if ${VAR} expands to a fully qualified path it is
2882 * treated as a path.
2884 cp = p = dollar_expand(&err, fwdspec);
2885 if (p == NULL || err)
2888 /* skip leading spaces */
2889 while (isspace((u_char)*cp))
2892 for (i = 0; i < 4; ++i) {
2893 if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
2897 /* Check for trailing garbage */
2898 if (cp != NULL && *cp != '\0') {
2899 i = 0; /* failure */
2904 if (fwdargs[0].ispath) {
2905 fwd->listen_path = xstrdup(fwdargs[0].arg);
2906 fwd->listen_port = PORT_STREAMLOCAL;
2908 fwd->listen_host = NULL;
2909 fwd->listen_port = a2port(fwdargs[0].arg);
2911 fwd->connect_host = xstrdup("socks");
2915 if (fwdargs[0].ispath && fwdargs[1].ispath) {
2916 fwd->listen_path = xstrdup(fwdargs[0].arg);
2917 fwd->listen_port = PORT_STREAMLOCAL;
2918 fwd->connect_path = xstrdup(fwdargs[1].arg);
2919 fwd->connect_port = PORT_STREAMLOCAL;
2920 } else if (fwdargs[1].ispath) {
2921 fwd->listen_host = NULL;
2922 fwd->listen_port = a2port(fwdargs[0].arg);
2923 fwd->connect_path = xstrdup(fwdargs[1].arg);
2924 fwd->connect_port = PORT_STREAMLOCAL;
2926 fwd->listen_host = xstrdup(fwdargs[0].arg);
2927 fwd->listen_port = a2port(fwdargs[1].arg);
2928 fwd->connect_host = xstrdup("socks");
2933 if (fwdargs[0].ispath) {
2934 fwd->listen_path = xstrdup(fwdargs[0].arg);
2935 fwd->listen_port = PORT_STREAMLOCAL;
2936 fwd->connect_host = xstrdup(fwdargs[1].arg);
2937 fwd->connect_port = a2port(fwdargs[2].arg);
2938 } else if (fwdargs[2].ispath) {
2939 fwd->listen_host = xstrdup(fwdargs[0].arg);
2940 fwd->listen_port = a2port(fwdargs[1].arg);
2941 fwd->connect_path = xstrdup(fwdargs[2].arg);
2942 fwd->connect_port = PORT_STREAMLOCAL;
2944 fwd->listen_host = NULL;
2945 fwd->listen_port = a2port(fwdargs[0].arg);
2946 fwd->connect_host = xstrdup(fwdargs[1].arg);
2947 fwd->connect_port = a2port(fwdargs[2].arg);
2952 fwd->listen_host = xstrdup(fwdargs[0].arg);
2953 fwd->listen_port = a2port(fwdargs[1].arg);
2954 fwd->connect_host = xstrdup(fwdargs[2].arg);
2955 fwd->connect_port = a2port(fwdargs[3].arg);
2958 i = 0; /* failure */
2964 if (!(i == 1 || i == 2))
2967 if (!(i == 3 || i == 4)) {
2968 if (fwd->connect_path == NULL &&
2969 fwd->listen_path == NULL)
2972 if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
2976 if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
2977 (!remotefwd && fwd->listen_port == 0))
2979 if (fwd->connect_host != NULL &&
2980 strlen(fwd->connect_host) >= NI_MAXHOST)
2983 * XXX - if connecting to a remote socket, max sun len may not
2986 if (fwd->connect_path != NULL &&
2987 strlen(fwd->connect_path) >= PATH_MAX_SUN)
2989 if (fwd->listen_host != NULL &&
2990 strlen(fwd->listen_host) >= NI_MAXHOST)
2992 if (fwd->listen_path != NULL &&
2993 strlen(fwd->listen_path) >= PATH_MAX_SUN)
2999 free(fwd->connect_host);
3000 fwd->connect_host = NULL;
3001 free(fwd->connect_path);
3002 fwd->connect_path = NULL;
3003 free(fwd->listen_host);
3004 fwd->listen_host = NULL;
3005 free(fwd->listen_path);
3006 fwd->listen_path = NULL;
3011 parse_jump(const char *s, Options *o, int active)
3013 char *orig, *sdup, *cp;
3014 char *host = NULL, *user = NULL;
3015 int r, ret = -1, port = -1, first;
3017 active &= o->proxy_command == NULL && o->jump_host == NULL;
3019 orig = sdup = xstrdup(s);
3021 /* Remove comment and trailing whitespace */
3022 if ((cp = strchr(orig, '#')) != NULL)
3028 if (strcasecmp(s, "none") == 0)
3030 if ((cp = strrchr(sdup, ',')) == NULL)
3031 cp = sdup; /* last */
3036 /* First argument and configuration is active */
3037 r = parse_ssh_uri(cp, &user, &host, &port);
3038 if (r == -1 || (r == 1 &&
3039 parse_user_host_port(cp, &user, &host, &port) != 0))
3042 /* Subsequent argument or inactive configuration */
3043 r = parse_ssh_uri(cp, NULL, NULL, NULL);
3044 if (r == -1 || (r == 1 &&
3045 parse_user_host_port(cp, NULL, NULL, NULL) != 0))
3048 first = 0; /* only check syntax for subsequent hosts */
3049 } while (cp != sdup);
3052 if (strcasecmp(s, "none") == 0) {
3053 o->jump_host = xstrdup("none");
3056 o->jump_user = user;
3057 o->jump_host = host;
3058 o->jump_port = port;
3059 o->proxy_command = xstrdup("none");
3061 if ((cp = strrchr(s, ',')) != NULL && cp != s) {
3062 o->jump_extra = xstrdup(s);
3063 o->jump_extra[cp - s] = '\0';
3076 parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp)
3078 char *user = NULL, *host = NULL, *path = NULL;
3081 r = parse_uri("ssh", uri, &user, &host, &port, &path);
3082 if (r == 0 && path != NULL)
3083 r = -1; /* path not allowed */
3085 if (userp != NULL) {
3089 if (hostp != NULL) {
3102 /* XXX the following is a near-vebatim copy from servconf.c; refactor */
3104 fmt_multistate_int(int val, const struct multistate *m)
3108 for (i = 0; m[i].key != NULL; i++) {
3109 if (m[i].value == val)
3116 fmt_intarg(OpCodes code, int val)
3121 case oAddressFamily:
3122 return fmt_multistate_int(val, multistate_addressfamily);
3123 case oVerifyHostKeyDNS:
3124 case oUpdateHostkeys:
3125 return fmt_multistate_int(val, multistate_yesnoask);
3126 case oStrictHostKeyChecking:
3127 return fmt_multistate_int(val, multistate_strict_hostkey);
3128 case oControlMaster:
3129 return fmt_multistate_int(val, multistate_controlmaster);
3131 return fmt_multistate_int(val, multistate_tunnel);
3133 return fmt_multistate_int(val, multistate_requesttty);
3135 return fmt_multistate_int(val, multistate_sessiontype);
3136 case oCanonicalizeHostname:
3137 return fmt_multistate_int(val, multistate_canonicalizehostname);
3138 case oAddKeysToAgent:
3139 return fmt_multistate_int(val, multistate_yesnoaskconfirm);
3140 case oFingerprintHash:
3141 return ssh_digest_alg_name(val);
3155 lookup_opcode_name(OpCodes code)
3159 for (i = 0; keywords[i].name != NULL; i++)
3160 if (keywords[i].opcode == code)
3161 return(keywords[i].name);
3166 dump_cfg_int(OpCodes code, int val)
3168 printf("%s %d\n", lookup_opcode_name(code), val);
3172 dump_cfg_fmtint(OpCodes code, int val)
3174 printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
3178 dump_cfg_string(OpCodes code, const char *val)
3182 printf("%s %s\n", lookup_opcode_name(code), val);
3186 dump_cfg_strarray(OpCodes code, u_int count, char **vals)
3190 for (i = 0; i < count; i++)
3191 printf("%s %s\n", lookup_opcode_name(code), vals[i]);
3195 dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
3199 printf("%s", lookup_opcode_name(code));
3202 for (i = 0; i < count; i++)
3203 printf(" %s", vals[i]);
3208 dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
3210 const struct Forward *fwd;
3213 /* oDynamicForward */
3214 for (i = 0; i < count; i++) {
3216 if (code == oDynamicForward && fwd->connect_host != NULL &&
3217 strcmp(fwd->connect_host, "socks") != 0)
3219 if (code == oLocalForward && fwd->connect_host != NULL &&
3220 strcmp(fwd->connect_host, "socks") == 0)
3222 printf("%s", lookup_opcode_name(code));
3223 if (fwd->listen_port == PORT_STREAMLOCAL)
3224 printf(" %s", fwd->listen_path);
3225 else if (fwd->listen_host == NULL)
3226 printf(" %d", fwd->listen_port);
3229 fwd->listen_host, fwd->listen_port);
3231 if (code != oDynamicForward) {
3232 if (fwd->connect_port == PORT_STREAMLOCAL)
3233 printf(" %s", fwd->connect_path);
3234 else if (fwd->connect_host == NULL)
3235 printf(" %d", fwd->connect_port);
3238 fwd->connect_host, fwd->connect_port);
3246 dump_client_config(Options *o, const char *host)
3249 char buf[8], *all_key;
3252 * Expand HostKeyAlgorithms name lists. This isn't handled in
3253 * fill_default_options() like the other algorithm lists because
3254 * the host key algorithms are by default dynamically chosen based
3255 * on the host's keys found in known_hosts.
3257 all_key = sshkey_alg_list(0, 0, 1, ',');
3258 if ((r = kex_assemble_names(&o->hostkeyalgorithms, kex_default_pk_alg(),
3260 fatal_fr(r, "expand HostKeyAlgorithms");
3263 /* Most interesting options first: user, host, port */
3264 dump_cfg_string(oUser, o->user);
3265 dump_cfg_string(oHostname, host);
3266 dump_cfg_int(oPort, o->port);
3269 dump_cfg_fmtint(oAddressFamily, o->address_family);
3270 dump_cfg_fmtint(oBatchMode, o->batch_mode);
3271 dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
3272 dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
3273 dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
3274 dump_cfg_fmtint(oCompression, o->compression);
3275 dump_cfg_fmtint(oControlMaster, o->control_master);
3276 dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
3277 dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
3278 dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
3279 dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
3280 dump_cfg_fmtint(oForwardX11, o->forward_x11);
3281 dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
3282 dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
3284 dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
3285 dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
3287 dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
3288 dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
3289 dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
3290 dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
3291 dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
3292 dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
3293 dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
3294 dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
3295 dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
3296 dump_cfg_fmtint(oRequestTTY, o->request_tty);
3297 dump_cfg_fmtint(oSessionType, o->session_type);
3298 dump_cfg_fmtint(oStdinNull, o->stdin_null);
3299 dump_cfg_fmtint(oForkAfterAuthentication, o->fork_after_authentication);
3300 dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
3301 dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
3302 dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
3303 dump_cfg_fmtint(oTunnel, o->tun_open);
3304 dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
3305 dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
3306 dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
3308 /* Integer options */
3309 dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
3310 dump_cfg_int(oConnectionAttempts, o->connection_attempts);
3311 dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
3312 dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
3313 dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
3314 dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
3316 /* String options */
3317 dump_cfg_string(oBindAddress, o->bind_address);
3318 dump_cfg_string(oBindInterface, o->bind_interface);
3319 dump_cfg_string(oCiphers, o->ciphers);
3320 dump_cfg_string(oControlPath, o->control_path);
3321 dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
3322 dump_cfg_string(oHostKeyAlias, o->host_key_alias);
3323 dump_cfg_string(oHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
3324 dump_cfg_string(oIdentityAgent, o->identity_agent);
3325 dump_cfg_string(oIgnoreUnknown, o->ignored_unknown);
3326 dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
3327 dump_cfg_string(oKexAlgorithms, o->kex_algorithms);
3328 dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms);
3329 dump_cfg_string(oLocalCommand, o->local_command);
3330 dump_cfg_string(oRemoteCommand, o->remote_command);
3331 dump_cfg_string(oLogLevel, log_level_name(o->log_level));
3332 dump_cfg_string(oMacs, o->macs);
3333 #ifdef ENABLE_PKCS11
3334 dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
3336 dump_cfg_string(oSecurityKeyProvider, o->sk_provider);
3337 dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
3338 dump_cfg_string(oPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
3339 dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
3340 dump_cfg_string(oXAuthLocation, o->xauth_location);
3341 dump_cfg_string(oKnownHostsCommand, o->known_hosts_command);
3344 dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
3345 dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
3346 dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
3348 /* String array options */
3349 dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
3350 dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
3351 dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files);
3352 dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
3353 dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
3354 dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
3355 dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv);
3356 dump_cfg_strarray_oneline(oLogVerbose,
3357 o->num_log_verbose, o->log_verbose);
3361 /* PermitRemoteOpen */
3362 if (o->num_permitted_remote_opens == 0)
3363 printf("%s any\n", lookup_opcode_name(oPermitRemoteOpen));
3365 dump_cfg_strarray_oneline(oPermitRemoteOpen,
3366 o->num_permitted_remote_opens, o->permitted_remote_opens);
3368 /* AddKeysToAgent */
3369 if (o->add_keys_to_agent_lifespan <= 0)
3370 dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent);
3372 printf("addkeystoagent%s %d\n",
3373 o->add_keys_to_agent == 3 ? " confirm" : "",
3374 o->add_keys_to_agent_lifespan);
3378 if (o->forward_agent_sock_path == NULL)
3379 dump_cfg_fmtint(oForwardAgent, o->forward_agent);
3381 dump_cfg_string(oForwardAgent, o->forward_agent_sock_path);
3383 /* oConnectTimeout */
3384 if (o->connection_timeout == -1)
3385 printf("connecttimeout none\n");
3387 dump_cfg_int(oConnectTimeout, o->connection_timeout);
3390 printf("tunneldevice");
3391 if (o->tun_local == SSH_TUNID_ANY)
3394 printf(" %d", o->tun_local);
3395 if (o->tun_remote == SSH_TUNID_ANY)
3398 printf(":%d", o->tun_remote);
3401 /* oCanonicalizePermittedCNAMEs */
3402 if ( o->num_permitted_cnames > 0) {
3403 printf("canonicalizePermittedcnames");
3404 for (i = 0; i < o->num_permitted_cnames; i++) {
3405 printf(" %s:%s", o->permitted_cnames[i].source_list,
3406 o->permitted_cnames[i].target_list);
3411 /* oControlPersist */
3412 if (o->control_persist == 0 || o->control_persist_timeout == 0)
3413 dump_cfg_fmtint(oControlPersist, o->control_persist);
3415 dump_cfg_int(oControlPersist, o->control_persist_timeout);
3418 if (o->escape_char == SSH_ESCAPECHAR_NONE)
3419 printf("escapechar none\n");
3421 vis(buf, o->escape_char, VIS_WHITE, 0);
3422 printf("escapechar %s\n", buf);
3426 printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
3427 printf("%s\n", iptos2str(o->ip_qos_bulk));
3430 printf("rekeylimit %llu %d\n",
3431 (unsigned long long)o->rekey_limit, o->rekey_interval);
3433 /* oStreamLocalBindMask */
3434 printf("streamlocalbindmask 0%o\n",
3435 o->fwd_opts.streamlocal_bind_mask);
3438 printf("syslogfacility %s\n", log_facility_name(o->log_facility));
3440 /* oProxyCommand / oProxyJump */
3441 if (o->jump_host == NULL)
3442 dump_cfg_string(oProxyCommand, o->proxy_command);
3444 /* Check for numeric addresses */
3445 i = strchr(o->jump_host, ':') != NULL ||
3446 strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
3447 snprintf(buf, sizeof(buf), "%d", o->jump_port);
3448 printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
3449 /* optional additional jump spec */
3450 o->jump_extra == NULL ? "" : o->jump_extra,
3451 o->jump_extra == NULL ? "" : ",",
3453 o->jump_user == NULL ? "" : o->jump_user,
3454 o->jump_user == NULL ? "" : "@",
3455 /* opening [ if hostname is numeric */
3457 /* mandatory hostname */
3459 /* closing ] if hostname is numeric */
3461 /* optional port number */
3462 o->jump_port <= 0 ? "" : ":",
3463 o->jump_port <= 0 ? "" : buf);