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