readconf.c revision 1.50 1 /* $NetBSD: readconf.c,v 1.50 2025/10/11 15:45:07 christos Exp $ */
2 /* $OpenBSD: readconf.c,v 1.406 2025/08/29 03:50:38 djm Exp $ */
3
4 /*
5 * Author: Tatu Ylonen <ylo (at) cs.hut.fi>
6 * Copyright (c) 1995 Tatu Ylonen <ylo (at) cs.hut.fi>, Espoo, Finland
7 * All rights reserved
8 * Functions for reading the configuration files.
9 *
10 * As far as I am concerned, the code I have written for this software
11 * can be used freely for any purpose. Any derived versions of this
12 * software must be clearly marked as such, and if the derived work is
13 * incompatible with the protocol description in the RFC file, it must be
14 * called by a name other than "ssh" or "Secure Shell".
15 */
16
17 #include "includes.h"
18 __RCSID("$NetBSD: readconf.c,v 1.50 2025/10/11 15:45:07 christos Exp $");
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/socket.h>
22 #include <sys/wait.h>
23 #include <sys/un.h>
24
25 #include <net/if.h>
26 #include <netinet/in.h>
27 #include <netinet/ip.h>
28
29 #include <ctype.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <glob.h>
33 #include <ifaddrs.h>
34 #include <netdb.h>
35 #include <paths.h>
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 #include <limits.h>
43 #include <util.h>
44 #include <vis.h>
45
46 #include "xmalloc.h"
47 #include "ssh.h"
48 #include "sshbuf.h"
49 #include "ssherr.h"
50 #include "cipher.h"
51 #include "pathnames.h"
52 #include "log.h"
53 #include "sshkey.h"
54 #include "misc.h"
55 #include "readconf.h"
56 #include "match.h"
57 #include "kex.h"
58 #include "mac.h"
59 #include "fmt_scaled.h"
60 #include "uidswap.h"
61 #include "myproposal.h"
62 #include "digest.h"
63 #include "version.h"
64
65 /* Format of the configuration file:
66
67 # Configuration data is parsed as follows:
68 # 1. command line options
69 # 2. user-specific file
70 # 3. system-wide file
71 # Any configuration value is only changed the first time it is set.
72 # Thus, host-specific definitions should be at the beginning of the
73 # configuration file, and defaults at the end.
74
75 # Host-specific declarations. These may override anything above. A single
76 # host may match multiple declarations; these are processed in the order
77 # that they are given in.
78
79 Host *.ngs.fi ngs.fi
80 User foo
81
82 Host fake.com
83 Hostname another.host.name.real.org
84 User blaah
85 Port 34289
86 ForwardX11 no
87 ForwardAgent no
88
89 Host books.com
90 RemoteForward 9999 shadows.cs.hut.fi:9999
91 Ciphers 3des-cbc
92
93 Host fascist.blob.com
94 Port 23123
95 User tylonen
96 PasswordAuthentication no
97
98 Host puukko.hut.fi
99 User t35124p
100 ProxyCommand ssh-proxy %h %p
101
102 Host *.fr
103 PublicKeyAuthentication no
104
105 Host *.su
106 Ciphers aes128-ctr
107 PasswordAuthentication no
108
109 Host vpn.fake.com
110 Tunnel yes
111 TunnelDevice 3
112
113 # Defaults for various options
114 Host *
115 ForwardAgent no
116 ForwardX11 no
117 PasswordAuthentication yes
118 StrictHostKeyChecking yes
119 TcpKeepAlive no
120 IdentityFile ~/.ssh/identity
121 Port 22
122 EscapeChar ~
123
124 */
125
126 static int read_config_file_depth(const char *filename, struct passwd *pw,
127 const char *host, const char *original_host, const char *remote_command,
128 Options *options, int flags, int *activep, int *want_final_pass, int depth);
129 static int process_config_line_depth(Options *options, struct passwd *pw,
130 const char *host, const char *original_host, const char *remote_command,
131 char *line, const char *filename, int linenum, int *activep, int flags,
132 int *want_final_pass, int depth);
133
134 /* Keyword tokens. */
135
136 typedef enum {
137 oBadOption,
138 oHost, oMatch, oInclude, oTag,
139 oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
140 oGatewayPorts, oExitOnForwardFailure,
141 oPasswordAuthentication,
142 oXAuthLocation,
143 #if defined(KRB4) || defined(KRB5)
144 oKerberosAuthentication,
145 #endif
146 #if defined(AFS) || defined(KRB5)
147 oKerberosTgtPassing,
148 #endif
149 #ifdef AFS
150 oAFSTokenPassing,
151 #endif
152 oIdentityFile, oHostname, oPort, oRemoteForward, oLocalForward,
153 oPermitRemoteOpen,
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 oIPv6PreferTemporary,
165 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
166 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
167 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
168 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
169 oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist,
170 oHashKnownHosts,
171 oTunnel, oTunnelDevice,
172 oLocalCommand, oPermitLocalCommand, oRemoteCommand,
173 oVisualHostKey,
174 oKexAlgorithms, oIPQoS, oRequestTTY, oSessionType, oStdinNull,
175 oForkAfterAuthentication, oIgnoreUnknown, oProxyUseFdpass,
176 oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
177 oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
178 oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
179 oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
180 oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
181 oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize,
182 oEnableEscapeCommandline, oObscureKeystrokeTiming, oChannelTimeout,
183 oVersionAddendum, oRefuseConnection, oWarnWeakCrypto,
184 oNoneEnabled, oTcpRcvBufPoll, oTcpRcvBuf, oNoneSwitch, oHPNDisabled,
185 oHPNBufferSize,
186 oSendVersionFirst,
187 oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
188 } OpCodes;
189
190 /* Textual representations of the tokens. */
191
192 static struct {
193 const char *name;
194 OpCodes opcode;
195 } keywords[] = {
196 /* Deprecated options */
197 { "protocol", oIgnore }, /* NB. silently ignored */
198 { "cipher", oDeprecated },
199 { "fallbacktorsh", oDeprecated },
200 { "globalknownhostsfile2", oDeprecated },
201 { "rhostsauthentication", oDeprecated },
202 { "userknownhostsfile2", oDeprecated },
203 { "useroaming", oDeprecated },
204 { "usersh", oDeprecated },
205 { "useprivilegedport", oDeprecated },
206
207 /* Unsupported options */
208 #ifdef AFS
209 { "afstokenpassing", oAFSTokenPassing },
210 #else
211 { "afstokenpassing", oUnsupported },
212 #endif
213 #if defined(KRB4) || defined(KRB5)
214 { "kerberosauthentication", oKerberosAuthentication },
215 #else
216 { "kerberosauthentication", oUnsupported },
217 #endif
218 #if defined(AFS) || defined(KRB5)
219 { "kerberostgtpassing", oKerberosTgtPassing },
220 { "kerberos5tgtpassing", oKerberosTgtPassing }, /* alias */
221 { "kerberos4tgtpassing", oKerberosTgtPassing }, /* alias */
222 #else
223 { "kerberostgtpassing", oUnsupported },
224 { "kerberos5tgtpassing", oUnsupported },
225 { "kerberos4tgtpassing", oUnsupported },
226 #endif
227 { "rsaauthentication", oUnsupported },
228 { "rhostsrsaauthentication", oUnsupported },
229 { "compressionlevel", oUnsupported },
230
231 /* Sometimes-unsupported options */
232 #if defined(GSSAPI)
233 { "gssapiauthentication", oGssAuthentication },
234 { "gssapidelegatecredentials", oGssDelegateCreds },
235 # else
236 { "gssapiauthentication", oUnsupported },
237 { "gssapidelegatecredentials", oUnsupported },
238 #endif
239 #ifdef ENABLE_PKCS11
240 { "pkcs11provider", oPKCS11Provider },
241 { "smartcarddevice", oPKCS11Provider },
242 # else
243 { "smartcarddevice", oUnsupported },
244 { "pkcs11provider", oUnsupported },
245 #endif
246
247 { "forwardagent", oForwardAgent },
248 { "forwardx11", oForwardX11 },
249 { "forwardx11trusted", oForwardX11Trusted },
250 { "forwardx11timeout", oForwardX11Timeout },
251 { "exitonforwardfailure", oExitOnForwardFailure },
252 { "xauthlocation", oXAuthLocation },
253 { "gatewayports", oGatewayPorts },
254 { "passwordauthentication", oPasswordAuthentication },
255 { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
256 { "kbdinteractivedevices", oKbdInteractiveDevices },
257 { "challengeresponseauthentication", oKbdInteractiveAuthentication }, /* alias */
258 { "skeyauthentication", oKbdInteractiveAuthentication }, /* alias */
259 { "tisauthentication", oKbdInteractiveAuthentication }, /* alias */
260 { "pubkeyauthentication", oPubkeyAuthentication },
261 { "dsaauthentication", oPubkeyAuthentication }, /* alias */
262 { "hostbasedauthentication", oHostbasedAuthentication },
263 #if defined(GSSAPI)
264 { "gssapiauthentication", oGssAuthentication },
265 { "gssapidelegatecredentials", oGssDelegateCreds },
266 #else
267 { "gssapiauthentication", oUnsupported },
268 { "gssapidelegatecredentials", oUnsupported },
269 #endif
270 { "identityfile", oIdentityFile },
271 { "identityfile2", oIdentityFile }, /* obsolete */
272 { "identitiesonly", oIdentitiesOnly },
273 { "certificatefile", oCertificateFile },
274 { "addkeystoagent", oAddKeysToAgent },
275 { "identityagent", oIdentityAgent },
276 { "hostname", oHostname },
277 { "hostkeyalias", oHostKeyAlias },
278 { "proxycommand", oProxyCommand },
279 { "port", oPort },
280 { "ciphers", oCiphers },
281 { "macs", oMacs },
282 { "remoteforward", oRemoteForward },
283 { "localforward", oLocalForward },
284 { "permitremoteopen", oPermitRemoteOpen },
285 { "user", oUser },
286 { "host", oHost },
287 { "match", oMatch },
288 { "tag", oTag },
289 { "escapechar", oEscapeChar },
290 { "globalknownhostsfile", oGlobalKnownHostsFile },
291 { "userknownhostsfile", oUserKnownHostsFile },
292 { "connectionattempts", oConnectionAttempts },
293 { "batchmode", oBatchMode },
294 { "checkhostip", oCheckHostIP },
295 { "stricthostkeychecking", oStrictHostKeyChecking },
296 { "compression", oCompression },
297 { "tcpkeepalive", oTCPKeepAlive },
298 { "keepalive", oTCPKeepAlive }, /* obsolete */
299 { "numberofpasswordprompts", oNumberOfPasswordPrompts },
300 { "syslogfacility", oLogFacility },
301 { "loglevel", oLogLevel },
302 { "logverbose", oLogVerbose },
303 { "dynamicforward", oDynamicForward },
304 { "preferredauthentications", oPreferredAuthentications },
305 { "hostkeyalgorithms", oHostKeyAlgorithms },
306 { "casignaturealgorithms", oCASignatureAlgorithms },
307 { "bindaddress", oBindAddress },
308 { "bindinterface", oBindInterface },
309 { "ipv6prefertemporary", oIPv6PreferTemporary },
310 { "clearallforwardings", oClearAllForwardings },
311 { "enablesshkeysign", oEnableSSHKeysign },
312 { "verifyhostkeydns", oVerifyHostKeyDNS },
313 { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
314 { "rekeylimit", oRekeyLimit },
315 { "connecttimeout", oConnectTimeout },
316 { "addressfamily", oAddressFamily },
317 { "serveraliveinterval", oServerAliveInterval },
318 { "serveralivecountmax", oServerAliveCountMax },
319 { "sendenv", oSendEnv },
320 { "setenv", oSetEnv },
321 { "controlpath", oControlPath },
322 { "controlmaster", oControlMaster },
323 { "controlpersist", oControlPersist },
324 { "hashknownhosts", oHashKnownHosts },
325 { "include", oInclude },
326 { "tunnel", oTunnel },
327 { "tunneldevice", oTunnelDevice },
328 { "localcommand", oLocalCommand },
329 { "permitlocalcommand", oPermitLocalCommand },
330 { "remotecommand", oRemoteCommand },
331 { "visualhostkey", oVisualHostKey },
332 { "kexalgorithms", oKexAlgorithms },
333 { "ipqos", oIPQoS },
334 { "requesttty", oRequestTTY },
335 { "sessiontype", oSessionType },
336 { "stdinnull", oStdinNull },
337 { "forkafterauthentication", oForkAfterAuthentication },
338 { "proxyusefdpass", oProxyUseFdpass },
339 { "canonicaldomains", oCanonicalDomains },
340 { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
341 { "canonicalizehostname", oCanonicalizeHostname },
342 { "canonicalizemaxdots", oCanonicalizeMaxDots },
343 { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
344 { "streamlocalbindmask", oStreamLocalBindMask },
345 { "streamlocalbindunlink", oStreamLocalBindUnlink },
346 { "revokedhostkeys", oRevokedHostKeys },
347 { "fingerprinthash", oFingerprintHash },
348 { "updatehostkeys", oUpdateHostkeys },
349 { "hostbasedacceptedalgorithms", oHostbasedAcceptedAlgorithms },
350 { "hostbasedkeytypes", oHostbasedAcceptedAlgorithms }, /* obsolete */
351 { "pubkeyacceptedalgorithms", oPubkeyAcceptedAlgorithms },
352 { "pubkeyacceptedkeytypes", oPubkeyAcceptedAlgorithms }, /* obsolete */
353 { "proxyjump", oProxyJump },
354 { "noneenabled", oNoneEnabled },
355 { "tcprcvbufpoll", oTcpRcvBufPoll },
356 { "tcprcvbuf", oTcpRcvBuf },
357 { "noneswitch", oNoneSwitch },
358 { "hpndisabled", oHPNDisabled },
359 { "hpnbuffersize", oHPNBufferSize },
360 { "sendversionfirst", oSendVersionFirst },
361 { "ignoreunknown", oIgnoreUnknown },
362 { "proxyjump", oProxyJump },
363 { "securitykeyprovider", oSecurityKeyProvider },
364 { "knownhostscommand", oKnownHostsCommand },
365 { "requiredrsasize", oRequiredRSASize },
366 { "enableescapecommandline", oEnableEscapeCommandline },
367 { "obscurekeystroketiming", oObscureKeystrokeTiming },
368 { "channeltimeout", oChannelTimeout },
369 { "versionaddendum", oVersionAddendum },
370 { "refuseconnection", oRefuseConnection },
371 { "warnweakcrypto", oWarnWeakCrypto },
372
373 { NULL, oBadOption }
374 };
375
376 static const char *lookup_opcode_name(OpCodes code);
377
378 const char *
379 kex_default_pk_alg(void)
380 {
381 static char *pkalgs;
382
383 if (pkalgs == NULL) {
384 char *all_key;
385
386 all_key = sshkey_alg_list(0, 0, 1, ',');
387 pkalgs = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
388 free(all_key);
389 }
390 return pkalgs;
391 }
392
393 char *
394 ssh_connection_hash(const char *thishost, const char *host, const char *portstr,
395 const char *user, const char *jumphost)
396 {
397 struct ssh_digest_ctx *md;
398 u_char conn_hash[SSH_DIGEST_MAX_LENGTH];
399
400 if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL ||
401 ssh_digest_update(md, thishost, strlen(thishost)) < 0 ||
402 ssh_digest_update(md, host, strlen(host)) < 0 ||
403 ssh_digest_update(md, portstr, strlen(portstr)) < 0 ||
404 ssh_digest_update(md, user, strlen(user)) < 0 ||
405 ssh_digest_update(md, jumphost, strlen(jumphost)) < 0 ||
406 ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0)
407 fatal_f("mux digest failed");
408 ssh_digest_free(md);
409 return tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1));
410 }
411
412 /*
413 * Adds a local TCP/IP port forward to options. Never returns if there is an
414 * error.
415 */
416
417 void
418 add_local_forward(Options *options, const struct Forward *newfwd)
419 {
420 struct Forward *fwd;
421 int i;
422
423 /* Don't add duplicates */
424 for (i = 0; i < options->num_local_forwards; i++) {
425 if (forward_equals(newfwd, options->local_forwards + i))
426 return;
427 }
428 options->local_forwards = xreallocarray(options->local_forwards,
429 options->num_local_forwards + 1,
430 sizeof(*options->local_forwards));
431 fwd = &options->local_forwards[options->num_local_forwards++];
432
433 fwd->listen_host = newfwd->listen_host;
434 fwd->listen_port = newfwd->listen_port;
435 fwd->listen_path = newfwd->listen_path;
436 fwd->connect_host = newfwd->connect_host;
437 fwd->connect_port = newfwd->connect_port;
438 fwd->connect_path = newfwd->connect_path;
439 }
440
441 /*
442 * Adds a remote TCP/IP port forward to options. Never returns if there is
443 * an error.
444 */
445
446 void
447 add_remote_forward(Options *options, const struct Forward *newfwd)
448 {
449 struct Forward *fwd;
450 int i;
451
452 /* Don't add duplicates */
453 for (i = 0; i < options->num_remote_forwards; i++) {
454 if (forward_equals(newfwd, options->remote_forwards + i))
455 return;
456 }
457 options->remote_forwards = xreallocarray(options->remote_forwards,
458 options->num_remote_forwards + 1,
459 sizeof(*options->remote_forwards));
460 fwd = &options->remote_forwards[options->num_remote_forwards++];
461
462 fwd->listen_host = newfwd->listen_host;
463 fwd->listen_port = newfwd->listen_port;
464 fwd->listen_path = newfwd->listen_path;
465 fwd->connect_host = newfwd->connect_host;
466 fwd->connect_port = newfwd->connect_port;
467 fwd->connect_path = newfwd->connect_path;
468 fwd->handle = newfwd->handle;
469 fwd->allocated_port = 0;
470 }
471
472 static void
473 clear_forwardings(Options *options)
474 {
475 int i;
476
477 for (i = 0; i < options->num_local_forwards; i++) {
478 free(options->local_forwards[i].listen_host);
479 free(options->local_forwards[i].listen_path);
480 free(options->local_forwards[i].connect_host);
481 free(options->local_forwards[i].connect_path);
482 }
483 if (options->num_local_forwards > 0) {
484 free(options->local_forwards);
485 options->local_forwards = NULL;
486 }
487 options->num_local_forwards = 0;
488 for (i = 0; i < options->num_remote_forwards; i++) {
489 free(options->remote_forwards[i].listen_host);
490 free(options->remote_forwards[i].listen_path);
491 free(options->remote_forwards[i].connect_host);
492 free(options->remote_forwards[i].connect_path);
493 }
494 if (options->num_remote_forwards > 0) {
495 free(options->remote_forwards);
496 options->remote_forwards = NULL;
497 }
498 options->num_remote_forwards = 0;
499 options->tun_open = SSH_TUNMODE_NO;
500 }
501
502 void
503 add_certificate_file(Options *options, const char *path, int userprovided)
504 {
505 int i;
506
507 if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
508 fatal("Too many certificate files specified (max %d)",
509 SSH_MAX_CERTIFICATE_FILES);
510
511 /* Avoid registering duplicates */
512 for (i = 0; i < options->num_certificate_files; i++) {
513 if (options->certificate_file_userprovided[i] == userprovided &&
514 strcmp(options->certificate_files[i], path) == 0) {
515 debug2_f("ignoring duplicate key %s", path);
516 return;
517 }
518 }
519
520 options->certificate_file_userprovided[options->num_certificate_files] =
521 userprovided;
522 options->certificate_files[options->num_certificate_files++] =
523 xstrdup(path);
524 }
525
526 void
527 add_identity_file(Options *options, const char *dir, const char *filename,
528 int userprovided)
529 {
530 char *path;
531 int i;
532
533 if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
534 fatal("Too many identity files specified (max %d)",
535 SSH_MAX_IDENTITY_FILES);
536
537 if (dir == NULL) /* no dir, filename is absolute */
538 path = xstrdup(filename);
539 else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX)
540 fatal("Identity file path %s too long", path);
541
542 /* Avoid registering duplicates */
543 for (i = 0; i < options->num_identity_files; i++) {
544 if (options->identity_file_userprovided[i] == userprovided &&
545 strcmp(options->identity_files[i], path) == 0) {
546 debug2_f("ignoring duplicate key %s", path);
547 free(path);
548 return;
549 }
550 }
551
552 options->identity_file_userprovided[options->num_identity_files] =
553 userprovided;
554 options->identity_files[options->num_identity_files++] = path;
555 }
556
557 int
558 default_ssh_port(void)
559 {
560 static int port;
561 struct servent *sp;
562
563 if (port == 0) {
564 sp = getservbyname(SSH_SERVICE_NAME, "tcp");
565 port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
566 }
567 return port;
568 }
569
570 /*
571 * Execute a command in a shell.
572 * Return its exit status or -1 on abnormal exit.
573 */
574 static int
575 execute_in_shell(const char *cmd)
576 {
577 const char *shell;
578 pid_t pid;
579 int status;
580
581 if ((shell = getenv("SHELL")) == NULL)
582 shell = _PATH_BSHELL;
583
584 if (access(shell, X_OK) == -1) {
585 fatal("Shell \"%s\" is not executable: %s",
586 shell, strerror(errno));
587 }
588
589 debug("Executing command: '%.500s'", cmd);
590
591 /* Fork and execute the command. */
592 if ((pid = fork()) == 0) {
593 char *argv[4];
594
595 if (stdfd_devnull(1, 1, 0) == -1)
596 fatal_f("stdfd_devnull failed");
597 closefrom(STDERR_FILENO + 1);
598
599 argv[0] = __UNCONST(shell);
600 argv[1] = __UNCONST("-c");
601 argv[2] = xstrdup(cmd);
602 argv[3] = NULL;
603
604 execv(argv[0], argv);
605 error("Unable to execute '%.100s': %s", cmd, strerror(errno));
606 /* Die with signal to make this error apparent to parent. */
607 ssh_signal(SIGTERM, SIG_DFL);
608 kill(getpid(), SIGTERM);
609 _exit(1);
610 }
611 /* Parent. */
612 if (pid == -1)
613 fatal_f("fork: %.100s", strerror(errno));
614
615 while (waitpid(pid, &status, 0) == -1) {
616 if (errno != EINTR && errno != EAGAIN)
617 fatal_f("waitpid: %s", strerror(errno));
618 }
619 if (!WIFEXITED(status)) {
620 error("command '%.100s' exited abnormally", cmd);
621 return -1;
622 }
623 debug3("command returned status %d", WEXITSTATUS(status));
624 return WEXITSTATUS(status);
625 }
626
627 /*
628 * Check whether a local network interface address appears in CIDR pattern-
629 * list 'addrlist'. Returns 1 if matched or 0 otherwise.
630 */
631 static int
632 check_match_ifaddrs(const char *addrlist)
633 {
634 struct ifaddrs *ifa, *ifaddrs = NULL;
635 int r, found = 0;
636 char addr[NI_MAXHOST];
637 socklen_t salen;
638
639 if (getifaddrs(&ifaddrs) != 0) {
640 error("match localnetwork: getifaddrs failed: %s",
641 strerror(errno));
642 return 0;
643 }
644 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
645 if (ifa->ifa_addr == NULL || ifa->ifa_name == NULL ||
646 (ifa->ifa_flags & IFF_UP) == 0)
647 continue;
648 switch (ifa->ifa_addr->sa_family) {
649 case AF_INET:
650 salen = sizeof(struct sockaddr_in);
651 break;
652 case AF_INET6:
653 salen = sizeof(struct sockaddr_in6);
654 break;
655 case AF_LINK:
656 /* ignore */
657 continue;
658 default:
659 debug2_f("interface %s: unsupported address family %d",
660 ifa->ifa_name, ifa->ifa_addr->sa_family);
661 continue;
662 }
663 if ((r = getnameinfo(ifa->ifa_addr, salen, addr, sizeof(addr),
664 NULL, 0, NI_NUMERICHOST)) != 0) {
665 debug2_f("interface %s getnameinfo failed: %s",
666 ifa->ifa_name, gai_strerror(r));
667 continue;
668 }
669 debug3_f("interface %s addr %s", ifa->ifa_name, addr);
670 if (addr_match_cidr_list(addr, addrlist) == 1) {
671 debug3_f("matched interface %s: address %s in %s",
672 ifa->ifa_name, addr, addrlist);
673 found = 1;
674 break;
675 }
676 }
677 freeifaddrs(ifaddrs);
678 return found;
679 }
680
681 /*
682 * Expand a "match exec" command or an Include path, caller must free returned
683 * value.
684 */
685 static char *
686 expand_match_exec_or_include_path(const char *path, Options *options,
687 struct passwd *pw, const char *host_arg, const char *original_host,
688 int final_pass, int is_include_path)
689 {
690 char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
691 char uidstr[32], *conn_hash_hex, *keyalias, *ruser;
692 const char *jmphost;
693 char *host, *ret;
694 int port;
695
696 port = options->port <= 0 ? default_ssh_port() : options->port;
697 ruser = options->user == NULL ? pw->pw_name : options->user;
698 if (final_pass) {
699 host = xstrdup(options->hostname);
700 } else if (options->hostname != NULL) {
701 /* NB. Please keep in sync with ssh.c:main() */
702 host = percent_expand(options->hostname,
703 "h", host_arg, (char *)NULL);
704 } else {
705 host = xstrdup(host_arg);
706 }
707 if (gethostname(thishost, sizeof(thishost)) == -1)
708 fatal("gethostname: %s", strerror(errno));
709 jmphost = option_clear_or_none(options->jump_host) ?
710 "" : options->jump_host;
711 strlcpy(shorthost, thishost, sizeof(shorthost));
712 shorthost[strcspn(thishost, ".")] = '\0';
713 snprintf(portstr, sizeof(portstr), "%d", port);
714 snprintf(uidstr, sizeof(uidstr), "%llu",
715 (unsigned long long)pw->pw_uid);
716 conn_hash_hex = ssh_connection_hash(thishost, host,
717 portstr, ruser, jmphost);
718 keyalias = options->host_key_alias ? options->host_key_alias : host;
719
720 ret = (is_include_path ? percent_dollar_expand : percent_expand)(path,
721 "C", conn_hash_hex,
722 "L", shorthost,
723 "d", pw->pw_dir,
724 "h", host,
725 "k", keyalias,
726 "l", thishost,
727 "n", original_host,
728 "p", portstr,
729 "r", ruser,
730 "u", pw->pw_name,
731 "i", uidstr,
732 "j", jmphost,
733 (char *)NULL);
734 free(host);
735 free(conn_hash_hex);
736 return ret;
737 }
738
739 /*
740 * Parse and execute a Match directive.
741 */
742 static int
743 match_cfg_line(Options *options, const char *full_line, int *acp, char ***avp,
744 struct passwd *pw, const char *host_arg, const char *original_host,
745 const char *remote_command, int final_pass, int *want_final_pass,
746 const char *filename, int linenum)
747 {
748 char *arg, *oattrib = NULL, *attrib = NULL, *cmd, *host, *criteria;
749 const char *ruser;
750 int r, this_result, result = 1, attributes = 0, negate;
751
752 /*
753 * Configuration is likely to be incomplete at this point so we
754 * must be prepared to use default values.
755 */
756 ruser = options->user == NULL ? pw->pw_name : options->user;
757 if (final_pass) {
758 host = xstrdup(options->hostname);
759 } else if (options->hostname != NULL) {
760 /* NB. Please keep in sync with ssh.c:main() */
761 host = percent_expand(options->hostname,
762 "h", host_arg, (char *)NULL);
763 } else {
764 host = xstrdup(host_arg);
765 }
766
767 debug2("checking match for '%s' host %s originally %s",
768 full_line, host, original_host);
769 while ((attrib = argv_next(acp, avp)) != NULL) {
770 attrib = oattrib = xstrdup(attrib);
771 /* Terminate on comment */
772 if (*attrib == '#') {
773 argv_consume(acp);
774 break;
775 }
776 arg = criteria = NULL;
777 this_result = 1;
778 if ((negate = (attrib[0] == '!')))
779 attrib++;
780 /* Criterion "all" has no argument and must appear alone */
781 if (strcasecmp(attrib, "all") == 0) {
782 if (attributes > 1 ||
783 ((arg = argv_next(acp, avp)) != NULL &&
784 *arg != '\0' && *arg != '#')) {
785 error("%.200s line %d: '%s' cannot be combined "
786 "with other Match attributes",
787 filename, linenum, oattrib);
788 result = -1;
789 goto out;
790 }
791 if (arg != NULL && *arg == '#')
792 argv_consume(acp); /* consume remaining args */
793 if (result)
794 result = negate ? 0 : 1;
795 goto out;
796 }
797 attributes++;
798 /* criteria "final" and "canonical" have no argument */
799 if (strcasecmp(attrib, "canonical") == 0 ||
800 strcasecmp(attrib, "final") == 0) {
801 /*
802 * If the config requests "Match final" without
803 * negation then remember this so we can perform a
804 * second pass later.
805 */
806 if (strcasecmp(attrib, "final") == 0 &&
807 want_final_pass != NULL)
808 *want_final_pass |= !negate;
809 r = !!final_pass; /* force bitmask member to boolean */
810 if (r == (negate ? 1 : 0))
811 this_result = result = 0;
812 debug3("%.200s line %d: %smatched '%s'",
813 filename, linenum,
814 this_result ? "" : "not ", oattrib);
815 continue;
816 }
817
818 /* Keep this list in sync with below */
819 if (strprefix(attrib, "host=", 1) != NULL ||
820 strprefix(attrib, "originalhost=", 1) != NULL ||
821 strprefix(attrib, "user=", 1) != NULL ||
822 strprefix(attrib, "localuser=", 1) != NULL ||
823 strprefix(attrib, "localnetwork=", 1) != NULL ||
824 strprefix(attrib, "version=", 1) != NULL ||
825 strprefix(attrib, "tagged=", 1) != NULL ||
826 strprefix(attrib, "command=", 1) != NULL ||
827 strprefix(attrib, "exec=", 1) != NULL) {
828 arg = strchr(attrib, '=');
829 *(arg++) = '\0';
830 } else if ((arg = argv_next(acp, avp)) == NULL) {
831 error("%.200s line %d: missing argument for Match '%s'",
832 filename, linenum, oattrib);
833 result = -1;
834 goto out;
835 }
836
837 /*
838 * All other criteria require an argument, though it may
839 * be the empty string for the "tagged" and "command"
840 * options.
841 */
842 if (*arg == '\0' &&
843 strcasecmp(attrib, "tagged") != 0 &&
844 strcasecmp(attrib, "command") != 0)
845 arg = NULL;
846 if (arg == NULL || *arg == '#') {
847 error("Missing Match criteria for %s", attrib);
848 result = -1;
849 goto out;
850 }
851 if (strcasecmp(attrib, "host") == 0) {
852 criteria = xstrdup(host);
853 r = match_hostname(host, arg) == 1;
854 if (r == (negate ? 1 : 0))
855 this_result = result = 0;
856 } else if (strcasecmp(attrib, "originalhost") == 0) {
857 criteria = xstrdup(original_host);
858 r = match_hostname(original_host, arg) == 1;
859 if (r == (negate ? 1 : 0))
860 this_result = result = 0;
861 } else if (strcasecmp(attrib, "user") == 0) {
862 criteria = xstrdup(ruser);
863 r = match_pattern_list(ruser, arg, 0) == 1;
864 if (r == (negate ? 1 : 0))
865 this_result = result = 0;
866 } else if (strcasecmp(attrib, "localuser") == 0) {
867 criteria = xstrdup(pw->pw_name);
868 r = match_pattern_list(pw->pw_name, arg, 0) == 1;
869 if (r == (negate ? 1 : 0))
870 this_result = result = 0;
871 } else if (strcasecmp(attrib, "localnetwork") == 0) {
872 if (addr_match_cidr_list(NULL, arg) == -1) {
873 /* Error already printed */
874 result = -1;
875 goto out;
876 }
877 r = check_match_ifaddrs(arg) == 1;
878 if (r == (negate ? 1 : 0))
879 this_result = result = 0;
880 } else if (strcasecmp(attrib, "version") == 0) {
881 criteria = xstrdup(SSH_RELEASE);
882 r = match_pattern_list(SSH_RELEASE, arg, 0) == 1;
883 if (r == (negate ? 1 : 0))
884 this_result = result = 0;
885 } else if (strcasecmp(attrib, "tagged") == 0) {
886 criteria = xstrdup(options->tag == NULL ? "" :
887 options->tag);
888 /* Special case: empty criteria matches empty arg */
889 r = (*criteria == '\0') ? *arg == '\0' :
890 match_pattern_list(criteria, arg, 0) == 1;
891 if (r == (negate ? 1 : 0))
892 this_result = result = 0;
893 } else if (strcasecmp(attrib, "command") == 0) {
894 criteria = xstrdup(remote_command == NULL ?
895 "" : remote_command);
896 /* Special case: empty criteria matches empty arg */
897 r = (*criteria == '\0') ? *arg == '\0' :
898 match_pattern_list(criteria, arg, 0) == 1;
899 if (r == (negate ? 1 : 0))
900 this_result = result = 0;
901 } else if (strcasecmp(attrib, "sessiontype") == 0) {
902 if (options->session_type == SESSION_TYPE_SUBSYSTEM)
903 criteria = xstrdup("subsystem");
904 else if (options->session_type == SESSION_TYPE_NONE)
905 criteria = xstrdup("none");
906 else if (remote_command != NULL &&
907 *remote_command != '\0')
908 criteria = xstrdup("exec");
909 else
910 criteria = xstrdup("shell");
911 r = match_pattern_list(criteria, arg, 0) == 1;
912 if (r == (negate ? 1 : 0))
913 this_result = result = 0;
914 } else if (strcasecmp(attrib, "exec") == 0) {
915 if ((cmd = expand_match_exec_or_include_path(arg,
916 options, pw, host_arg, original_host,
917 final_pass, 0)) == NULL) {
918 fatal("%.200s line %d: failed to expand match "
919 "exec '%.100s'", filename, linenum, arg);
920 }
921 if (result != 1) {
922 /* skip execution if prior predicate failed */
923 debug3("%.200s line %d: skipped exec "
924 "\"%.100s\"", filename, linenum, cmd);
925 free(cmd);
926 continue;
927 }
928 r = execute_in_shell(cmd);
929 if (r == -1) {
930 fatal("%.200s line %d: match exec "
931 "'%.100s' error", filename,
932 linenum, cmd);
933 }
934 criteria = xstrdup(cmd);
935 free(cmd);
936 /* Force exit status to boolean */
937 r = r == 0;
938 if (r == (negate ? 1 : 0))
939 this_result = result = 0;
940 } else {
941 error("Unsupported Match attribute %s", attrib);
942 result = -1;
943 goto out;
944 }
945 debug3("%.200s line %d: %smatched '%s%s%.100s%s' ",
946 filename, linenum, this_result ? "": "not ", oattrib,
947 criteria == NULL ? "" : " \"",
948 criteria == NULL ? "" : criteria,
949 criteria == NULL ? "" : "\"");
950 free(criteria);
951 free(oattrib);
952 oattrib = attrib = NULL;
953 }
954 if (attributes == 0) {
955 error("One or more attributes required for Match");
956 result = -1;
957 goto out;
958 }
959 out:
960 if (result != -1)
961 debug2("match %sfound", result ? "" : "not ");
962 free(oattrib);
963 free(host);
964 return result;
965 }
966
967 /* Remove environment variable by pattern */
968 static void
969 rm_env(Options *options, const char *arg, const char *filename, int linenum)
970 {
971 u_int i, j, onum_send_env = options->num_send_env;
972
973 /* Remove an environment variable */
974 for (i = 0; i < options->num_send_env; ) {
975 if (!match_pattern(options->send_env[i], arg + 1)) {
976 i++;
977 continue;
978 }
979 debug3("%s line %d: removing environment %s",
980 filename, linenum, options->send_env[i]);
981 free(options->send_env[i]);
982 options->send_env[i] = NULL;
983 for (j = i; j < options->num_send_env - 1; j++) {
984 options->send_env[j] = options->send_env[j + 1];
985 options->send_env[j + 1] = NULL;
986 }
987 options->num_send_env--;
988 /* NB. don't increment i */
989 }
990 if (onum_send_env != options->num_send_env) {
991 options->send_env = xrecallocarray(options->send_env,
992 onum_send_env, options->num_send_env,
993 sizeof(*options->send_env));
994 }
995 }
996
997 /*
998 * Returns the number of the token pointed to by cp or oBadOption.
999 */
1000 static OpCodes
1001 parse_token(const char *cp, const char *filename, int linenum,
1002 const char *ignored_unknown)
1003 {
1004 int i;
1005
1006 for (i = 0; keywords[i].name; i++)
1007 if (strcmp(cp, keywords[i].name) == 0)
1008 return keywords[i].opcode;
1009 if (ignored_unknown != NULL &&
1010 match_pattern_list(cp, ignored_unknown, 1) == 1)
1011 return oIgnoredUnknownOption;
1012 error("%s: line %d: Bad configuration option: %s",
1013 filename, linenum, cp);
1014 return oBadOption;
1015 }
1016
1017 static void
1018 free_canon_cnames(struct allowed_cname *cnames, u_int n)
1019 {
1020 u_int i;
1021
1022 if (cnames == NULL || n == 0)
1023 return;
1024 for (i = 0; i < n; i++) {
1025 free(cnames[i].source_list);
1026 free(cnames[i].target_list);
1027 }
1028 free(cnames);
1029 }
1030
1031 /* Multistate option parsing */
1032 struct multistate {
1033 const char *key;
1034 int value;
1035 };
1036 static const struct multistate multistate_flag[] = {
1037 { "true", 1 },
1038 { "false", 0 },
1039 { "yes", 1 },
1040 { "no", 0 },
1041 { NULL, -1 }
1042 };
1043 static const struct multistate multistate_yesnoask[] = {
1044 { "true", 1 },
1045 { "false", 0 },
1046 { "yes", 1 },
1047 { "no", 0 },
1048 { "ask", 2 },
1049 { NULL, -1 }
1050 };
1051 static const struct multistate multistate_strict_hostkey[] = {
1052 { "true", SSH_STRICT_HOSTKEY_YES },
1053 { "false", SSH_STRICT_HOSTKEY_OFF },
1054 { "yes", SSH_STRICT_HOSTKEY_YES },
1055 { "no", SSH_STRICT_HOSTKEY_OFF },
1056 { "ask", SSH_STRICT_HOSTKEY_ASK },
1057 { "off", SSH_STRICT_HOSTKEY_OFF },
1058 { "accept-new", SSH_STRICT_HOSTKEY_NEW },
1059 { NULL, -1 }
1060 };
1061 static const struct multistate multistate_yesnoaskconfirm[] = {
1062 { "true", 1 },
1063 { "false", 0 },
1064 { "yes", 1 },
1065 { "no", 0 },
1066 { "ask", 2 },
1067 { "confirm", 3 },
1068 { NULL, -1 }
1069 };
1070 static const struct multistate multistate_addressfamily[] = {
1071 { "inet", AF_INET },
1072 { "inet6", AF_INET6 },
1073 { "any", AF_UNSPEC },
1074 { NULL, -1 }
1075 };
1076 static const struct multistate multistate_controlmaster[] = {
1077 { "true", SSHCTL_MASTER_YES },
1078 { "yes", SSHCTL_MASTER_YES },
1079 { "false", SSHCTL_MASTER_NO },
1080 { "no", SSHCTL_MASTER_NO },
1081 { "auto", SSHCTL_MASTER_AUTO },
1082 { "ask", SSHCTL_MASTER_ASK },
1083 { "autoask", SSHCTL_MASTER_AUTO_ASK },
1084 { NULL, -1 }
1085 };
1086 static const struct multistate multistate_tunnel[] = {
1087 { "ethernet", SSH_TUNMODE_ETHERNET },
1088 { "point-to-point", SSH_TUNMODE_POINTOPOINT },
1089 { "true", SSH_TUNMODE_DEFAULT },
1090 { "yes", SSH_TUNMODE_DEFAULT },
1091 { "false", SSH_TUNMODE_NO },
1092 { "no", SSH_TUNMODE_NO },
1093 { NULL, -1 }
1094 };
1095 static const struct multistate multistate_requesttty[] = {
1096 { "true", REQUEST_TTY_YES },
1097 { "yes", REQUEST_TTY_YES },
1098 { "false", REQUEST_TTY_NO },
1099 { "no", REQUEST_TTY_NO },
1100 { "force", REQUEST_TTY_FORCE },
1101 { "auto", REQUEST_TTY_AUTO },
1102 { NULL, -1 }
1103 };
1104 static const struct multistate multistate_sessiontype[] = {
1105 { "none", SESSION_TYPE_NONE },
1106 { "subsystem", SESSION_TYPE_SUBSYSTEM },
1107 { "default", SESSION_TYPE_DEFAULT },
1108 { NULL, -1 }
1109 };
1110 static const struct multistate multistate_canonicalizehostname[] = {
1111 { "true", SSH_CANONICALISE_YES },
1112 { "false", SSH_CANONICALISE_NO },
1113 { "yes", SSH_CANONICALISE_YES },
1114 { "no", SSH_CANONICALISE_NO },
1115 { "always", SSH_CANONICALISE_ALWAYS },
1116 { NULL, -1 }
1117 };
1118 static const struct multistate multistate_pubkey_auth[] = {
1119 { "true", SSH_PUBKEY_AUTH_ALL },
1120 { "false", SSH_PUBKEY_AUTH_NO },
1121 { "yes", SSH_PUBKEY_AUTH_ALL },
1122 { "no", SSH_PUBKEY_AUTH_NO },
1123 { "unbound", SSH_PUBKEY_AUTH_UNBOUND },
1124 { "host-bound", SSH_PUBKEY_AUTH_HBOUND },
1125 { NULL, -1 }
1126 };
1127 static const struct multistate multistate_compression[] = {
1128 #ifdef WITH_ZLIB
1129 { "yes", COMP_DELAYED },
1130 #endif
1131 { "no", COMP_NONE },
1132 { NULL, -1 }
1133 };
1134 /* XXX this will need to be replaced with a bitmask if we add more flags */
1135 static const struct multistate multistate_warnweakcrypto[] = {
1136 { "true", 1 },
1137 { "false", 0 },
1138 { "yes", 1 },
1139 { "no", 0 },
1140 { "no-pq-kex", 0 },
1141 { NULL, -1 }
1142 };
1143
1144 static int
1145 parse_multistate_value(const char *arg, const char *filename, int linenum,
1146 const struct multistate *multistate_ptr)
1147 {
1148 int i;
1149
1150 if (!arg || *arg == '\0') {
1151 error("%s line %d: missing argument.", filename, linenum);
1152 return -1;
1153 }
1154 for (i = 0; multistate_ptr[i].key != NULL; i++) {
1155 if (strcasecmp(arg, multistate_ptr[i].key) == 0)
1156 return multistate_ptr[i].value;
1157 }
1158 return -1;
1159 }
1160
1161 /*
1162 * Processes a single option line as used in the configuration files. This
1163 * only sets those values that have not already been set.
1164 */
1165 int
1166 process_config_line(Options *options, struct passwd *pw, const char *host,
1167 const char *original_host, const char *remote_command, char *line,
1168 const char *filename, int linenum, int *activep, int flags)
1169 {
1170 return process_config_line_depth(options, pw, host, original_host,
1171 remote_command, line, filename, linenum, activep, flags, NULL, 0);
1172 }
1173
1174 #define WHITESPACE " \t\r\n"
1175 static int
1176 process_config_line_depth(Options *options, struct passwd *pw, const char *host,
1177 const char *original_host, const char *remote_command, char *line,
1178 const char *filename, int linenum, int *activep, int flags,
1179 int *want_final_pass, int depth)
1180 {
1181 char *str, **charptr, *endofnumber, *keyword, *arg, *arg2, *p;
1182 char **cpptr, ***cppptr, fwdarg[256];
1183 u_int i, *uintptr, max_entries = 0;
1184 int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
1185 int remotefwd, dynamicfwd, ca_only = 0, found = 0;
1186 LogLevel *log_level_ptr;
1187 SyslogFacility *log_facility_ptr;
1188 long long val64;
1189 size_t len;
1190 struct Forward fwd;
1191 const struct multistate *multistate_ptr;
1192 glob_t gl;
1193 const char *errstr;
1194 char **oav = NULL, **av;
1195 int oac = 0, ac;
1196 int ret = -1;
1197 struct allowed_cname *cnames = NULL;
1198 u_int ncnames = 0;
1199 char **strs = NULL; /* string array arguments; freed implicitly */
1200 u_int nstrs = 0;
1201
1202 if (activep == NULL) { /* We are processing a command line directive */
1203 cmdline = 1;
1204 activep = &cmdline;
1205 }
1206
1207 /* Strip trailing whitespace. Allow \f (form feed) at EOL only */
1208 if ((len = strlen(line)) == 0)
1209 return 0;
1210 for (len--; len > 0; len--) {
1211 if (strchr(WHITESPACE "\f", line[len]) == NULL)
1212 break;
1213 line[len] = '\0';
1214 }
1215
1216 str = line;
1217 /* Get the keyword. (Each line is supposed to begin with a keyword). */
1218 if ((keyword = strdelim(&str)) == NULL)
1219 return 0;
1220 /* Ignore leading whitespace. */
1221 if (*keyword == '\0')
1222 keyword = strdelim(&str);
1223 if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
1224 return 0;
1225 /* Match lowercase keyword */
1226 lowercase(keyword);
1227
1228 /* Prepare to parse remainder of line */
1229 if (str != NULL)
1230 str += strspn(str, WHITESPACE);
1231 if (str == NULL || *str == '\0') {
1232 error("%s line %d: no argument after keyword \"%s\"",
1233 filename, linenum, keyword);
1234 return -1;
1235 }
1236 opcode = parse_token(keyword, filename, linenum,
1237 options->ignored_unknown);
1238 if (argv_split(str, &oac, &oav, 1) != 0) {
1239 error("%s line %d: invalid quotes", filename, linenum);
1240 return -1;
1241 }
1242 ac = oac;
1243 av = oav;
1244
1245 switch (opcode) {
1246 case oBadOption:
1247 /* don't panic, but count bad options */
1248 goto out;
1249 case oIgnore:
1250 argv_consume(&ac);
1251 break;
1252 case oIgnoredUnknownOption:
1253 debug("%s line %d: Ignored unknown option \"%s\"",
1254 filename, linenum, keyword);
1255 argv_consume(&ac);
1256 break;
1257 case oConnectTimeout:
1258 intptr = &options->connection_timeout;
1259 parse_time:
1260 arg = argv_next(&ac, &av);
1261 if (!arg || *arg == '\0') {
1262 error("%s line %d: missing time value.",
1263 filename, linenum);
1264 goto out;
1265 }
1266 if (strcmp(arg, "none") == 0)
1267 value = -1;
1268 else if ((value = convtime(arg)) == -1) {
1269 error("%s line %d: invalid time value.",
1270 filename, linenum);
1271 goto out;
1272 }
1273 if (*activep && *intptr == -1)
1274 *intptr = value;
1275 break;
1276
1277 case oForwardAgent:
1278 intptr = &options->forward_agent;
1279
1280 arg = argv_next(&ac, &av);
1281 if (!arg || *arg == '\0') {
1282 error("%s line %d: missing argument.",
1283 filename, linenum);
1284 goto out;
1285 }
1286
1287 value = -1;
1288 multistate_ptr = multistate_flag;
1289 for (i = 0; multistate_ptr[i].key != NULL; i++) {
1290 if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
1291 value = multistate_ptr[i].value;
1292 break;
1293 }
1294 }
1295 if (value != -1) {
1296 if (*activep && *intptr == -1)
1297 *intptr = value;
1298 break;
1299 }
1300 /* ForwardAgent wasn't 'yes' or 'no', assume a path */
1301 if (*activep && *intptr == -1)
1302 *intptr = 1;
1303
1304 charptr = &options->forward_agent_sock_path;
1305 goto parse_agent_path;
1306
1307 case oForwardX11:
1308 intptr = &options->forward_x11;
1309 parse_flag:
1310 multistate_ptr = multistate_flag;
1311 parse_multistate:
1312 arg = argv_next(&ac, &av);
1313 if ((value = parse_multistate_value(arg, filename, linenum,
1314 multistate_ptr)) == -1) {
1315 error("%s line %d: unsupported option \"%s\".",
1316 filename, linenum, arg);
1317 goto out;
1318 }
1319 if (*activep && *intptr == -1)
1320 *intptr = value;
1321 break;
1322
1323 case oForwardX11Trusted:
1324 intptr = &options->forward_x11_trusted;
1325 goto parse_flag;
1326
1327 case oForwardX11Timeout:
1328 intptr = &options->forward_x11_timeout;
1329 goto parse_time;
1330
1331 case oGatewayPorts:
1332 intptr = &options->fwd_opts.gateway_ports;
1333 goto parse_flag;
1334
1335 case oExitOnForwardFailure:
1336 intptr = &options->exit_on_forward_failure;
1337 goto parse_flag;
1338
1339 case oPasswordAuthentication:
1340 intptr = &options->password_authentication;
1341 goto parse_flag;
1342
1343 case oKbdInteractiveAuthentication:
1344 intptr = &options->kbd_interactive_authentication;
1345 goto parse_flag;
1346
1347 case oKbdInteractiveDevices:
1348 charptr = &options->kbd_interactive_devices;
1349 goto parse_string;
1350
1351 case oPubkeyAuthentication:
1352 multistate_ptr = multistate_pubkey_auth;
1353 intptr = &options->pubkey_authentication;
1354 goto parse_multistate;
1355
1356 case oHostbasedAuthentication:
1357 intptr = &options->hostbased_authentication;
1358 goto parse_flag;
1359
1360 #if defined(KRB4) || defined(KRB5)
1361 case oKerberosAuthentication:
1362 intptr = &options->kerberos_authentication;
1363 goto parse_flag;
1364 #endif
1365 #if defined(AFS) || defined(KRB5)
1366 case oKerberosTgtPassing:
1367 intptr = &options->kerberos_tgt_passing;
1368 goto parse_flag;
1369 #endif
1370
1371 case oGssAuthentication:
1372 intptr = &options->gss_authentication;
1373 goto parse_flag;
1374
1375 #ifdef AFS
1376 case oAFSTokenPassing:
1377 intptr = &options->afs_token_passing;
1378 goto parse_flag;
1379 #endif
1380
1381 case oGssDelegateCreds:
1382 intptr = &options->gss_deleg_creds;
1383 goto parse_flag;
1384
1385 case oBatchMode:
1386 intptr = &options->batch_mode;
1387 goto parse_flag;
1388
1389 case oCheckHostIP:
1390 intptr = &options->check_host_ip;
1391 goto parse_flag;
1392
1393 case oNoneEnabled:
1394 intptr = &options->none_enabled;
1395 goto parse_flag;
1396
1397 /* we check to see if the command comes from the */
1398 /* command line or not. If it does then enable it */
1399 /* otherwise fail. NONE should never be a default configuration */
1400 case oNoneSwitch:
1401 if(strcmp(filename,"command-line")==0)
1402 {
1403 intptr = &options->none_switch;
1404 goto parse_flag;
1405 } else {
1406 error("NoneSwitch is found in %.200s.\nYou may only use this configuration option from the command line", filename);
1407 error("Continuing...");
1408 debug("NoneSwitch directive found in %.200s.", filename);
1409 return 0;
1410 }
1411
1412 case oHPNDisabled:
1413 intptr = &options->hpn_disabled;
1414 goto parse_flag;
1415
1416 case oHPNBufferSize:
1417 intptr = &options->hpn_buffer_size;
1418 goto parse_int;
1419
1420 case oTcpRcvBufPoll:
1421 intptr = &options->tcp_rcv_buf_poll;
1422 goto parse_flag;
1423
1424 case oVerifyHostKeyDNS:
1425 intptr = &options->verify_host_key_dns;
1426 multistate_ptr = multistate_yesnoask;
1427 goto parse_multistate;
1428
1429 case oStrictHostKeyChecking:
1430 intptr = &options->strict_host_key_checking;
1431 multistate_ptr = multistate_strict_hostkey;
1432 goto parse_multistate;
1433
1434 case oCompression:
1435 intptr = &options->compression;
1436 multistate_ptr = multistate_compression;
1437 goto parse_multistate;
1438
1439 case oTCPKeepAlive:
1440 intptr = &options->tcp_keep_alive;
1441 goto parse_flag;
1442
1443 case oNoHostAuthenticationForLocalhost:
1444 intptr = &options->no_host_authentication_for_localhost;
1445 goto parse_flag;
1446
1447 case oNumberOfPasswordPrompts:
1448 intptr = &options->number_of_password_prompts;
1449 goto parse_int;
1450
1451 case oRekeyLimit:
1452 arg = argv_next(&ac, &av);
1453 if (!arg || *arg == '\0') {
1454 error("%.200s line %d: Missing argument.", filename,
1455 linenum);
1456 goto out;
1457 }
1458 if (strcmp(arg, "default") == 0) {
1459 val64 = 0;
1460 } else {
1461 if (scan_scaled(arg, &val64) == -1) {
1462 error("%.200s line %d: Bad number '%s': %s",
1463 filename, linenum, arg, strerror(errno));
1464 goto out;
1465 }
1466 if (val64 != 0 && val64 < 16) {
1467 error("%.200s line %d: RekeyLimit too small",
1468 filename, linenum);
1469 goto out;
1470 }
1471 }
1472 if (*activep && options->rekey_limit == -1)
1473 options->rekey_limit = val64;
1474 if (ac != 0) { /* optional rekey interval present */
1475 if (strcmp(av[0], "none") == 0) {
1476 (void)argv_next(&ac, &av); /* discard */
1477 break;
1478 }
1479 intptr = &options->rekey_interval;
1480 goto parse_time;
1481 }
1482 break;
1483
1484 case oIdentityFile:
1485 arg = argv_next(&ac, &av);
1486 if (!arg || *arg == '\0') {
1487 error("%.200s line %d: Missing argument.",
1488 filename, linenum);
1489 goto out;
1490 }
1491 if (*activep) {
1492 intptr = &options->num_identity_files;
1493 if (*intptr >= SSH_MAX_IDENTITY_FILES) {
1494 error("%.200s line %d: Too many identity files "
1495 "specified (max %d).", filename, linenum,
1496 SSH_MAX_IDENTITY_FILES);
1497 goto out;
1498 }
1499 add_identity_file(options, NULL,
1500 arg, flags & SSHCONF_USERCONF);
1501 }
1502 break;
1503
1504 case oCertificateFile:
1505 arg = argv_next(&ac, &av);
1506 if (!arg || *arg == '\0') {
1507 error("%.200s line %d: Missing argument.",
1508 filename, linenum);
1509 goto out;
1510 }
1511 if (*activep) {
1512 intptr = &options->num_certificate_files;
1513 if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
1514 error("%.200s line %d: Too many certificate "
1515 "files specified (max %d).",
1516 filename, linenum,
1517 SSH_MAX_CERTIFICATE_FILES);
1518 goto out;
1519 }
1520 add_certificate_file(options, arg,
1521 flags & SSHCONF_USERCONF);
1522 }
1523 break;
1524
1525 case oXAuthLocation:
1526 charptr=&options->xauth_location;
1527 goto parse_string;
1528
1529 case oUser:
1530 charptr = &options->user;
1531 parse_string:
1532 arg = argv_next(&ac, &av);
1533 if (!arg || *arg == '\0') {
1534 error("%.200s line %d: Missing argument.",
1535 filename, linenum);
1536 goto out;
1537 }
1538 if (*activep && *charptr == NULL)
1539 *charptr = xstrdup(arg);
1540 break;
1541
1542 case oGlobalKnownHostsFile:
1543 cpptr = (char **)&options->system_hostfiles;
1544 uintptr = &options->num_system_hostfiles;
1545 max_entries = SSH_MAX_HOSTS_FILES;
1546 parse_char_array:
1547 i = 0;
1548 value = *uintptr == 0; /* was array empty when we started? */
1549 while ((arg = argv_next(&ac, &av)) != NULL) {
1550 if (*arg == '\0') {
1551 error("%s line %d: keyword %s empty argument",
1552 filename, linenum, keyword);
1553 goto out;
1554 }
1555 /* Allow "none" only in first position */
1556 if (strcasecmp(arg, "none") == 0) {
1557 if (i > 0 || ac > 0) {
1558 error("%s line %d: keyword %s \"none\" "
1559 "argument must appear alone.",
1560 filename, linenum, keyword);
1561 goto out;
1562 }
1563 }
1564 i++;
1565 if (*activep && value) {
1566 if ((*uintptr) >= max_entries) {
1567 error("%s line %d: too many %s "
1568 "entries.", filename, linenum,
1569 keyword);
1570 goto out;
1571 }
1572 cpptr[(*uintptr)++] = xstrdup(arg);
1573 }
1574 }
1575 break;
1576
1577 case oUserKnownHostsFile:
1578 cpptr = (char **)&options->user_hostfiles;
1579 uintptr = &options->num_user_hostfiles;
1580 max_entries = SSH_MAX_HOSTS_FILES;
1581 goto parse_char_array;
1582
1583 case oHostname:
1584 charptr = &options->hostname;
1585 goto parse_string;
1586
1587 case oTag:
1588 charptr = &options->tag;
1589 goto parse_string;
1590
1591 case oHostKeyAlias:
1592 charptr = &options->host_key_alias;
1593 goto parse_string;
1594
1595 case oPreferredAuthentications:
1596 charptr = &options->preferred_authentications;
1597 goto parse_string;
1598
1599 case oBindAddress:
1600 charptr = &options->bind_address;
1601 goto parse_string;
1602
1603 case oBindInterface:
1604 charptr = &options->bind_interface;
1605 goto parse_string;
1606
1607 case oIPv6PreferTemporary:
1608 intptr = &options->ipv6_prefer_temporary;
1609 goto parse_flag;
1610
1611 case oPKCS11Provider:
1612 charptr = &options->pkcs11_provider;
1613 goto parse_string;
1614
1615 case oSecurityKeyProvider:
1616 charptr = &options->sk_provider;
1617 goto parse_string;
1618
1619 case oKnownHostsCommand:
1620 charptr = &options->known_hosts_command;
1621 goto parse_command;
1622
1623 case oProxyCommand:
1624 charptr = &options->proxy_command;
1625 /* Ignore ProxyCommand if ProxyJump already specified */
1626 if (options->jump_host != NULL)
1627 charptr = &options->jump_host; /* Skip below */
1628 parse_command:
1629 if (str == NULL) {
1630 error("%.200s line %d: Missing argument.",
1631 filename, linenum);
1632 goto out;
1633 }
1634 len = strspn(str, WHITESPACE "=");
1635 if (*activep && *charptr == NULL)
1636 *charptr = xstrdup(str + len);
1637 argv_consume(&ac);
1638 break;
1639
1640 case oProxyJump:
1641 if (str == NULL) {
1642 error("%.200s line %d: Missing argument.",
1643 filename, linenum);
1644 goto out;
1645 }
1646 len = strspn(str, WHITESPACE "=");
1647 /* XXX use argv? */
1648 if (parse_jump(str + len, options, *activep) == -1) {
1649 error("%.200s line %d: Invalid ProxyJump \"%s\"",
1650 filename, linenum, str + len);
1651 goto out;
1652 }
1653 argv_consume(&ac);
1654 break;
1655
1656 case oPort:
1657 arg = argv_next(&ac, &av);
1658 if (!arg || *arg == '\0') {
1659 error("%.200s line %d: Missing argument.",
1660 filename, linenum);
1661 goto out;
1662 }
1663 value = a2port(arg);
1664 if (value <= 0) {
1665 error("%.200s line %d: Bad port '%s'.",
1666 filename, linenum, arg);
1667 goto out;
1668 }
1669 if (*activep && options->port == -1)
1670 options->port = value;
1671 break;
1672
1673 case oConnectionAttempts:
1674 intptr = &options->connection_attempts;
1675 parse_int:
1676 arg = argv_next(&ac, &av);
1677 if ((errstr = atoi_err(arg, &value)) != NULL) {
1678 error("%s line %d: integer value %s.",
1679 filename, linenum, errstr);
1680 goto out;
1681 }
1682 if (*activep && *intptr == -1)
1683 *intptr = value;
1684 break;
1685
1686 case oTcpRcvBuf:
1687 intptr = &options->tcp_rcv_buf;
1688 goto parse_int;
1689
1690 case oCiphers:
1691 arg = argv_next(&ac, &av);
1692 if (!arg || *arg == '\0') {
1693 error("%.200s line %d: Missing argument.",
1694 filename, linenum);
1695 goto out;
1696 }
1697 if (*arg != '-' &&
1698 !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)){
1699 error("%.200s line %d: Bad SSH2 cipher spec '%s'.",
1700 filename, linenum, arg ? arg : "<NONE>");
1701 goto out;
1702 }
1703 if (*activep && options->ciphers == NULL)
1704 options->ciphers = xstrdup(arg);
1705 break;
1706
1707 case oMacs:
1708 arg = argv_next(&ac, &av);
1709 if (!arg || *arg == '\0') {
1710 error("%.200s line %d: Missing argument.",
1711 filename, linenum);
1712 goto out;
1713 }
1714 if (*arg != '-' &&
1715 !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)) {
1716 error("%.200s line %d: Bad SSH2 MAC spec '%s'.",
1717 filename, linenum, arg ? arg : "<NONE>");
1718 goto out;
1719 }
1720 if (*activep && options->macs == NULL)
1721 options->macs = xstrdup(arg);
1722 break;
1723
1724 case oKexAlgorithms:
1725 arg = argv_next(&ac, &av);
1726 if (!arg || *arg == '\0') {
1727 error("%.200s line %d: Missing argument.",
1728 filename, linenum);
1729 goto out;
1730 }
1731 if (*arg != '-' &&
1732 !kex_names_valid(*arg == '+' || *arg == '^' ?
1733 arg + 1 : arg)) {
1734 error("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
1735 filename, linenum, arg ? arg : "<NONE>");
1736 goto out;
1737 }
1738 if (*activep && options->kex_algorithms == NULL)
1739 options->kex_algorithms = xstrdup(arg);
1740 break;
1741
1742 case oHostKeyAlgorithms:
1743 charptr = &options->hostkeyalgorithms;
1744 ca_only = 0;
1745 parse_pubkey_algos:
1746 arg = argv_next(&ac, &av);
1747 if (!arg || *arg == '\0') {
1748 error("%.200s line %d: Missing argument.",
1749 filename, linenum);
1750 goto out;
1751 }
1752 if (*arg != '-' &&
1753 !sshkey_names_valid2(*arg == '+' || *arg == '^' ?
1754 arg + 1 : arg, 1, ca_only)) {
1755 error("%s line %d: Bad key types '%s'.",
1756 filename, linenum, arg ? arg : "<NONE>");
1757 goto out;
1758 }
1759 if (*activep && *charptr == NULL)
1760 *charptr = xstrdup(arg);
1761 break;
1762
1763 case oCASignatureAlgorithms:
1764 charptr = &options->ca_sign_algorithms;
1765 ca_only = 1;
1766 goto parse_pubkey_algos;
1767
1768 case oLogLevel:
1769 log_level_ptr = &options->log_level;
1770 arg = argv_next(&ac, &av);
1771 value = log_level_number(arg);
1772 if (value == SYSLOG_LEVEL_NOT_SET) {
1773 error("%.200s line %d: unsupported log level '%s'",
1774 filename, linenum, arg ? arg : "<NONE>");
1775 goto out;
1776 }
1777 if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1778 *log_level_ptr = (LogLevel) value;
1779 break;
1780
1781 case oLogFacility:
1782 log_facility_ptr = &options->log_facility;
1783 arg = argv_next(&ac, &av);
1784 value = log_facility_number(arg);
1785 if (value == SYSLOG_FACILITY_NOT_SET) {
1786 error("%.200s line %d: unsupported log facility '%s'",
1787 filename, linenum, arg ? arg : "<NONE>");
1788 goto out;
1789 }
1790 if (*log_facility_ptr == -1)
1791 *log_facility_ptr = (SyslogFacility) value;
1792 break;
1793
1794 case oLogVerbose:
1795 cppptr = &options->log_verbose;
1796 uintptr = &options->num_log_verbose;
1797 i = 0;
1798 while ((arg = argv_next(&ac, &av)) != NULL) {
1799 if (*arg == '\0') {
1800 error("%s line %d: keyword %s empty argument",
1801 filename, linenum, keyword);
1802 goto out;
1803 }
1804 /* Allow "none" only in first position */
1805 if (strcasecmp(arg, "none") == 0) {
1806 if (i > 0 || ac > 0) {
1807 error("%s line %d: keyword %s \"none\" "
1808 "argument must appear alone.",
1809 filename, linenum, keyword);
1810 goto out;
1811 }
1812 }
1813 i++;
1814 if (*activep && *uintptr == 0) {
1815 *cppptr = xrecallocarray(*cppptr, *uintptr,
1816 *uintptr + 1, sizeof(**cppptr));
1817 (*cppptr)[(*uintptr)++] = xstrdup(arg);
1818 }
1819 }
1820 break;
1821
1822 case oLocalForward:
1823 case oRemoteForward:
1824 case oDynamicForward:
1825 arg = argv_next(&ac, &av);
1826 if (!arg || *arg == '\0') {
1827 error("%.200s line %d: Missing argument.",
1828 filename, linenum);
1829 goto out;
1830 }
1831
1832 remotefwd = (opcode == oRemoteForward);
1833 dynamicfwd = (opcode == oDynamicForward);
1834
1835 if (!dynamicfwd) {
1836 arg2 = argv_next(&ac, &av);
1837 if (arg2 == NULL || *arg2 == '\0') {
1838 if (remotefwd)
1839 dynamicfwd = 1;
1840 else {
1841 error("%.200s line %d: Missing target "
1842 "argument.", filename, linenum);
1843 goto out;
1844 }
1845 } else {
1846 /* construct a string for parse_forward */
1847 snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg,
1848 arg2);
1849 }
1850 }
1851 if (dynamicfwd)
1852 strlcpy(fwdarg, arg, sizeof(fwdarg));
1853
1854 if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0) {
1855 error("%.200s line %d: Bad forwarding specification.",
1856 filename, linenum);
1857 goto out;
1858 }
1859
1860 if (*activep) {
1861 if (remotefwd) {
1862 add_remote_forward(options, &fwd);
1863 } else {
1864 add_local_forward(options, &fwd);
1865 }
1866 }
1867 break;
1868
1869 case oPermitRemoteOpen:
1870 uintptr = &options->num_permitted_remote_opens;
1871 cppptr = &options->permitted_remote_opens;
1872 found = *uintptr == 0;
1873 while ((arg = argv_next(&ac, &av)) != NULL) {
1874 arg2 = xstrdup(arg);
1875 /* Allow any/none only in first position */
1876 if (strcasecmp(arg, "none") == 0 ||
1877 strcasecmp(arg, "any") == 0) {
1878 if (nstrs > 0 || ac > 0) {
1879 error("%s line %d: keyword %s \"%s\" "
1880 "argument must appear alone.",
1881 filename, linenum, keyword, arg);
1882 free(arg2);
1883 goto out;
1884 }
1885 } else {
1886 p = hpdelim(&arg);
1887 if (p == NULL) {
1888 fatal("%s line %d: missing host in %s",
1889 filename, linenum,
1890 lookup_opcode_name(opcode));
1891 }
1892 p = cleanhostname(p);
1893 /*
1894 * don't want to use permitopen_port to avoid
1895 * dependency on channels.[ch] here.
1896 */
1897 if (arg == NULL || (strcmp(arg, "*") != 0 &&
1898 a2port(arg) <= 0)) {
1899 fatal("%s line %d: bad port number "
1900 "in %s", filename, linenum,
1901 lookup_opcode_name(opcode));
1902 }
1903 }
1904 opt_array_append(filename, linenum,
1905 lookup_opcode_name(opcode),
1906 &strs, &nstrs, arg2);
1907 free(arg2);
1908 }
1909 if (nstrs == 0)
1910 fatal("%s line %d: missing %s specification",
1911 filename, linenum, lookup_opcode_name(opcode));
1912 if (found && *activep) {
1913 *cppptr = strs;
1914 *uintptr = nstrs;
1915 strs = NULL; /* transferred */
1916 nstrs = 0;
1917 }
1918 break;
1919
1920 case oClearAllForwardings:
1921 intptr = &options->clear_forwardings;
1922 goto parse_flag;
1923
1924 case oHost:
1925 if (cmdline) {
1926 error("Host directive not supported as a command-line "
1927 "option");
1928 goto out;
1929 }
1930 *activep = 0;
1931 arg2 = NULL;
1932 while ((arg = argv_next(&ac, &av)) != NULL) {
1933 if (*arg == '\0') {
1934 error("%s line %d: keyword %s empty argument",
1935 filename, linenum, keyword);
1936 goto out;
1937 }
1938 if ((flags & SSHCONF_NEVERMATCH) != 0) {
1939 argv_consume(&ac);
1940 break;
1941 }
1942 negated = *arg == '!';
1943 if (negated)
1944 arg++;
1945 if (match_pattern(host, arg)) {
1946 if (negated) {
1947 debug("%.200s line %d: Skipping Host "
1948 "block because of negated match "
1949 "for %.100s", filename, linenum,
1950 arg);
1951 *activep = 0;
1952 argv_consume(&ac);
1953 break;
1954 }
1955 if (!*activep)
1956 arg2 = arg; /* logged below */
1957 *activep = 1;
1958 }
1959 }
1960 if (*activep)
1961 debug("%.200s line %d: Applying options for %.100s",
1962 filename, linenum, arg2);
1963 break;
1964
1965 case oMatch:
1966 if (cmdline) {
1967 error("Host directive not supported as a command-line "
1968 "option");
1969 goto out;
1970 }
1971 value = match_cfg_line(options, str, &ac, &av, pw, host,
1972 original_host, remote_command, flags & SSHCONF_FINAL,
1973 want_final_pass, filename, linenum);
1974 if (value < 0) {
1975 error("%.200s line %d: Bad Match condition", filename,
1976 linenum);
1977 goto out;
1978 }
1979 *activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
1980 break;
1981
1982 case oEscapeChar:
1983 intptr = &options->escape_char;
1984 arg = argv_next(&ac, &av);
1985 if (!arg || *arg == '\0') {
1986 error("%.200s line %d: Missing argument.",
1987 filename, linenum);
1988 goto out;
1989 }
1990 if (strcmp(arg, "none") == 0)
1991 value = SSH_ESCAPECHAR_NONE;
1992 else if (arg[1] == '\0')
1993 value = (u_char) arg[0];
1994 else if (arg[0] == '^' && arg[2] == 0 &&
1995 (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1996 value = (u_char) arg[1] & 31;
1997 else {
1998 error("%.200s line %d: Bad escape character.",
1999 filename, linenum);
2000 goto out;
2001 }
2002 if (*activep && *intptr == -1)
2003 *intptr = value;
2004 break;
2005
2006 case oAddressFamily:
2007 intptr = &options->address_family;
2008 multistate_ptr = multistate_addressfamily;
2009 goto parse_multistate;
2010
2011 case oEnableSSHKeysign:
2012 intptr = &options->enable_ssh_keysign;
2013 goto parse_flag;
2014
2015 case oIdentitiesOnly:
2016 intptr = &options->identities_only;
2017 goto parse_flag;
2018
2019 case oServerAliveInterval:
2020 intptr = &options->server_alive_interval;
2021 goto parse_time;
2022
2023 case oServerAliveCountMax:
2024 intptr = &options->server_alive_count_max;
2025 goto parse_int;
2026
2027 case oSendEnv:
2028 /* XXX appends to list; doesn't respect first-match-wins */
2029 while ((arg = argv_next(&ac, &av)) != NULL) {
2030 if (*arg == '\0' || strchr(arg, '=') != NULL) {
2031 error("%s line %d: Invalid environment name.",
2032 filename, linenum);
2033 goto out;
2034 }
2035 found = 1;
2036 if (!*activep)
2037 continue;
2038 if (*arg == '-') {
2039 /* Removing an env var */
2040 rm_env(options, arg, filename, linenum);
2041 continue;
2042 }
2043 opt_array_append(filename, linenum,
2044 lookup_opcode_name(opcode),
2045 &options->send_env, &options->num_send_env, arg);
2046 }
2047 if (!found) {
2048 fatal("%s line %d: no %s specified",
2049 filename, linenum, keyword);
2050 }
2051 break;
2052
2053 case oSetEnv:
2054 found = options->num_setenv == 0;
2055 while ((arg = argv_next(&ac, &av)) != NULL) {
2056 if (strchr(arg, '=') == NULL) {
2057 error("%s line %d: Invalid SetEnv.",
2058 filename, linenum);
2059 goto out;
2060 }
2061 if (lookup_setenv_in_list(arg, strs, nstrs) != NULL) {
2062 debug2("%s line %d: ignoring duplicate env "
2063 "name \"%.64s\"", filename, linenum, arg);
2064 continue;
2065 }
2066 opt_array_append(filename, linenum,
2067 lookup_opcode_name(opcode),
2068 &strs, &nstrs, arg);
2069 }
2070 if (nstrs == 0) {
2071 fatal("%s line %d: no %s specified",
2072 filename, linenum, keyword);
2073 }
2074 if (found && *activep) {
2075 options->setenv = strs;
2076 options->num_setenv = nstrs;
2077 strs = NULL; /* transferred */
2078 nstrs = 0;
2079 }
2080 break;
2081
2082 case oControlPath:
2083 charptr = &options->control_path;
2084 goto parse_string;
2085
2086 case oControlMaster:
2087 intptr = &options->control_master;
2088 multistate_ptr = multistate_controlmaster;
2089 goto parse_multistate;
2090
2091 case oControlPersist:
2092 /* no/false/yes/true, or a time spec */
2093 intptr = &options->control_persist;
2094 arg = argv_next(&ac, &av);
2095 if (!arg || *arg == '\0') {
2096 error("%.200s line %d: Missing ControlPersist"
2097 " argument.", filename, linenum);
2098 goto out;
2099 }
2100 value = 0;
2101 value2 = 0; /* timeout */
2102 if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
2103 value = 0;
2104 else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
2105 value = 1;
2106 else if ((value2 = convtime(arg)) >= 0)
2107 value = 1;
2108 else {
2109 error("%.200s line %d: Bad ControlPersist argument.",
2110 filename, linenum);
2111 goto out;
2112 }
2113 if (*activep && *intptr == -1) {
2114 *intptr = value;
2115 options->control_persist_timeout = value2;
2116 }
2117 break;
2118
2119 case oHashKnownHosts:
2120 intptr = &options->hash_known_hosts;
2121 goto parse_flag;
2122
2123 case oTunnel:
2124 intptr = &options->tun_open;
2125 multistate_ptr = multistate_tunnel;
2126 goto parse_multistate;
2127
2128 case oTunnelDevice:
2129 arg = argv_next(&ac, &av);
2130 if (!arg || *arg == '\0') {
2131 error("%.200s line %d: Missing argument.",
2132 filename, linenum);
2133 goto out;
2134 }
2135 value = a2tun(arg, &value2);
2136 if (value == SSH_TUNID_ERR) {
2137 error("%.200s line %d: Bad tun device.",
2138 filename, linenum);
2139 goto out;
2140 }
2141 if (*activep && options->tun_local == -1) {
2142 options->tun_local = value;
2143 options->tun_remote = value2;
2144 }
2145 break;
2146
2147 case oLocalCommand:
2148 charptr = &options->local_command;
2149 goto parse_command;
2150
2151 case oPermitLocalCommand:
2152 intptr = &options->permit_local_command;
2153 goto parse_flag;
2154
2155 case oRemoteCommand:
2156 charptr = &options->remote_command;
2157 goto parse_command;
2158
2159 case oVisualHostKey:
2160 intptr = &options->visual_host_key;
2161 goto parse_flag;
2162
2163 case oInclude:
2164 if (cmdline) {
2165 error("Include directive not supported as a "
2166 "command-line option");
2167 goto out;
2168 }
2169 value = 0;
2170 while ((arg = argv_next(&ac, &av)) != NULL) {
2171 if (*arg == '\0') {
2172 error("%s line %d: keyword %s empty argument",
2173 filename, linenum, keyword);
2174 goto out;
2175 }
2176 /* Expand %tokens and environment variables */
2177 if ((p = expand_match_exec_or_include_path(arg,
2178 options, pw, host, original_host,
2179 flags & SSHCONF_FINAL, 1)) == NULL) {
2180 error("%.200s line %d: Unable to expand user "
2181 "config file '%.100s'",
2182 filename, linenum, arg);
2183 continue;
2184 }
2185 /*
2186 * Ensure all paths are anchored. User configuration
2187 * files may begin with '~/' but system configurations
2188 * must not. If the path is relative, then treat it
2189 * as living in ~/.ssh for user configurations or
2190 * /etc/ssh for system ones.
2191 */
2192 if (*p == '~' && (flags & SSHCONF_USERCONF) == 0) {
2193 error("%.200s line %d: bad include path %s.",
2194 filename, linenum, p);
2195 goto out;
2196 }
2197 if (!path_absolute(p) && *p != '~') {
2198 xasprintf(&arg2, "%s/%s",
2199 (flags & SSHCONF_USERCONF) ?
2200 "~/" _PATH_SSH_USER_DIR : SSHDIR, p);
2201 } else {
2202 arg2 = xstrdup(p);
2203 }
2204 free(p);
2205 memset(&gl, 0, sizeof(gl));
2206 r = glob(arg2, GLOB_TILDE | GLOB_LIMIT, NULL, &gl);
2207 if (r == GLOB_NOMATCH) {
2208 debug("%.200s line %d: include %s matched no "
2209 "files",filename, linenum, arg2);
2210 free(arg2);
2211 continue;
2212 } else if (r != 0) {
2213 error("%.200s line %d: glob failed for %s.",
2214 filename, linenum, arg2);
2215 goto out;
2216 }
2217 free(arg2);
2218 oactive = *activep;
2219 for (i = 0; i < gl.gl_pathc; i++) {
2220 debug3("%.200s line %d: Including file %s "
2221 "depth %d%s", filename, linenum,
2222 gl.gl_pathv[i], depth,
2223 oactive ? "" : " (parse only)");
2224 r = read_config_file_depth(gl.gl_pathv[i],
2225 pw, host, original_host, remote_command,
2226 options, flags | SSHCONF_CHECKPERM |
2227 (oactive ? 0 : SSHCONF_NEVERMATCH),
2228 activep, want_final_pass, depth + 1);
2229 if (r != 1 && errno != ENOENT) {
2230 error("%.200s line %d: Can't open user "
2231 "config file %.100s: %.100s",
2232 filename, linenum, gl.gl_pathv[i],
2233 strerror(errno));
2234 globfree(&gl);
2235 goto out;
2236 }
2237 /*
2238 * don't let Match in includes clobber the
2239 * containing file's Match state.
2240 */
2241 *activep = oactive;
2242 if (r != 1)
2243 value = -1;
2244 }
2245 globfree(&gl);
2246 }
2247 if (value != 0)
2248 ret = value;
2249 break;
2250
2251 case oIPQoS:
2252 arg = argv_next(&ac, &av);
2253 if ((value = parse_ipqos(arg)) == -1) {
2254 error("%s line %d: Bad IPQoS value: %s",
2255 filename, linenum, arg);
2256 goto out;
2257 }
2258 if (value == INT_MIN) {
2259 debug("%s line %d: Deprecated IPQoS value \"%s\" "
2260 "ignored - using system default instead. Consider"
2261 " using DSCP values.", filename, linenum, arg);
2262 value = INT_MAX;
2263 }
2264 arg = argv_next(&ac, &av);
2265 if (arg == NULL)
2266 value2 = value;
2267 else if ((value2 = parse_ipqos(arg)) == -1) {
2268 error("%s line %d: Bad IPQoS value: %s",
2269 filename, linenum, arg);
2270 goto out;
2271 }
2272 if (value2 == INT_MIN) {
2273 debug("%s line %d: Deprecated IPQoS value \"%s\" "
2274 "ignored - using system default instead. Consider"
2275 " using DSCP values.", filename, linenum, arg);
2276 value2 = INT_MAX;
2277 }
2278 if (*activep && options->ip_qos_interactive == -1) {
2279 options->ip_qos_interactive = value;
2280 options->ip_qos_bulk = value2;
2281 }
2282 break;
2283
2284 case oRequestTTY:
2285 intptr = &options->request_tty;
2286 multistate_ptr = multistate_requesttty;
2287 goto parse_multistate;
2288
2289 case oSendVersionFirst:
2290 intptr = &options->send_version_first;
2291 goto parse_flag;
2292
2293 case oSessionType:
2294 intptr = &options->session_type;
2295 multistate_ptr = multistate_sessiontype;
2296 goto parse_multistate;
2297
2298 case oStdinNull:
2299 intptr = &options->stdin_null;
2300 goto parse_flag;
2301
2302 case oForkAfterAuthentication:
2303 intptr = &options->fork_after_authentication;
2304 goto parse_flag;
2305
2306 case oIgnoreUnknown:
2307 charptr = &options->ignored_unknown;
2308 goto parse_string;
2309
2310 case oProxyUseFdpass:
2311 intptr = &options->proxy_use_fdpass;
2312 goto parse_flag;
2313
2314 case oCanonicalDomains:
2315 found = options->num_canonical_domains == 0;
2316 while ((arg = argv_next(&ac, &av)) != NULL) {
2317 /* Allow "none" only in first position */
2318 if (strcasecmp(arg, "none") == 0) {
2319 if (nstrs > 0 || ac > 0) {
2320 error("%s line %d: keyword %s \"none\" "
2321 "argument must appear alone.",
2322 filename, linenum, keyword);
2323 goto out;
2324 }
2325 }
2326 if (!valid_domain(arg, 1, &errstr)) {
2327 error("%s line %d: %s", filename, linenum,
2328 errstr);
2329 goto out;
2330 }
2331 opt_array_append(filename, linenum, keyword,
2332 &strs, &nstrs, arg);
2333 }
2334 if (nstrs == 0) {
2335 fatal("%s line %d: no %s specified",
2336 filename, linenum, keyword);
2337 }
2338 if (found && *activep) {
2339 options->canonical_domains = strs;
2340 options->num_canonical_domains = nstrs;
2341 strs = NULL; /* transferred */
2342 nstrs = 0;
2343 }
2344 break;
2345
2346 case oCanonicalizePermittedCNAMEs:
2347 found = options->num_permitted_cnames == 0;
2348 while ((arg = argv_next(&ac, &av)) != NULL) {
2349 char empty[] = "";
2350 /*
2351 * Either 'none' (only in first position), '*' for
2352 * everything or 'list:list'
2353 */
2354 if (strcasecmp(arg, "none") == 0) {
2355 if (ncnames > 0 || ac > 0) {
2356 error("%s line %d: keyword %s \"none\" "
2357 "argument must appear alone.",
2358 filename, linenum, keyword);
2359 goto out;
2360 }
2361 arg2 = empty;
2362 } else if (strcmp(arg, "*") == 0) {
2363 arg2 = arg;
2364 } else {
2365 lowercase(arg);
2366 if ((arg2 = strchr(arg, ':')) == NULL ||
2367 arg2[1] == '\0') {
2368 error("%s line %d: "
2369 "Invalid permitted CNAME \"%s\"",
2370 filename, linenum, arg);
2371 goto out;
2372 }
2373 *arg2 = '\0';
2374 arg2++;
2375 }
2376 cnames = xrecallocarray(cnames, ncnames, ncnames + 1,
2377 sizeof(*cnames));
2378 cnames[ncnames].source_list = xstrdup(arg);
2379 cnames[ncnames].target_list = xstrdup(arg2);
2380 ncnames++;
2381 }
2382 if (ncnames == 0) {
2383 fatal("%s line %d: no %s specified",
2384 filename, linenum, keyword);
2385 }
2386 if (found && *activep) {
2387 options->permitted_cnames = cnames;
2388 options->num_permitted_cnames = ncnames;
2389 cnames = NULL; /* transferred */
2390 ncnames = 0;
2391 }
2392 /* un-transferred cnames is cleaned up before exit */
2393 break;
2394
2395 case oCanonicalizeHostname:
2396 intptr = &options->canonicalize_hostname;
2397 multistate_ptr = multistate_canonicalizehostname;
2398 goto parse_multistate;
2399
2400 case oCanonicalizeMaxDots:
2401 intptr = &options->canonicalize_max_dots;
2402 goto parse_int;
2403
2404 case oCanonicalizeFallbackLocal:
2405 intptr = &options->canonicalize_fallback_local;
2406 goto parse_flag;
2407
2408 case oStreamLocalBindMask:
2409 arg = argv_next(&ac, &av);
2410 if (!arg || *arg == '\0') {
2411 error("%.200s line %d: Missing StreamLocalBindMask "
2412 "argument.", filename, linenum);
2413 goto out;
2414 }
2415 /* Parse mode in octal format */
2416 value = strtol(arg, &endofnumber, 8);
2417 if (arg == endofnumber || value < 0 || value > 0777) {
2418 error("%.200s line %d: Bad mask.", filename, linenum);
2419 goto out;
2420 }
2421 options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
2422 break;
2423
2424 case oStreamLocalBindUnlink:
2425 intptr = &options->fwd_opts.streamlocal_bind_unlink;
2426 goto parse_flag;
2427
2428 case oRevokedHostKeys:
2429 charptr = &options->revoked_host_keys;
2430 goto parse_string;
2431
2432 case oFingerprintHash:
2433 intptr = &options->fingerprint_hash;
2434 arg = argv_next(&ac, &av);
2435 if (!arg || *arg == '\0') {
2436 error("%.200s line %d: Missing argument.",
2437 filename, linenum);
2438 goto out;
2439 }
2440 if ((value = ssh_digest_alg_by_name(arg)) == -1) {
2441 error("%.200s line %d: Invalid hash algorithm \"%s\".",
2442 filename, linenum, arg);
2443 goto out;
2444 }
2445 if (*activep && *intptr == -1)
2446 *intptr = value;
2447 break;
2448
2449 case oUpdateHostkeys:
2450 intptr = &options->update_hostkeys;
2451 multistate_ptr = multistate_yesnoask;
2452 goto parse_multistate;
2453
2454 case oHostbasedAcceptedAlgorithms:
2455 charptr = &options->hostbased_accepted_algos;
2456 ca_only = 0;
2457 goto parse_pubkey_algos;
2458
2459 case oPubkeyAcceptedAlgorithms:
2460 charptr = &options->pubkey_accepted_algos;
2461 ca_only = 0;
2462 goto parse_pubkey_algos;
2463
2464 case oAddKeysToAgent:
2465 arg = argv_next(&ac, &av);
2466 arg2 = argv_next(&ac, &av);
2467 value = parse_multistate_value(arg, filename, linenum,
2468 multistate_yesnoaskconfirm);
2469 value2 = 0; /* unlimited lifespan by default */
2470 if (value == 3 && arg2 != NULL) {
2471 /* allow "AddKeysToAgent confirm 5m" */
2472 if ((value2 = convtime(arg2)) == -1) {
2473 error("%s line %d: invalid time value.",
2474 filename, linenum);
2475 goto out;
2476 }
2477 } else if (value == -1 && arg2 == NULL) {
2478 if ((value2 = convtime(arg)) == -1) {
2479 error("%s line %d: unsupported option",
2480 filename, linenum);
2481 goto out;
2482 }
2483 value = 1; /* yes */
2484 } else if (value == -1 || arg2 != NULL) {
2485 error("%s line %d: unsupported option",
2486 filename, linenum);
2487 goto out;
2488 }
2489 if (*activep && options->add_keys_to_agent == -1) {
2490 options->add_keys_to_agent = value;
2491 options->add_keys_to_agent_lifespan = value2;
2492 }
2493 break;
2494
2495 case oIdentityAgent:
2496 charptr = &options->identity_agent;
2497 arg = argv_next(&ac, &av);
2498 if (!arg || *arg == '\0') {
2499 error("%.200s line %d: Missing argument.",
2500 filename, linenum);
2501 goto out;
2502 }
2503 parse_agent_path:
2504 /* Extra validation if the string represents an env var. */
2505 if ((arg2 = dollar_expand(&r, arg)) == NULL || r) {
2506 error("%.200s line %d: Invalid environment expansion "
2507 "%s.", filename, linenum, arg);
2508 goto out;
2509 }
2510 free(arg2);
2511 /* check for legacy environment format */
2512 if (arg[0] == '$' && arg[1] != '{' &&
2513 !valid_env_name(arg + 1)) {
2514 error("%.200s line %d: Invalid environment name %s.",
2515 filename, linenum, arg);
2516 goto out;
2517 }
2518 if (*activep && *charptr == NULL)
2519 *charptr = xstrdup(arg);
2520 break;
2521
2522 case oEnableEscapeCommandline:
2523 intptr = &options->enable_escape_commandline;
2524 goto parse_flag;
2525
2526 case oRequiredRSASize:
2527 intptr = &options->required_rsa_size;
2528 goto parse_int;
2529
2530 case oWarnWeakCrypto:
2531 intptr = &options->warn_weak_crypto;
2532 multistate_ptr = multistate_warnweakcrypto;
2533 goto parse_multistate;
2534
2535 case oObscureKeystrokeTiming:
2536 value = -1;
2537 while ((arg = argv_next(&ac, &av)) != NULL) {
2538 if (value != -1) {
2539 error("%s line %d: invalid arguments",
2540 filename, linenum);
2541 goto out;
2542 }
2543 if (strcmp(arg, "yes") == 0 ||
2544 strcmp(arg, "true") == 0)
2545 value = SSH_KEYSTROKE_DEFAULT_INTERVAL_MS;
2546 else if (strcmp(arg, "no") == 0 ||
2547 strcmp(arg, "false") == 0)
2548 value = 0;
2549 else if (strncmp(arg, "interval:", 9) == 0) {
2550 if ((errstr = atoi_err(arg + 9,
2551 &value)) != NULL) {
2552 error("%s line %d: integer value %s.",
2553 filename, linenum, errstr);
2554 goto out;
2555 }
2556 if (value <= 0 || value > 1000) {
2557 error("%s line %d: value out of range.",
2558 filename, linenum);
2559 goto out;
2560 }
2561 } else {
2562 error("%s line %d: unsupported argument \"%s\"",
2563 filename, linenum, arg);
2564 goto out;
2565 }
2566 }
2567 if (value == -1) {
2568 error("%s line %d: missing argument",
2569 filename, linenum);
2570 goto out;
2571 }
2572 intptr = &options->obscure_keystroke_timing_interval;
2573 if (*activep && *intptr == -1)
2574 *intptr = value;
2575 break;
2576
2577 case oChannelTimeout:
2578 found = options->num_channel_timeouts == 0;
2579 while ((arg = argv_next(&ac, &av)) != NULL) {
2580 /* Allow "none" only in first position */
2581 if (strcasecmp(arg, "none") == 0) {
2582 if (nstrs > 0 || ac > 0) {
2583 error("%s line %d: keyword %s \"none\" "
2584 "argument must appear alone.",
2585 filename, linenum, keyword);
2586 goto out;
2587 }
2588 } else if (parse_pattern_interval(arg,
2589 NULL, NULL) != 0) {
2590 fatal("%s line %d: invalid channel timeout %s",
2591 filename, linenum, arg);
2592 }
2593 opt_array_append(filename, linenum, keyword,
2594 &strs, &nstrs, arg);
2595 }
2596 if (nstrs == 0) {
2597 fatal("%s line %d: no %s specified",
2598 filename, linenum, keyword);
2599 }
2600 if (found && *activep) {
2601 options->channel_timeouts = strs;
2602 options->num_channel_timeouts = nstrs;
2603 strs = NULL; /* transferred */
2604 nstrs = 0;
2605 }
2606 break;
2607
2608 case oVersionAddendum:
2609 if (str == NULL || *str == '\0')
2610 fatal("%s line %d: %s missing argument.",
2611 filename, linenum, keyword);
2612 len = strspn(str, WHITESPACE);
2613 if (strchr(str + len, '\r') != NULL) {
2614 fatal("%.200s line %d: Invalid %s argument",
2615 filename, linenum, keyword);
2616 }
2617 if ((arg = strchr(line, '#')) != NULL) {
2618 *arg = '\0';
2619 rtrim(line);
2620 }
2621 if (*activep && options->version_addendum == NULL) {
2622 if (strcasecmp(str + len, "none") == 0)
2623 options->version_addendum = xstrdup("");
2624 else
2625 options->version_addendum = xstrdup(str + len);
2626 }
2627 argv_consume(&ac);
2628 break;
2629
2630 case oRefuseConnection:
2631 arg = argv_next(&ac, &av);
2632 if (!arg || *arg == '\0') {
2633 error("%.200s line %d: Missing argument.",
2634 filename, linenum);
2635 goto out;
2636 }
2637 if (*activep) {
2638 fatal("%.200s line %d: RefuseConnection: %s",
2639 filename, linenum, arg);
2640 }
2641 break;
2642
2643 case oDeprecated:
2644 debug("%s line %d: Deprecated option \"%s\"",
2645 filename, linenum, keyword);
2646 argv_consume(&ac);
2647 break;
2648
2649 case oUnsupported:
2650 error("%s line %d: Unsupported option \"%s\"",
2651 filename, linenum, keyword);
2652 argv_consume(&ac);
2653 break;
2654
2655 default:
2656 error("%s line %d: Unimplemented opcode %d",
2657 filename, linenum, opcode);
2658 goto out;
2659 }
2660
2661 /* Check that there is no garbage at end of line. */
2662 if (ac > 0) {
2663 error("%.200s line %d: keyword %s extra arguments "
2664 "at end of line", filename, linenum, keyword);
2665 goto out;
2666 }
2667
2668 /* success */
2669 ret = 0;
2670 out:
2671 free_canon_cnames(cnames, ncnames);
2672 opt_array_free2(strs, NULL, nstrs);
2673 argv_free(oav, oac);
2674 return ret;
2675 }
2676
2677 /*
2678 * Reads the config file and modifies the options accordingly. Options
2679 * should already be initialized before this call. This never returns if
2680 * there is an error. If the file does not exist, this returns 0.
2681 */
2682 int
2683 read_config_file(const char *filename, struct passwd *pw, const char *host,
2684 const char *original_host, const char *remote_command, Options *options, int flags,
2685 int *want_final_pass)
2686 {
2687 int active = 1;
2688
2689 return read_config_file_depth(filename, pw, host, original_host,
2690 remote_command, options, flags, &active, want_final_pass, 0);
2691 }
2692
2693 #define READCONF_MAX_DEPTH 16
2694 static int
2695 read_config_file_depth(const char *filename, struct passwd *pw,
2696 const char *host, const char *original_host, const char *remote_command,
2697 Options *options, int flags, int *activep, int *want_final_pass, int depth)
2698 {
2699 FILE *f;
2700 char *line = NULL;
2701 size_t linesize = 0;
2702 int linenum;
2703 int bad_options = 0;
2704
2705 if (depth < 0 || depth > READCONF_MAX_DEPTH)
2706 fatal("Too many recursive configuration includes");
2707
2708 if ((f = fopen(filename, "r")) == NULL)
2709 return 0;
2710
2711 if (flags & SSHCONF_CHECKPERM) {
2712 struct stat sb;
2713
2714 if (fstat(fileno(f), &sb) == -1)
2715 fatal("fstat %s: %s", filename, strerror(errno));
2716 if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
2717 (sb.st_mode & 022) != 0))
2718 fatal("Bad owner or permissions on %s", filename);
2719 }
2720
2721 debug("Reading configuration data %.200s", filename);
2722
2723 /*
2724 * Mark that we are now processing the options. This flag is turned
2725 * on/off by Host specifications.
2726 */
2727 linenum = 0;
2728 while (getline(&line, &linesize, f) != -1) {
2729 /* Update line number counter. */
2730 linenum++;
2731 /*
2732 * Trim out comments and strip whitespace.
2733 * NB - preserve newlines, they are needed to reproduce
2734 * line numbers later for error messages.
2735 */
2736 if (process_config_line_depth(options, pw, host, original_host,
2737 remote_command, line, filename, linenum, activep, flags,
2738 want_final_pass, depth) != 0)
2739 bad_options++;
2740 }
2741 free(line);
2742 fclose(f);
2743 if (bad_options > 0)
2744 fatal("%s: terminating, %d bad configuration options",
2745 filename, bad_options);
2746 return 1;
2747 }
2748
2749 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
2750 int
2751 option_clear_or_none(const char *o)
2752 {
2753 return o == NULL || strcasecmp(o, "none") == 0;
2754 }
2755
2756 /*
2757 * Returns 1 if CanonicalizePermittedCNAMEs have been specified, 0 otherwise.
2758 * Allowed to be called on non-final configuration.
2759 */
2760 int
2761 config_has_permitted_cnames(Options *options)
2762 {
2763 if (options->num_permitted_cnames == 1 &&
2764 strcasecmp(options->permitted_cnames[0].source_list, "none") == 0 &&
2765 strcmp(options->permitted_cnames[0].target_list, "") == 0)
2766 return 0;
2767 return options->num_permitted_cnames > 0;
2768 }
2769
2770 /*
2771 * Initializes options to special values that indicate that they have not yet
2772 * been set. Read_config_file will only set options with this value. Options
2773 * are processed in the following order: command line, user config file,
2774 * system config file. Last, fill_default_options is called.
2775 */
2776
2777 void
2778 initialize_options(Options * options)
2779 {
2780 memset(options, 'X', sizeof(*options));
2781 options->host_arg = NULL;
2782 options->forward_agent = -1;
2783 options->forward_agent_sock_path = NULL;
2784 options->forward_x11 = -1;
2785 options->forward_x11_trusted = -1;
2786 options->forward_x11_timeout = -1;
2787 options->stdio_forward_host = NULL;
2788 options->stdio_forward_port = 0;
2789 options->clear_forwardings = -1;
2790 options->exit_on_forward_failure = -1;
2791 options->xauth_location = NULL;
2792 options->fwd_opts.gateway_ports = -1;
2793 options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
2794 options->fwd_opts.streamlocal_bind_unlink = -1;
2795 options->pubkey_authentication = -1;
2796 #if defined(KRB4) || defined(KRB5)
2797 options->kerberos_authentication = -1;
2798 #endif
2799 #if defined(AFS) || defined(KRB5)
2800 options->kerberos_tgt_passing = -1;
2801 #endif
2802 #ifdef AFS
2803 options->afs_token_passing = -1;
2804 #endif
2805 options->gss_authentication = -1;
2806 options->gss_deleg_creds = -1;
2807 options->password_authentication = -1;
2808 options->kbd_interactive_authentication = -1;
2809 options->kbd_interactive_devices = NULL;
2810 options->hostbased_authentication = -1;
2811 options->batch_mode = -1;
2812 options->check_host_ip = -1;
2813 options->strict_host_key_checking = -1;
2814 options->compression = -1;
2815 options->tcp_keep_alive = -1;
2816 options->port = -1;
2817 options->address_family = -1;
2818 options->connection_attempts = -1;
2819 options->connection_timeout = -1;
2820 options->number_of_password_prompts = -1;
2821 options->ciphers = NULL;
2822 options->macs = NULL;
2823 options->kex_algorithms = NULL;
2824 options->hostkeyalgorithms = NULL;
2825 options->ca_sign_algorithms = NULL;
2826 options->num_identity_files = 0;
2827 memset(options->identity_keys, 0, sizeof(options->identity_keys));
2828 options->num_certificate_files = 0;
2829 memset(options->certificates, 0, sizeof(options->certificates));
2830 options->hostname = NULL;
2831 options->host_key_alias = NULL;
2832 options->proxy_command = NULL;
2833 options->jump_user = NULL;
2834 options->jump_host = NULL;
2835 options->jump_port = -1;
2836 options->jump_extra = NULL;
2837 options->user = NULL;
2838 options->escape_char = -1;
2839 options->num_system_hostfiles = 0;
2840 options->num_user_hostfiles = 0;
2841 options->local_forwards = NULL;
2842 options->num_local_forwards = 0;
2843 options->remote_forwards = NULL;
2844 options->num_remote_forwards = 0;
2845 options->permitted_remote_opens = NULL;
2846 options->num_permitted_remote_opens = 0;
2847 options->log_facility = SYSLOG_FACILITY_NOT_SET;
2848 options->log_level = SYSLOG_LEVEL_NOT_SET;
2849 options->num_log_verbose = 0;
2850 options->log_verbose = NULL;
2851 options->preferred_authentications = NULL;
2852 options->bind_address = NULL;
2853 options->bind_interface = NULL;
2854 options->ipv6_prefer_temporary = -1;
2855 options->pkcs11_provider = NULL;
2856 options->sk_provider = NULL;
2857 options->enable_ssh_keysign = - 1;
2858 options->no_host_authentication_for_localhost = - 1;
2859 options->identities_only = - 1;
2860 options->rekey_limit = - 1;
2861 options->rekey_interval = -1;
2862 options->verify_host_key_dns = -1;
2863 options->server_alive_interval = -1;
2864 options->server_alive_count_max = -1;
2865 options->send_env = NULL;
2866 options->num_send_env = 0;
2867 options->setenv = NULL;
2868 options->num_setenv = 0;
2869 options->control_path = NULL;
2870 options->control_master = -1;
2871 options->control_persist = -1;
2872 options->control_persist_timeout = 0;
2873 options->hash_known_hosts = -1;
2874 options->tun_open = -1;
2875 options->tun_local = -1;
2876 options->tun_remote = -1;
2877 options->local_command = NULL;
2878 options->permit_local_command = -1;
2879 options->remote_command = NULL;
2880 options->add_keys_to_agent = -1;
2881 options->add_keys_to_agent_lifespan = -1;
2882 options->identity_agent = NULL;
2883 options->visual_host_key = -1;
2884 options->ip_qos_interactive = -1;
2885 options->ip_qos_bulk = -1;
2886 options->request_tty = -1;
2887 options->session_type = -1;
2888 options->stdin_null = -1;
2889 options->fork_after_authentication = -1;
2890 options->proxy_use_fdpass = -1;
2891 options->ignored_unknown = NULL;
2892 options->num_canonical_domains = 0;
2893 options->num_permitted_cnames = 0;
2894 options->canonicalize_max_dots = -1;
2895 options->canonicalize_fallback_local = -1;
2896 options->canonicalize_hostname = -1;
2897 options->revoked_host_keys = NULL;
2898 options->fingerprint_hash = -1;
2899 options->update_hostkeys = -1;
2900 options->hostbased_accepted_algos = NULL;
2901 options->pubkey_accepted_algos = NULL;
2902 options->known_hosts_command = NULL;
2903 options->required_rsa_size = -1;
2904 options->warn_weak_crypto = -1;
2905 options->enable_escape_commandline = -1;
2906 options->obscure_keystroke_timing_interval = -1;
2907 options->tag = NULL;
2908 options->channel_timeouts = NULL;
2909 options->num_channel_timeouts = 0;
2910 options->version_addendum = NULL;
2911 options->none_switch = -1;
2912 options->none_enabled = -1;
2913 options->hpn_disabled = -1;
2914 options->hpn_buffer_size = -1;
2915 options->tcp_rcv_buf_poll = -1;
2916 options->tcp_rcv_buf = -1;
2917 options->send_version_first = -1;
2918 }
2919
2920 /*
2921 * A petite version of fill_default_options() that just fills the options
2922 * needed for hostname canonicalization to proceed.
2923 */
2924 void
2925 fill_default_options_for_canonicalization(Options *options)
2926 {
2927 if (options->canonicalize_max_dots == -1)
2928 options->canonicalize_max_dots = 1;
2929 if (options->canonicalize_fallback_local == -1)
2930 options->canonicalize_fallback_local = 1;
2931 if (options->canonicalize_hostname == -1)
2932 options->canonicalize_hostname = SSH_CANONICALISE_NO;
2933 }
2934
2935 /*
2936 * Called after processing other sources of option data, this fills those
2937 * options for which no value has been specified with their default values.
2938 */
2939 int
2940 fill_default_options(Options * options)
2941 {
2942 char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
2943 char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
2944 int ret = 0, r;
2945
2946 if (options->forward_agent == -1)
2947 options->forward_agent = 0;
2948 if (options->forward_x11 == -1)
2949 options->forward_x11 = 0;
2950 if (options->forward_x11_trusted == -1)
2951 options->forward_x11_trusted = 0;
2952 if (options->forward_x11_timeout == -1)
2953 options->forward_x11_timeout = 1200;
2954 /*
2955 * stdio forwarding (-W) changes the default for these but we defer
2956 * setting the values so they can be overridden.
2957 */
2958 if (options->exit_on_forward_failure == -1)
2959 options->exit_on_forward_failure =
2960 options->stdio_forward_host != NULL ? 1 : 0;
2961 if (options->clear_forwardings == -1)
2962 options->clear_forwardings =
2963 options->stdio_forward_host != NULL ? 1 : 0;
2964 if (options->clear_forwardings == 1)
2965 clear_forwardings(options);
2966
2967 if (options->xauth_location == NULL)
2968 options->xauth_location = xstrdup(_PATH_XAUTH);
2969 if (options->fwd_opts.gateway_ports == -1)
2970 options->fwd_opts.gateway_ports = 0;
2971 if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
2972 options->fwd_opts.streamlocal_bind_mask = 0177;
2973 if (options->fwd_opts.streamlocal_bind_unlink == -1)
2974 options->fwd_opts.streamlocal_bind_unlink = 0;
2975 if (options->pubkey_authentication == -1)
2976 options->pubkey_authentication = SSH_PUBKEY_AUTH_ALL;
2977 #if defined(KRB4) || defined(KRB5)
2978 if (options->kerberos_authentication == -1)
2979 options->kerberos_authentication = 1;
2980 #endif
2981 #if defined(AFS) || defined(KRB5)
2982 if (options->kerberos_tgt_passing == -1)
2983 options->kerberos_tgt_passing = 1;
2984 #endif
2985 #ifdef AFS
2986 if (options->afs_token_passing == -1)
2987 options->afs_token_passing = 1;
2988 #endif
2989 if (options->gss_authentication == -1)
2990 options->gss_authentication = 0;
2991 if (options->gss_deleg_creds == -1)
2992 options->gss_deleg_creds = 0;
2993 if (options->password_authentication == -1)
2994 options->password_authentication = 1;
2995 if (options->kbd_interactive_authentication == -1)
2996 options->kbd_interactive_authentication = 1;
2997 if (options->hostbased_authentication == -1)
2998 options->hostbased_authentication = 0;
2999 if (options->batch_mode == -1)
3000 options->batch_mode = 0;
3001 if (options->check_host_ip == -1)
3002 options->check_host_ip = 0;
3003 if (options->strict_host_key_checking == -1)
3004 options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK;
3005 if (options->compression == -1)
3006 options->compression = 0;
3007 if (options->tcp_keep_alive == -1)
3008 options->tcp_keep_alive = 1;
3009 if (options->port == -1)
3010 options->port = 0; /* Filled in ssh_connect. */
3011 if (options->address_family == -1)
3012 options->address_family = AF_UNSPEC;
3013 if (options->connection_attempts == -1)
3014 options->connection_attempts = 1;
3015 if (options->number_of_password_prompts == -1)
3016 options->number_of_password_prompts = 3;
3017 /* options->hostkeyalgorithms, default set in myproposals.h */
3018 if (options->add_keys_to_agent == -1) {
3019 options->add_keys_to_agent = 0;
3020 options->add_keys_to_agent_lifespan = 0;
3021 }
3022 if (options->num_identity_files == 0) {
3023 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0);
3024 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0);
3025 add_identity_file(options, "~/",
3026 _PATH_SSH_CLIENT_ID_ECDSA_SK, 0);
3027 add_identity_file(options, "~/",
3028 _PATH_SSH_CLIENT_ID_ED25519, 0);
3029 add_identity_file(options, "~/",
3030 _PATH_SSH_CLIENT_ID_ED25519_SK, 0);
3031 }
3032 if (options->escape_char == -1)
3033 options->escape_char = '~';
3034 if (options->num_system_hostfiles == 0) {
3035 options->system_hostfiles[options->num_system_hostfiles++] =
3036 xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
3037 options->system_hostfiles[options->num_system_hostfiles++] =
3038 xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
3039 }
3040 if (options->update_hostkeys == -1) {
3041 if (options->verify_host_key_dns <= 0 &&
3042 (options->num_user_hostfiles == 0 ||
3043 (options->num_user_hostfiles == 1 && strcmp(options->
3044 user_hostfiles[0], _PATH_SSH_USER_HOSTFILE) == 0)))
3045 options->update_hostkeys = SSH_UPDATE_HOSTKEYS_YES;
3046 else
3047 options->update_hostkeys = SSH_UPDATE_HOSTKEYS_NO;
3048 }
3049 if (options->num_user_hostfiles == 0) {
3050 options->user_hostfiles[options->num_user_hostfiles++] =
3051 xstrdup(_PATH_SSH_USER_HOSTFILE);
3052 options->user_hostfiles[options->num_user_hostfiles++] =
3053 xstrdup(_PATH_SSH_USER_HOSTFILE2);
3054 }
3055 if (options->log_level == SYSLOG_LEVEL_NOT_SET)
3056 options->log_level = SYSLOG_LEVEL_INFO;
3057 if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
3058 options->log_facility = SYSLOG_FACILITY_USER;
3059 if (options->no_host_authentication_for_localhost == - 1)
3060 options->no_host_authentication_for_localhost = 0;
3061 if (options->identities_only == -1)
3062 options->identities_only = 0;
3063 if (options->enable_ssh_keysign == -1)
3064 options->enable_ssh_keysign = 0;
3065 if (options->rekey_limit == -1)
3066 options->rekey_limit = 0;
3067 if (options->rekey_interval == -1)
3068 options->rekey_interval = 0;
3069 if (options->verify_host_key_dns == -1)
3070 options->verify_host_key_dns = 0;
3071 if (options->server_alive_interval == -1)
3072 options->server_alive_interval = 0;
3073 if (options->server_alive_count_max == -1)
3074 options->server_alive_count_max = 3;
3075 if (options->none_switch == -1)
3076 options->none_switch = 0;
3077 if (options->hpn_disabled == -1)
3078 options->hpn_disabled = 0;
3079 if (options->hpn_buffer_size > -1)
3080 {
3081 /* if a user tries to set the size to 0 set it to 1KB */
3082 if (options->hpn_buffer_size == 0)
3083 options->hpn_buffer_size = 1;
3084 /*limit the buffer to 64MB*/
3085 if (options->hpn_buffer_size > (SSHBUF_SIZE_MAX / 1024))
3086 {
3087 options->hpn_buffer_size = SSHBUF_SIZE_MAX;
3088 debug("User requested buffer larger than 256MB. Request reverted to 256MB");
3089 } else
3090 options->hpn_buffer_size *= 1024;
3091 debug("hpn_buffer_size set to %d", options->hpn_buffer_size);
3092 }
3093 if (options->tcp_rcv_buf == 0)
3094 options->tcp_rcv_buf = 1;
3095 if (options->tcp_rcv_buf > -1)
3096 options->tcp_rcv_buf *=1024;
3097 if (options->tcp_rcv_buf_poll == -1)
3098 options->tcp_rcv_buf_poll = 1;
3099 if (options->control_master == -1)
3100 options->control_master = 0;
3101 if (options->control_persist == -1) {
3102 options->control_persist = 0;
3103 options->control_persist_timeout = 0;
3104 }
3105 if (options->hash_known_hosts == -1)
3106 options->hash_known_hosts = 0;
3107 if (options->tun_open == -1)
3108 options->tun_open = SSH_TUNMODE_NO;
3109 if (options->tun_local == -1)
3110 options->tun_local = SSH_TUNID_ANY;
3111 if (options->tun_remote == -1)
3112 options->tun_remote = SSH_TUNID_ANY;
3113 if (options->permit_local_command == -1)
3114 options->permit_local_command = 0;
3115 if (options->visual_host_key == -1)
3116 options->visual_host_key = 0;
3117 if (options->ip_qos_interactive == -1)
3118 options->ip_qos_interactive = IPTOS_DSCP_EF;
3119 if (options->ip_qos_bulk == -1)
3120 options->ip_qos_bulk = IPTOS_DSCP_CS0;
3121 if (options->request_tty == -1)
3122 options->request_tty = REQUEST_TTY_AUTO;
3123 if (options->session_type == -1)
3124 options->session_type = SESSION_TYPE_DEFAULT;
3125 if (options->stdin_null == -1)
3126 options->stdin_null = 0;
3127 if (options->fork_after_authentication == -1)
3128 options->fork_after_authentication = 0;
3129 if (options->proxy_use_fdpass == -1)
3130 options->proxy_use_fdpass = 0;
3131 if (options->canonicalize_max_dots == -1)
3132 options->canonicalize_max_dots = 1;
3133 if (options->canonicalize_fallback_local == -1)
3134 options->canonicalize_fallback_local = 1;
3135 if (options->canonicalize_hostname == -1)
3136 options->canonicalize_hostname = SSH_CANONICALISE_NO;
3137 if (options->fingerprint_hash == -1)
3138 options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
3139 if (options->sk_provider == NULL)
3140 options->sk_provider = xstrdup("internal");
3141 if (options->required_rsa_size == -1)
3142 options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
3143 if (options->warn_weak_crypto == -1)
3144 options->warn_weak_crypto = 1;
3145 if (options->enable_escape_commandline == -1)
3146 options->enable_escape_commandline = 0;
3147 if (options->obscure_keystroke_timing_interval == -1) {
3148 options->obscure_keystroke_timing_interval =
3149 SSH_KEYSTROKE_DEFAULT_INTERVAL_MS;
3150 }
3151
3152 /* Expand KEX name lists */
3153 all_cipher = cipher_alg_list(',', 0);
3154 all_mac = mac_alg_list(',');
3155 all_kex = kex_alg_list(',');
3156 all_key = sshkey_alg_list(0, 0, 1, ',');
3157 all_sig = sshkey_alg_list(0, 1, 1, ',');
3158 /* remove unsupported algos from default lists */
3159 def_cipher = match_filter_allowlist(KEX_CLIENT_ENCRYPT, all_cipher);
3160 def_mac = match_filter_allowlist(KEX_CLIENT_MAC, all_mac);
3161 def_kex = match_filter_allowlist(KEX_CLIENT_KEX, all_kex);
3162 def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
3163 def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
3164 #define ASSEMBLE(what, defaults, all) \
3165 do { \
3166 if ((r = kex_assemble_names(&options->what, \
3167 defaults, all)) != 0) { \
3168 error_fr(r, "%s", #what); \
3169 goto fail; \
3170 } \
3171 } while (0)
3172 options->kex_algorithms_set = options->kex_algorithms != NULL;
3173 ASSEMBLE(ciphers, def_cipher, all_cipher);
3174 ASSEMBLE(macs, def_mac, all_mac);
3175 ASSEMBLE(kex_algorithms, def_kex, all_kex);
3176 ASSEMBLE(hostbased_accepted_algos, def_key, all_key);
3177 ASSEMBLE(pubkey_accepted_algos, def_key, all_key);
3178 ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
3179 #undef ASSEMBLE
3180
3181 if (options->send_version_first == -1)
3182 options->send_version_first = 1;
3183 #define CLEAR_ON_NONE(v) \
3184 do { \
3185 if (option_clear_or_none(v)) { \
3186 free(v); \
3187 v = NULL; \
3188 } \
3189 } while(0)
3190 #define CLEAR_ON_NONE_ARRAY(v, nv, none) \
3191 do { \
3192 if (options->nv == 1 && \
3193 strcasecmp(options->v[0], none) == 0) { \
3194 free(options->v[0]); \
3195 free(options->v); \
3196 options->v = NULL; \
3197 options->nv = 0; \
3198 } \
3199 } while (0)
3200 CLEAR_ON_NONE(options->local_command);
3201 CLEAR_ON_NONE(options->remote_command);
3202 CLEAR_ON_NONE(options->proxy_command);
3203 CLEAR_ON_NONE(options->control_path);
3204 CLEAR_ON_NONE(options->revoked_host_keys);
3205 CLEAR_ON_NONE(options->pkcs11_provider);
3206 CLEAR_ON_NONE(options->sk_provider);
3207 CLEAR_ON_NONE(options->known_hosts_command);
3208 CLEAR_ON_NONE_ARRAY(channel_timeouts, num_channel_timeouts, "none");
3209 #undef CLEAR_ON_NONE
3210 #undef CLEAR_ON_NONE_ARRAY
3211 if (options->jump_host != NULL &&
3212 strcmp(options->jump_host, "none") == 0 &&
3213 options->jump_port == 0 && options->jump_user == NULL) {
3214 free(options->jump_host);
3215 options->jump_host = NULL;
3216 }
3217 if (options->num_permitted_cnames == 1 &&
3218 !config_has_permitted_cnames(options)) {
3219 /* clean up CanonicalizePermittedCNAMEs=none */
3220 free(options->permitted_cnames[0].source_list);
3221 free(options->permitted_cnames[0].target_list);
3222 memset(options->permitted_cnames, '\0',
3223 sizeof(*options->permitted_cnames));
3224 options->num_permitted_cnames = 0;
3225 }
3226 /* options->identity_agent distinguishes NULL from 'none' */
3227 /* options->user will be set in the main program if appropriate */
3228 /* options->hostname will be set in the main program if appropriate */
3229 /* options->host_key_alias should not be set by default */
3230 /* options->preferred_authentications will be set in ssh */
3231
3232 /* success */
3233 ret = 0;
3234 fail:
3235 free(all_cipher);
3236 free(all_mac);
3237 free(all_kex);
3238 free(all_key);
3239 free(all_sig);
3240 free(def_cipher);
3241 free(def_mac);
3242 free(def_kex);
3243 free(def_key);
3244 free(def_sig);
3245 return ret;
3246 }
3247
3248 void
3249 free_options(Options *o)
3250 {
3251 int i;
3252
3253 if (o == NULL)
3254 return;
3255
3256 #define FREE_ARRAY(type, n, a) \
3257 do { \
3258 type _i; \
3259 for (_i = 0; _i < (n); _i++) \
3260 free((a)[_i]); \
3261 } while (0)
3262
3263 free(o->forward_agent_sock_path);
3264 free(o->xauth_location);
3265 FREE_ARRAY(u_int, o->num_log_verbose, o->log_verbose);
3266 free(o->log_verbose);
3267 free(o->ciphers);
3268 free(o->macs);
3269 free(o->hostkeyalgorithms);
3270 free(o->kex_algorithms);
3271 free(o->ca_sign_algorithms);
3272 free(o->hostname);
3273 free(o->host_key_alias);
3274 free(o->proxy_command);
3275 free(o->user);
3276 FREE_ARRAY(u_int, o->num_system_hostfiles, o->system_hostfiles);
3277 FREE_ARRAY(u_int, o->num_user_hostfiles, o->user_hostfiles);
3278 free(o->preferred_authentications);
3279 free(o->bind_address);
3280 free(o->bind_interface);
3281 free(o->pkcs11_provider);
3282 free(o->sk_provider);
3283 for (i = 0; i < o->num_identity_files; i++) {
3284 free(o->identity_files[i]);
3285 sshkey_free(o->identity_keys[i]);
3286 }
3287 for (i = 0; i < o->num_certificate_files; i++) {
3288 free(o->certificate_files[i]);
3289 sshkey_free(o->certificates[i]);
3290 }
3291 free(o->identity_agent);
3292 for (i = 0; i < o->num_local_forwards; i++) {
3293 free(o->local_forwards[i].listen_host);
3294 free(o->local_forwards[i].listen_path);
3295 free(o->local_forwards[i].connect_host);
3296 free(o->local_forwards[i].connect_path);
3297 }
3298 free(o->local_forwards);
3299 for (i = 0; i < o->num_remote_forwards; i++) {
3300 free(o->remote_forwards[i].listen_host);
3301 free(o->remote_forwards[i].listen_path);
3302 free(o->remote_forwards[i].connect_host);
3303 free(o->remote_forwards[i].connect_path);
3304 }
3305 free(o->remote_forwards);
3306 free(o->stdio_forward_host);
3307 FREE_ARRAY(u_int, o->num_send_env, o->send_env);
3308 free(o->send_env);
3309 FREE_ARRAY(u_int, o->num_setenv, o->setenv);
3310 free(o->setenv);
3311 free(o->control_path);
3312 free(o->local_command);
3313 free(o->remote_command);
3314 FREE_ARRAY(int, o->num_canonical_domains, o->canonical_domains);
3315 for (i = 0; i < o->num_permitted_cnames; i++) {
3316 free(o->permitted_cnames[i].source_list);
3317 free(o->permitted_cnames[i].target_list);
3318 }
3319 free(o->revoked_host_keys);
3320 free(o->hostbased_accepted_algos);
3321 free(o->pubkey_accepted_algos);
3322 free(o->jump_user);
3323 free(o->jump_host);
3324 free(o->jump_extra);
3325 free(o->ignored_unknown);
3326 explicit_bzero(o, sizeof(*o));
3327 #undef FREE_ARRAY
3328 }
3329
3330 struct fwdarg {
3331 char *arg;
3332 int ispath;
3333 };
3334
3335 /*
3336 * parse_fwd_field
3337 * parses the next field in a port forwarding specification.
3338 * sets fwd to the parsed field and advances p past the colon
3339 * or sets it to NULL at end of string.
3340 * returns 0 on success, else non-zero.
3341 */
3342 static int
3343 parse_fwd_field(char **p, struct fwdarg *fwd)
3344 {
3345 char *ep, *cp = *p;
3346 int ispath = 0;
3347
3348 if (*cp == '\0') {
3349 *p = NULL;
3350 return -1; /* end of string */
3351 }
3352
3353 /*
3354 * A field escaped with square brackets is used literally.
3355 * XXX - allow ']' to be escaped via backslash?
3356 */
3357 if (*cp == '[') {
3358 /* find matching ']' */
3359 for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
3360 if (*ep == '/')
3361 ispath = 1;
3362 }
3363 /* no matching ']' or not at end of field. */
3364 if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
3365 return -1;
3366 /* NUL terminate the field and advance p past the colon */
3367 *ep++ = '\0';
3368 if (*ep != '\0')
3369 *ep++ = '\0';
3370 fwd->arg = cp + 1;
3371 fwd->ispath = ispath;
3372 *p = ep;
3373 return 0;
3374 }
3375
3376 for (cp = *p; *cp != '\0'; cp++) {
3377 switch (*cp) {
3378 case '\\':
3379 memmove(cp, cp + 1, strlen(cp + 1) + 1);
3380 if (*cp == '\0')
3381 return -1;
3382 break;
3383 case '/':
3384 ispath = 1;
3385 break;
3386 case ':':
3387 *cp++ = '\0';
3388 goto done;
3389 }
3390 }
3391 done:
3392 fwd->arg = *p;
3393 fwd->ispath = ispath;
3394 *p = cp;
3395 return 0;
3396 }
3397
3398 /*
3399 * parse_forward
3400 * parses a string containing a port forwarding specification of the form:
3401 * dynamicfwd == 0
3402 * [listenhost:]listenport|listenpath:connecthost:connectport|connectpath
3403 * listenpath:connectpath
3404 * dynamicfwd == 1
3405 * [listenhost:]listenport
3406 * returns number of arguments parsed or zero on error
3407 */
3408 int
3409 parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
3410 {
3411 struct fwdarg fwdargs[4];
3412 char *p, *cp;
3413 int i, err;
3414
3415 memset(fwd, 0, sizeof(*fwd));
3416 memset(fwdargs, 0, sizeof(fwdargs));
3417
3418 /*
3419 * We expand environment variables before checking if we think they're
3420 * paths so that if ${VAR} expands to a fully qualified path it is
3421 * treated as a path.
3422 */
3423 cp = p = dollar_expand(&err, fwdspec);
3424 if (p == NULL || err)
3425 return 0;
3426
3427 /* skip leading spaces */
3428 while (isspace((u_char)*cp))
3429 cp++;
3430
3431 for (i = 0; i < 4; ++i) {
3432 if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
3433 break;
3434 }
3435
3436 /* Check for trailing garbage */
3437 if (cp != NULL && *cp != '\0') {
3438 i = 0; /* failure */
3439 }
3440
3441 switch (i) {
3442 case 1:
3443 if (fwdargs[0].ispath) {
3444 fwd->listen_path = xstrdup(fwdargs[0].arg);
3445 fwd->listen_port = PORT_STREAMLOCAL;
3446 } else {
3447 fwd->listen_host = NULL;
3448 fwd->listen_port = a2port(fwdargs[0].arg);
3449 }
3450 fwd->connect_host = xstrdup("socks");
3451 break;
3452
3453 case 2:
3454 if (fwdargs[0].ispath && fwdargs[1].ispath) {
3455 fwd->listen_path = xstrdup(fwdargs[0].arg);
3456 fwd->listen_port = PORT_STREAMLOCAL;
3457 fwd->connect_path = xstrdup(fwdargs[1].arg);
3458 fwd->connect_port = PORT_STREAMLOCAL;
3459 } else if (fwdargs[1].ispath) {
3460 fwd->listen_host = NULL;
3461 fwd->listen_port = a2port(fwdargs[0].arg);
3462 fwd->connect_path = xstrdup(fwdargs[1].arg);
3463 fwd->connect_port = PORT_STREAMLOCAL;
3464 } else {
3465 fwd->listen_host = xstrdup(fwdargs[0].arg);
3466 fwd->listen_port = a2port(fwdargs[1].arg);
3467 fwd->connect_host = xstrdup("socks");
3468 }
3469 break;
3470
3471 case 3:
3472 if (fwdargs[0].ispath) {
3473 fwd->listen_path = xstrdup(fwdargs[0].arg);
3474 fwd->listen_port = PORT_STREAMLOCAL;
3475 fwd->connect_host = xstrdup(fwdargs[1].arg);
3476 fwd->connect_port = a2port(fwdargs[2].arg);
3477 } else if (fwdargs[2].ispath) {
3478 fwd->listen_host = xstrdup(fwdargs[0].arg);
3479 fwd->listen_port = a2port(fwdargs[1].arg);
3480 fwd->connect_path = xstrdup(fwdargs[2].arg);
3481 fwd->connect_port = PORT_STREAMLOCAL;
3482 } else {
3483 fwd->listen_host = NULL;
3484 fwd->listen_port = a2port(fwdargs[0].arg);
3485 fwd->connect_host = xstrdup(fwdargs[1].arg);
3486 fwd->connect_port = a2port(fwdargs[2].arg);
3487 }
3488 break;
3489
3490 case 4:
3491 fwd->listen_host = xstrdup(fwdargs[0].arg);
3492 fwd->listen_port = a2port(fwdargs[1].arg);
3493 fwd->connect_host = xstrdup(fwdargs[2].arg);
3494 fwd->connect_port = a2port(fwdargs[3].arg);
3495 break;
3496 default:
3497 i = 0; /* failure */
3498 }
3499
3500 free(p);
3501
3502 if (dynamicfwd) {
3503 if (!(i == 1 || i == 2))
3504 goto fail_free;
3505 } else {
3506 if (!(i == 3 || i == 4)) {
3507 if (fwd->connect_path == NULL &&
3508 fwd->listen_path == NULL)
3509 goto fail_free;
3510 }
3511 if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
3512 goto fail_free;
3513 }
3514
3515 if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
3516 (!remotefwd && fwd->listen_port == 0))
3517 goto fail_free;
3518 if (fwd->connect_host != NULL &&
3519 strlen(fwd->connect_host) >= NI_MAXHOST)
3520 goto fail_free;
3521 /*
3522 * XXX - if connecting to a remote socket, max sun len may not
3523 * match this host
3524 */
3525 if (fwd->connect_path != NULL &&
3526 strlen(fwd->connect_path) >= PATH_MAX_SUN)
3527 goto fail_free;
3528 if (fwd->listen_host != NULL &&
3529 strlen(fwd->listen_host) >= NI_MAXHOST)
3530 goto fail_free;
3531 if (fwd->listen_path != NULL &&
3532 strlen(fwd->listen_path) >= PATH_MAX_SUN)
3533 goto fail_free;
3534
3535 return (i);
3536
3537 fail_free:
3538 free(fwd->connect_host);
3539 fwd->connect_host = NULL;
3540 free(fwd->connect_path);
3541 fwd->connect_path = NULL;
3542 free(fwd->listen_host);
3543 fwd->listen_host = NULL;
3544 free(fwd->listen_path);
3545 fwd->listen_path = NULL;
3546 return (0);
3547 }
3548
3549 int
3550 parse_jump(const char *s, Options *o, int active)
3551 {
3552 char *orig, *sdup, *cp;
3553 char *host = NULL, *user = NULL;
3554 int r, ret = -1, port = -1, first;
3555
3556 active &= o->proxy_command == NULL && o->jump_host == NULL;
3557
3558 orig = sdup = xstrdup(s);
3559
3560 /* Remove comment and trailing whitespace */
3561 if ((cp = strchr(orig, '#')) != NULL)
3562 *cp = '\0';
3563 rtrim(orig);
3564
3565 first = active;
3566 do {
3567 if (strcasecmp(s, "none") == 0)
3568 break;
3569 if ((cp = strrchr(sdup, ',')) == NULL)
3570 cp = sdup; /* last */
3571 else
3572 *cp++ = '\0';
3573
3574 if (first) {
3575 /* First argument and configuration is active */
3576 r = parse_ssh_uri(cp, &user, &host, &port);
3577 if (r == -1 || (r == 1 &&
3578 parse_user_host_port(cp, &user, &host, &port) != 0))
3579 goto out;
3580 } else {
3581 /* Subsequent argument or inactive configuration */
3582 r = parse_ssh_uri(cp, NULL, NULL, NULL);
3583 if (r == -1 || (r == 1 &&
3584 parse_user_host_port(cp, NULL, NULL, NULL) != 0))
3585 goto out;
3586 }
3587 first = 0; /* only check syntax for subsequent hosts */
3588 } while (cp != sdup);
3589 /* success */
3590 if (active) {
3591 if (strcasecmp(s, "none") == 0) {
3592 o->jump_host = xstrdup("none");
3593 o->jump_port = 0;
3594 } else {
3595 o->jump_user = user;
3596 o->jump_host = host;
3597 o->jump_port = port;
3598 o->proxy_command = xstrdup("none");
3599 user = host = NULL;
3600 if ((cp = strrchr(s, ',')) != NULL && cp != s) {
3601 o->jump_extra = xstrdup(s);
3602 o->jump_extra[cp - s] = '\0';
3603 }
3604 }
3605 }
3606 ret = 0;
3607 out:
3608 free(orig);
3609 free(user);
3610 free(host);
3611 return ret;
3612 }
3613
3614 int
3615 parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp)
3616 {
3617 char *user = NULL, *host = NULL, *path = NULL;
3618 int r, port;
3619
3620 r = parse_uri("ssh", uri, &user, &host, &port, &path);
3621 if (r == 0 && path != NULL)
3622 r = -1; /* path not allowed */
3623 if (r == 0) {
3624 if (userp != NULL) {
3625 *userp = user;
3626 user = NULL;
3627 }
3628 if (hostp != NULL) {
3629 *hostp = host;
3630 host = NULL;
3631 }
3632 if (portp != NULL)
3633 *portp = port;
3634 }
3635 free(user);
3636 free(host);
3637 free(path);
3638 return r;
3639 }
3640
3641 /* XXX the following is a near-verbatim copy from servconf.c; refactor */
3642 static const char *
3643 fmt_multistate_int(int val, const struct multistate *m)
3644 {
3645 u_int i;
3646
3647 for (i = 0; m[i].key != NULL; i++) {
3648 if (m[i].value == val)
3649 return m[i].key;
3650 }
3651 return "UNKNOWN";
3652 }
3653
3654 static const char *
3655 fmt_intarg(OpCodes code, int val)
3656 {
3657 if (val == -1)
3658 return "unset";
3659 switch (code) {
3660 case oAddressFamily:
3661 return fmt_multistate_int(val, multistate_addressfamily);
3662 case oCompression:
3663 return fmt_multistate_int(val, multistate_compression);
3664 case oVerifyHostKeyDNS:
3665 case oUpdateHostkeys:
3666 return fmt_multistate_int(val, multistate_yesnoask);
3667 case oStrictHostKeyChecking:
3668 return fmt_multistate_int(val, multistate_strict_hostkey);
3669 case oControlMaster:
3670 return fmt_multistate_int(val, multistate_controlmaster);
3671 case oTunnel:
3672 return fmt_multistate_int(val, multistate_tunnel);
3673 case oRequestTTY:
3674 return fmt_multistate_int(val, multistate_requesttty);
3675 case oSessionType:
3676 return fmt_multistate_int(val, multistate_sessiontype);
3677 case oCanonicalizeHostname:
3678 return fmt_multistate_int(val, multistate_canonicalizehostname);
3679 case oAddKeysToAgent:
3680 return fmt_multistate_int(val, multistate_yesnoaskconfirm);
3681 case oPubkeyAuthentication:
3682 return fmt_multistate_int(val, multistate_pubkey_auth);
3683 case oFingerprintHash:
3684 return ssh_digest_alg_name(val);
3685 default:
3686 switch (val) {
3687 case 0:
3688 return "no";
3689 case 1:
3690 return "yes";
3691 default:
3692 return "UNKNOWN";
3693 }
3694 }
3695 }
3696
3697 static const char *
3698 lookup_opcode_name(OpCodes code)
3699 {
3700 u_int i;
3701
3702 for (i = 0; keywords[i].name != NULL; i++)
3703 if (keywords[i].opcode == code)
3704 return(keywords[i].name);
3705 return "UNKNOWN";
3706 }
3707
3708 static void
3709 dump_cfg_int(OpCodes code, int val)
3710 {
3711 if (code == oObscureKeystrokeTiming) {
3712 if (val == 0) {
3713 printf("%s no\n", lookup_opcode_name(code));
3714 return;
3715 } else if (val == SSH_KEYSTROKE_DEFAULT_INTERVAL_MS) {
3716 printf("%s yes\n", lookup_opcode_name(code));
3717 return;
3718 }
3719 /* FALLTHROUGH */
3720 }
3721 printf("%s %d\n", lookup_opcode_name(code), val);
3722 }
3723
3724 static void
3725 dump_cfg_fmtint(OpCodes code, int val)
3726 {
3727 printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
3728 }
3729
3730 static void
3731 dump_cfg_string(OpCodes code, const char *val)
3732 {
3733 if (val == NULL)
3734 return;
3735 printf("%s %s\n", lookup_opcode_name(code), val);
3736 }
3737
3738 static void
3739 dump_cfg_strarray(OpCodes code, u_int count, char **vals)
3740 {
3741 u_int i;
3742
3743 for (i = 0; i < count; i++)
3744 printf("%s %s\n", lookup_opcode_name(code), vals[i]);
3745 }
3746
3747 static void
3748 dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
3749 {
3750 u_int i;
3751
3752 printf("%s", lookup_opcode_name(code));
3753 if (count == 0)
3754 printf(" none");
3755 for (i = 0; i < count; i++)
3756 printf(" %s", vals[i]);
3757 printf("\n");
3758 }
3759
3760 static void
3761 dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
3762 {
3763 const struct Forward *fwd;
3764 u_int i;
3765
3766 /* oDynamicForward */
3767 for (i = 0; i < count; i++) {
3768 fwd = &fwds[i];
3769 if (code == oDynamicForward && fwd->connect_host != NULL &&
3770 strcmp(fwd->connect_host, "socks") != 0)
3771 continue;
3772 if (code == oLocalForward && fwd->connect_host != NULL &&
3773 strcmp(fwd->connect_host, "socks") == 0)
3774 continue;
3775 printf("%s", lookup_opcode_name(code));
3776 if (fwd->listen_port == PORT_STREAMLOCAL)
3777 printf(" %s", fwd->listen_path);
3778 else if (fwd->listen_host == NULL)
3779 printf(" %d", fwd->listen_port);
3780 else {
3781 printf(" [%s]:%d",
3782 fwd->listen_host, fwd->listen_port);
3783 }
3784 if (code != oDynamicForward) {
3785 if (fwd->connect_port == PORT_STREAMLOCAL)
3786 printf(" %s", fwd->connect_path);
3787 else if (fwd->connect_host == NULL)
3788 printf(" %d", fwd->connect_port);
3789 else {
3790 printf(" [%s]:%d",
3791 fwd->connect_host, fwd->connect_port);
3792 }
3793 }
3794 printf("\n");
3795 }
3796 }
3797
3798 void
3799 dump_client_config(Options *o, const char *host)
3800 {
3801 int i, r;
3802 char buf[8], *all_key;
3803
3804 /*
3805 * Expand HostKeyAlgorithms name lists. This isn't handled in
3806 * fill_default_options() like the other algorithm lists because
3807 * the host key algorithms are by default dynamically chosen based
3808 * on the host's keys found in known_hosts.
3809 */
3810 all_key = sshkey_alg_list(0, 0, 1, ',');
3811 if ((r = kex_assemble_names(&o->hostkeyalgorithms, kex_default_pk_alg(),
3812 all_key)) != 0)
3813 fatal_fr(r, "expand HostKeyAlgorithms");
3814 free(all_key);
3815
3816 /* Most interesting options first: user, host, port */
3817 dump_cfg_string(oHost, o->host_arg);
3818 dump_cfg_string(oUser, o->user);
3819 dump_cfg_string(oHostname, host);
3820 dump_cfg_int(oPort, o->port);
3821
3822 /* Flag options */
3823 dump_cfg_fmtint(oAddressFamily, o->address_family);
3824 dump_cfg_fmtint(oBatchMode, o->batch_mode);
3825 dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
3826 dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
3827 dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
3828 dump_cfg_fmtint(oCompression, o->compression);
3829 dump_cfg_fmtint(oControlMaster, o->control_master);
3830 dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
3831 dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
3832 dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
3833 dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
3834 dump_cfg_fmtint(oForwardX11, o->forward_x11);
3835 dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
3836 dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
3837 #ifdef GSSAPI
3838 dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
3839 dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
3840 #endif /* GSSAPI */
3841 dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
3842 dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
3843 dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
3844 dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
3845 dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
3846 dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
3847 dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
3848 dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
3849 dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
3850 dump_cfg_fmtint(oRequestTTY, o->request_tty);
3851 dump_cfg_fmtint(oSessionType, o->session_type);
3852 dump_cfg_fmtint(oStdinNull, o->stdin_null);
3853 dump_cfg_fmtint(oForkAfterAuthentication, o->fork_after_authentication);
3854 dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
3855 dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
3856 dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
3857 dump_cfg_fmtint(oTunnel, o->tun_open);
3858 dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
3859 dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
3860 dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
3861 dump_cfg_fmtint(oEnableEscapeCommandline, o->enable_escape_commandline);
3862 dump_cfg_fmtint(oWarnWeakCrypto, o->warn_weak_crypto);
3863
3864 /* Integer options */
3865 dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
3866 dump_cfg_int(oConnectionAttempts, o->connection_attempts);
3867 dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
3868 dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
3869 dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
3870 dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
3871 dump_cfg_int(oRequiredRSASize, o->required_rsa_size);
3872 dump_cfg_int(oObscureKeystrokeTiming,
3873 o->obscure_keystroke_timing_interval);
3874
3875 /* String options */
3876 dump_cfg_string(oBindAddress, o->bind_address);
3877 dump_cfg_string(oBindInterface, o->bind_interface);
3878 dump_cfg_string(oCiphers, o->ciphers);
3879 dump_cfg_string(oControlPath, o->control_path);
3880 dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
3881 dump_cfg_string(oHostKeyAlias, o->host_key_alias);
3882 dump_cfg_string(oHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
3883 dump_cfg_string(oIdentityAgent, o->identity_agent);
3884 dump_cfg_string(oIgnoreUnknown, o->ignored_unknown);
3885 dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
3886 dump_cfg_string(oKexAlgorithms, o->kex_algorithms);
3887 dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms);
3888 dump_cfg_string(oLocalCommand, o->local_command);
3889 dump_cfg_string(oRemoteCommand, o->remote_command);
3890 dump_cfg_string(oLogLevel, log_level_name(o->log_level));
3891 dump_cfg_string(oMacs, o->macs);
3892 #ifdef ENABLE_PKCS11
3893 dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
3894 #endif
3895 dump_cfg_string(oSecurityKeyProvider, o->sk_provider);
3896 dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
3897 dump_cfg_string(oPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
3898 dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
3899 dump_cfg_string(oXAuthLocation, o->xauth_location);
3900 dump_cfg_string(oKnownHostsCommand, o->known_hosts_command);
3901 dump_cfg_string(oTag, o->tag);
3902 dump_cfg_string(oVersionAddendum, o->version_addendum);
3903
3904 /* Forwards */
3905 dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
3906 dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
3907 dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
3908
3909 /* String array options */
3910 dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
3911 dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
3912 dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files);
3913 dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
3914 dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
3915 dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
3916 dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv);
3917 dump_cfg_strarray_oneline(oLogVerbose,
3918 o->num_log_verbose, o->log_verbose);
3919 dump_cfg_strarray_oneline(oChannelTimeout,
3920 o->num_channel_timeouts, o->channel_timeouts);
3921
3922 /* Special cases */
3923
3924 /* PermitRemoteOpen */
3925 if (o->num_permitted_remote_opens == 0)
3926 printf("%s any\n", lookup_opcode_name(oPermitRemoteOpen));
3927 else
3928 dump_cfg_strarray_oneline(oPermitRemoteOpen,
3929 o->num_permitted_remote_opens, o->permitted_remote_opens);
3930
3931 /* AddKeysToAgent */
3932 if (o->add_keys_to_agent_lifespan <= 0)
3933 dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent);
3934 else {
3935 printf("addkeystoagent%s %d\n",
3936 o->add_keys_to_agent == 3 ? " confirm" : "",
3937 o->add_keys_to_agent_lifespan);
3938 }
3939
3940 /* oForwardAgent */
3941 if (o->forward_agent_sock_path == NULL)
3942 dump_cfg_fmtint(oForwardAgent, o->forward_agent);
3943 else
3944 dump_cfg_string(oForwardAgent, o->forward_agent_sock_path);
3945
3946 /* oConnectTimeout */
3947 if (o->connection_timeout == -1)
3948 printf("connecttimeout none\n");
3949 else
3950 dump_cfg_int(oConnectTimeout, o->connection_timeout);
3951
3952 /* oTunnelDevice */
3953 printf("tunneldevice");
3954 if (o->tun_local == SSH_TUNID_ANY)
3955 printf(" any");
3956 else
3957 printf(" %d", o->tun_local);
3958 if (o->tun_remote == SSH_TUNID_ANY)
3959 printf(":any");
3960 else
3961 printf(":%d", o->tun_remote);
3962 printf("\n");
3963
3964 /* oCanonicalizePermittedCNAMEs */
3965 printf("canonicalizePermittedcnames");
3966 if (o->num_permitted_cnames == 0)
3967 printf(" none");
3968 for (i = 0; i < o->num_permitted_cnames; i++) {
3969 printf(" %s:%s", o->permitted_cnames[i].source_list,
3970 o->permitted_cnames[i].target_list);
3971 }
3972 printf("\n");
3973
3974 /* oControlPersist */
3975 if (o->control_persist == 0 || o->control_persist_timeout == 0)
3976 dump_cfg_fmtint(oControlPersist, o->control_persist);
3977 else
3978 dump_cfg_int(oControlPersist, o->control_persist_timeout);
3979
3980 /* oEscapeChar */
3981 if (o->escape_char == SSH_ESCAPECHAR_NONE)
3982 printf("escapechar none\n");
3983 else {
3984 vis(buf, o->escape_char, VIS_WHITE, 0);
3985 printf("escapechar %s\n", buf);
3986 }
3987
3988 /* oIPQoS */
3989 printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
3990 printf("%s\n", iptos2str(o->ip_qos_bulk));
3991
3992 /* oRekeyLimit */
3993 printf("rekeylimit %llu %d\n",
3994 (unsigned long long)o->rekey_limit, o->rekey_interval);
3995
3996 /* oStreamLocalBindMask */
3997 printf("streamlocalbindmask 0%o\n",
3998 o->fwd_opts.streamlocal_bind_mask);
3999
4000 /* oLogFacility */
4001 printf("syslogfacility %s\n", log_facility_name(o->log_facility));
4002
4003 /* oProxyCommand / oProxyJump */
4004 if (o->jump_host == NULL)
4005 dump_cfg_string(oProxyCommand, o->proxy_command);
4006 else {
4007 /* Check for numeric addresses */
4008 i = strchr(o->jump_host, ':') != NULL ||
4009 strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
4010 snprintf(buf, sizeof(buf), "%d", o->jump_port);
4011 printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
4012 /* optional additional jump spec */
4013 o->jump_extra == NULL ? "" : o->jump_extra,
4014 o->jump_extra == NULL ? "" : ",",
4015 /* optional user */
4016 o->jump_user == NULL ? "" : o->jump_user,
4017 o->jump_user == NULL ? "" : "@",
4018 /* opening [ if hostname is numeric */
4019 i ? "[" : "",
4020 /* mandatory hostname */
4021 o->jump_host,
4022 /* closing ] if hostname is numeric */
4023 i ? "]" : "",
4024 /* optional port number */
4025 o->jump_port <= 0 ? "" : ":",
4026 o->jump_port <= 0 ? "" : buf);
4027 }
4028 }
4029