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