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