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