GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: readconf.c,v 1.279 2017/09/21 19:16:53 markus Exp $ */ |
||
2 |
/* |
||
3 |
* Author: Tatu Ylonen <ylo@cs.hut.fi> |
||
4 |
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
||
5 |
* All rights reserved |
||
6 |
* Functions for reading the configuration files. |
||
7 |
* |
||
8 |
* As far as I am concerned, the code I have written for this software |
||
9 |
* can be used freely for any purpose. Any derived versions of this |
||
10 |
* software must be clearly marked as such, and if the derived work is |
||
11 |
* incompatible with the protocol description in the RFC file, it must be |
||
12 |
* called by a name other than "ssh" or "Secure Shell". |
||
13 |
*/ |
||
14 |
|||
15 |
#include <sys/types.h> |
||
16 |
#include <sys/stat.h> |
||
17 |
#include <sys/socket.h> |
||
18 |
#include <sys/wait.h> |
||
19 |
#include <sys/un.h> |
||
20 |
|||
21 |
#include <netinet/in.h> |
||
22 |
#include <netinet/ip.h> |
||
23 |
|||
24 |
#include <ctype.h> |
||
25 |
#include <errno.h> |
||
26 |
#include <fcntl.h> |
||
27 |
#include <glob.h> |
||
28 |
#include <netdb.h> |
||
29 |
#include <paths.h> |
||
30 |
#include <pwd.h> |
||
31 |
#include <signal.h> |
||
32 |
#include <stdio.h> |
||
33 |
#include <string.h> |
||
34 |
#include <unistd.h> |
||
35 |
#include <limits.h> |
||
36 |
#include <util.h> |
||
37 |
#include <vis.h> |
||
38 |
|||
39 |
#include "xmalloc.h" |
||
40 |
#include "ssh.h" |
||
41 |
#include "compat.h" |
||
42 |
#include "cipher.h" |
||
43 |
#include "pathnames.h" |
||
44 |
#include "log.h" |
||
45 |
#include "sshkey.h" |
||
46 |
#include "misc.h" |
||
47 |
#include "readconf.h" |
||
48 |
#include "match.h" |
||
49 |
#include "kex.h" |
||
50 |
#include "mac.h" |
||
51 |
#include "uidswap.h" |
||
52 |
#include "myproposal.h" |
||
53 |
#include "digest.h" |
||
54 |
|||
55 |
/* Format of the configuration file: |
||
56 |
|||
57 |
# Configuration data is parsed as follows: |
||
58 |
# 1. command line options |
||
59 |
# 2. user-specific file |
||
60 |
# 3. system-wide file |
||
61 |
# Any configuration value is only changed the first time it is set. |
||
62 |
# Thus, host-specific definitions should be at the beginning of the |
||
63 |
# configuration file, and defaults at the end. |
||
64 |
|||
65 |
# Host-specific declarations. These may override anything above. A single |
||
66 |
# host may match multiple declarations; these are processed in the order |
||
67 |
# that they are given in. |
||
68 |
|||
69 |
Host *.ngs.fi ngs.fi |
||
70 |
User foo |
||
71 |
|||
72 |
Host fake.com |
||
73 |
HostName another.host.name.real.org |
||
74 |
User blaah |
||
75 |
Port 34289 |
||
76 |
ForwardX11 no |
||
77 |
ForwardAgent no |
||
78 |
|||
79 |
Host books.com |
||
80 |
RemoteForward 9999 shadows.cs.hut.fi:9999 |
||
81 |
Ciphers 3des-cbc |
||
82 |
|||
83 |
Host fascist.blob.com |
||
84 |
Port 23123 |
||
85 |
User tylonen |
||
86 |
PasswordAuthentication no |
||
87 |
|||
88 |
Host puukko.hut.fi |
||
89 |
User t35124p |
||
90 |
ProxyCommand ssh-proxy %h %p |
||
91 |
|||
92 |
Host *.fr |
||
93 |
PublicKeyAuthentication no |
||
94 |
|||
95 |
Host *.su |
||
96 |
Ciphers aes128-ctr |
||
97 |
PasswordAuthentication no |
||
98 |
|||
99 |
Host vpn.fake.com |
||
100 |
Tunnel yes |
||
101 |
TunnelDevice 3 |
||
102 |
|||
103 |
# Defaults for various options |
||
104 |
Host * |
||
105 |
ForwardAgent no |
||
106 |
ForwardX11 no |
||
107 |
PasswordAuthentication yes |
||
108 |
RSAAuthentication yes |
||
109 |
RhostsRSAAuthentication yes |
||
110 |
StrictHostKeyChecking yes |
||
111 |
TcpKeepAlive no |
||
112 |
IdentityFile ~/.ssh/identity |
||
113 |
Port 22 |
||
114 |
EscapeChar ~ |
||
115 |
|||
116 |
*/ |
||
117 |
|||
118 |
static int read_config_file_depth(const char *filename, struct passwd *pw, |
||
119 |
const char *host, const char *original_host, Options *options, |
||
120 |
int flags, int *activep, int depth); |
||
121 |
static int process_config_line_depth(Options *options, struct passwd *pw, |
||
122 |
const char *host, const char *original_host, char *line, |
||
123 |
const char *filename, int linenum, int *activep, int flags, int depth); |
||
124 |
|||
125 |
/* Keyword tokens. */ |
||
126 |
|||
127 |
typedef enum { |
||
128 |
oBadOption, |
||
129 |
oHost, oMatch, oInclude, |
||
130 |
oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout, |
||
131 |
oGatewayPorts, oExitOnForwardFailure, |
||
132 |
oPasswordAuthentication, oRSAAuthentication, |
||
133 |
oChallengeResponseAuthentication, oXAuthLocation, |
||
134 |
oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, |
||
135 |
oCertificateFile, oAddKeysToAgent, oIdentityAgent, |
||
136 |
oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, |
||
137 |
oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, |
||
138 |
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, |
||
139 |
oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts, |
||
140 |
oUsePrivilegedPort, oLogFacility, oLogLevel, oCiphers, oMacs, |
||
141 |
oPubkeyAuthentication, |
||
142 |
oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, |
||
143 |
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, |
||
144 |
oHostKeyAlgorithms, oBindAddress, oPKCS11Provider, |
||
145 |
oClearAllForwardings, oNoHostAuthenticationForLocalhost, |
||
146 |
oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, |
||
147 |
oAddressFamily, oGssAuthentication, oGssDelegateCreds, |
||
148 |
oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, |
||
149 |
oSendEnv, oControlPath, oControlMaster, oControlPersist, |
||
150 |
oHashKnownHosts, |
||
151 |
oTunnel, oTunnelDevice, |
||
152 |
oLocalCommand, oPermitLocalCommand, oRemoteCommand, |
||
153 |
oVisualHostKey, |
||
154 |
oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, |
||
155 |
oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, |
||
156 |
oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, |
||
157 |
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, |
||
158 |
oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes, |
||
159 |
oPubkeyAcceptedKeyTypes, oProxyJump, |
||
160 |
oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported |
||
161 |
} OpCodes; |
||
162 |
|||
163 |
/* Textual representations of the tokens. */ |
||
164 |
|||
165 |
static struct { |
||
166 |
const char *name; |
||
167 |
OpCodes opcode; |
||
168 |
} keywords[] = { |
||
169 |
/* Deprecated options */ |
||
170 |
{ "protocol", oIgnore }, /* NB. silently ignored */ |
||
171 |
{ "cipher", oDeprecated }, |
||
172 |
{ "fallbacktorsh", oDeprecated }, |
||
173 |
{ "globalknownhostsfile2", oDeprecated }, |
||
174 |
{ "rhostsauthentication", oDeprecated }, |
||
175 |
{ "userknownhostsfile2", oDeprecated }, |
||
176 |
{ "useroaming", oDeprecated }, |
||
177 |
{ "usersh", oDeprecated }, |
||
178 |
|||
179 |
/* Unsupported options */ |
||
180 |
{ "afstokenpassing", oUnsupported }, |
||
181 |
{ "kerberosauthentication", oUnsupported }, |
||
182 |
{ "kerberostgtpassing", oUnsupported }, |
||
183 |
|||
184 |
/* Sometimes-unsupported options */ |
||
185 |
#if defined(GSSAPI) |
||
186 |
{ "gssapiauthentication", oGssAuthentication }, |
||
187 |
{ "gssapidelegatecredentials", oGssDelegateCreds }, |
||
188 |
# else |
||
189 |
{ "gssapiauthentication", oUnsupported }, |
||
190 |
{ "gssapidelegatecredentials", oUnsupported }, |
||
191 |
#endif |
||
192 |
#ifdef ENABLE_PKCS11 |
||
193 |
{ "smartcarddevice", oPKCS11Provider }, |
||
194 |
{ "pkcs11provider", oPKCS11Provider }, |
||
195 |
# else |
||
196 |
{ "smartcarddevice", oUnsupported }, |
||
197 |
{ "pkcs11provider", oUnsupported }, |
||
198 |
#endif |
||
199 |
{ "rsaauthentication", oUnsupported }, |
||
200 |
{ "rhostsrsaauthentication", oUnsupported }, |
||
201 |
{ "compressionlevel", oUnsupported }, |
||
202 |
|||
203 |
{ "forwardagent", oForwardAgent }, |
||
204 |
{ "forwardx11", oForwardX11 }, |
||
205 |
{ "forwardx11trusted", oForwardX11Trusted }, |
||
206 |
{ "forwardx11timeout", oForwardX11Timeout }, |
||
207 |
{ "exitonforwardfailure", oExitOnForwardFailure }, |
||
208 |
{ "xauthlocation", oXAuthLocation }, |
||
209 |
{ "gatewayports", oGatewayPorts }, |
||
210 |
{ "useprivilegedport", oUsePrivilegedPort }, |
||
211 |
{ "passwordauthentication", oPasswordAuthentication }, |
||
212 |
{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication }, |
||
213 |
{ "kbdinteractivedevices", oKbdInteractiveDevices }, |
||
214 |
{ "pubkeyauthentication", oPubkeyAuthentication }, |
||
215 |
{ "dsaauthentication", oPubkeyAuthentication }, /* alias */ |
||
216 |
{ "hostbasedauthentication", oHostbasedAuthentication }, |
||
217 |
{ "challengeresponseauthentication", oChallengeResponseAuthentication }, |
||
218 |
{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */ |
||
219 |
{ "tisauthentication", oChallengeResponseAuthentication }, /* alias */ |
||
220 |
{ "identityfile", oIdentityFile }, |
||
221 |
{ "identityfile2", oIdentityFile }, /* obsolete */ |
||
222 |
{ "identitiesonly", oIdentitiesOnly }, |
||
223 |
{ "certificatefile", oCertificateFile }, |
||
224 |
{ "addkeystoagent", oAddKeysToAgent }, |
||
225 |
{ "identityagent", oIdentityAgent }, |
||
226 |
{ "hostname", oHostName }, |
||
227 |
{ "hostkeyalias", oHostKeyAlias }, |
||
228 |
{ "proxycommand", oProxyCommand }, |
||
229 |
{ "port", oPort }, |
||
230 |
{ "ciphers", oCiphers }, |
||
231 |
{ "macs", oMacs }, |
||
232 |
{ "remoteforward", oRemoteForward }, |
||
233 |
{ "localforward", oLocalForward }, |
||
234 |
{ "user", oUser }, |
||
235 |
{ "host", oHost }, |
||
236 |
{ "match", oMatch }, |
||
237 |
{ "escapechar", oEscapeChar }, |
||
238 |
{ "globalknownhostsfile", oGlobalKnownHostsFile }, |
||
239 |
{ "userknownhostsfile", oUserKnownHostsFile }, |
||
240 |
{ "connectionattempts", oConnectionAttempts }, |
||
241 |
{ "batchmode", oBatchMode }, |
||
242 |
{ "checkhostip", oCheckHostIP }, |
||
243 |
{ "stricthostkeychecking", oStrictHostKeyChecking }, |
||
244 |
{ "compression", oCompression }, |
||
245 |
{ "tcpkeepalive", oTCPKeepAlive }, |
||
246 |
{ "keepalive", oTCPKeepAlive }, /* obsolete */ |
||
247 |
{ "numberofpasswordprompts", oNumberOfPasswordPrompts }, |
||
248 |
{ "syslogfacility", oLogFacility }, |
||
249 |
{ "loglevel", oLogLevel }, |
||
250 |
{ "dynamicforward", oDynamicForward }, |
||
251 |
{ "preferredauthentications", oPreferredAuthentications }, |
||
252 |
{ "hostkeyalgorithms", oHostKeyAlgorithms }, |
||
253 |
{ "bindaddress", oBindAddress }, |
||
254 |
{ "clearallforwardings", oClearAllForwardings }, |
||
255 |
{ "enablesshkeysign", oEnableSSHKeysign }, |
||
256 |
{ "verifyhostkeydns", oVerifyHostKeyDNS }, |
||
257 |
{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost }, |
||
258 |
{ "rekeylimit", oRekeyLimit }, |
||
259 |
{ "connecttimeout", oConnectTimeout }, |
||
260 |
{ "addressfamily", oAddressFamily }, |
||
261 |
{ "serveraliveinterval", oServerAliveInterval }, |
||
262 |
{ "serveralivecountmax", oServerAliveCountMax }, |
||
263 |
{ "sendenv", oSendEnv }, |
||
264 |
{ "controlpath", oControlPath }, |
||
265 |
{ "controlmaster", oControlMaster }, |
||
266 |
{ "controlpersist", oControlPersist }, |
||
267 |
{ "hashknownhosts", oHashKnownHosts }, |
||
268 |
{ "include", oInclude }, |
||
269 |
{ "tunnel", oTunnel }, |
||
270 |
{ "tunneldevice", oTunnelDevice }, |
||
271 |
{ "localcommand", oLocalCommand }, |
||
272 |
{ "permitlocalcommand", oPermitLocalCommand }, |
||
273 |
{ "remotecommand", oRemoteCommand }, |
||
274 |
{ "visualhostkey", oVisualHostKey }, |
||
275 |
{ "kexalgorithms", oKexAlgorithms }, |
||
276 |
{ "ipqos", oIPQoS }, |
||
277 |
{ "requesttty", oRequestTTY }, |
||
278 |
{ "proxyusefdpass", oProxyUseFdpass }, |
||
279 |
{ "canonicaldomains", oCanonicalDomains }, |
||
280 |
{ "canonicalizefallbacklocal", oCanonicalizeFallbackLocal }, |
||
281 |
{ "canonicalizehostname", oCanonicalizeHostname }, |
||
282 |
{ "canonicalizemaxdots", oCanonicalizeMaxDots }, |
||
283 |
{ "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs }, |
||
284 |
{ "streamlocalbindmask", oStreamLocalBindMask }, |
||
285 |
{ "streamlocalbindunlink", oStreamLocalBindUnlink }, |
||
286 |
{ "revokedhostkeys", oRevokedHostKeys }, |
||
287 |
{ "fingerprinthash", oFingerprintHash }, |
||
288 |
{ "updatehostkeys", oUpdateHostkeys }, |
||
289 |
{ "hostbasedkeytypes", oHostbasedKeyTypes }, |
||
290 |
{ "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes }, |
||
291 |
{ "ignoreunknown", oIgnoreUnknown }, |
||
292 |
{ "proxyjump", oProxyJump }, |
||
293 |
|||
294 |
{ NULL, oBadOption } |
||
295 |
}; |
||
296 |
|||
297 |
/* |
||
298 |
* Adds a local TCP/IP port forward to options. Never returns if there is an |
||
299 |
* error. |
||
300 |
*/ |
||
301 |
|||
302 |
void |
||
303 |
add_local_forward(Options *options, const struct Forward *newfwd) |
||
304 |
{ |
||
305 |
struct Forward *fwd; |
||
306 |
extern uid_t original_real_uid; |
||
307 |
int i; |
||
308 |
|||
309 |
if (!bind_permitted(newfwd->listen_port, original_real_uid) && |
||
310 |
newfwd->listen_path == NULL) |
||
311 |
fatal("Privileged ports can only be forwarded by root."); |
||
312 |
/* Don't add duplicates */ |
||
313 |
for (i = 0; i < options->num_local_forwards; i++) { |
||
314 |
if (forward_equals(newfwd, options->local_forwards + i)) |
||
315 |
return; |
||
316 |
} |
||
317 |
options->local_forwards = xreallocarray(options->local_forwards, |
||
318 |
options->num_local_forwards + 1, |
||
319 |
sizeof(*options->local_forwards)); |
||
320 |
fwd = &options->local_forwards[options->num_local_forwards++]; |
||
321 |
|||
322 |
fwd->listen_host = newfwd->listen_host; |
||
323 |
fwd->listen_port = newfwd->listen_port; |
||
324 |
fwd->listen_path = newfwd->listen_path; |
||
325 |
fwd->connect_host = newfwd->connect_host; |
||
326 |
fwd->connect_port = newfwd->connect_port; |
||
327 |
fwd->connect_path = newfwd->connect_path; |
||
328 |
} |
||
329 |
|||
330 |
/* |
||
331 |
* Adds a remote TCP/IP port forward to options. Never returns if there is |
||
332 |
* an error. |
||
333 |
*/ |
||
334 |
|||
335 |
void |
||
336 |
add_remote_forward(Options *options, const struct Forward *newfwd) |
||
337 |
{ |
||
338 |
struct Forward *fwd; |
||
339 |
int i; |
||
340 |
|||
341 |
/* Don't add duplicates */ |
||
342 |
for (i = 0; i < options->num_remote_forwards; i++) { |
||
343 |
if (forward_equals(newfwd, options->remote_forwards + i)) |
||
344 |
return; |
||
345 |
} |
||
346 |
options->remote_forwards = xreallocarray(options->remote_forwards, |
||
347 |
options->num_remote_forwards + 1, |
||
348 |
sizeof(*options->remote_forwards)); |
||
349 |
fwd = &options->remote_forwards[options->num_remote_forwards++]; |
||
350 |
|||
351 |
fwd->listen_host = newfwd->listen_host; |
||
352 |
fwd->listen_port = newfwd->listen_port; |
||
353 |
fwd->listen_path = newfwd->listen_path; |
||
354 |
fwd->connect_host = newfwd->connect_host; |
||
355 |
fwd->connect_port = newfwd->connect_port; |
||
356 |
fwd->connect_path = newfwd->connect_path; |
||
357 |
fwd->handle = newfwd->handle; |
||
358 |
fwd->allocated_port = 0; |
||
359 |
} |
||
360 |
|||
361 |
static void |
||
362 |
clear_forwardings(Options *options) |
||
363 |
{ |
||
364 |
int i; |
||
365 |
|||
366 |
✗✓ | 3 |
for (i = 0; i < options->num_local_forwards; i++) { |
367 |
free(options->local_forwards[i].listen_host); |
||
368 |
free(options->local_forwards[i].listen_path); |
||
369 |
free(options->local_forwards[i].connect_host); |
||
370 |
free(options->local_forwards[i].connect_path); |
||
371 |
} |
||
372 |
✗✓ | 1 |
if (options->num_local_forwards > 0) { |
373 |
free(options->local_forwards); |
||
374 |
options->local_forwards = NULL; |
||
375 |
} |
||
376 |
1 |
options->num_local_forwards = 0; |
|
377 |
✗✓ | 2 |
for (i = 0; i < options->num_remote_forwards; i++) { |
378 |
free(options->remote_forwards[i].listen_host); |
||
379 |
free(options->remote_forwards[i].listen_path); |
||
380 |
free(options->remote_forwards[i].connect_host); |
||
381 |
free(options->remote_forwards[i].connect_path); |
||
382 |
} |
||
383 |
✗✓ | 1 |
if (options->num_remote_forwards > 0) { |
384 |
free(options->remote_forwards); |
||
385 |
options->remote_forwards = NULL; |
||
386 |
} |
||
387 |
1 |
options->num_remote_forwards = 0; |
|
388 |
1 |
options->tun_open = SSH_TUNMODE_NO; |
|
389 |
1 |
} |
|
390 |
|||
391 |
void |
||
392 |
add_certificate_file(Options *options, const char *path, int userprovided) |
||
393 |
{ |
||
394 |
int i; |
||
395 |
|||
396 |
if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES) |
||
397 |
fatal("Too many certificate files specified (max %d)", |
||
398 |
SSH_MAX_CERTIFICATE_FILES); |
||
399 |
|||
400 |
/* Avoid registering duplicates */ |
||
401 |
for (i = 0; i < options->num_certificate_files; i++) { |
||
402 |
if (options->certificate_file_userprovided[i] == userprovided && |
||
403 |
strcmp(options->certificate_files[i], path) == 0) { |
||
404 |
debug2("%s: ignoring duplicate key %s", __func__, path); |
||
405 |
return; |
||
406 |
} |
||
407 |
} |
||
408 |
|||
409 |
options->certificate_file_userprovided[options->num_certificate_files] = |
||
410 |
userprovided; |
||
411 |
options->certificate_files[options->num_certificate_files++] = |
||
412 |
xstrdup(path); |
||
413 |
} |
||
414 |
|||
415 |
void |
||
416 |
add_identity_file(Options *options, const char *dir, const char *filename, |
||
417 |
int userprovided) |
||
418 |
{ |
||
419 |
8 |
char *path; |
|
420 |
int i; |
||
421 |
|||
422 |
✗✓ | 4 |
if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES) |
423 |
fatal("Too many identity files specified (max %d)", |
||
424 |
SSH_MAX_IDENTITY_FILES); |
||
425 |
|||
426 |
✗✓ | 4 |
if (dir == NULL) /* no dir, filename is absolute */ |
427 |
path = xstrdup(filename); |
||
428 |
✗✓ | 4 |
else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX) |
429 |
fatal("Identity file path %s too long", path); |
||
430 |
|||
431 |
/* Avoid registering duplicates */ |
||
432 |
✓✓ | 20 |
for (i = 0; i < options->num_identity_files; i++) { |
433 |
✓✗✗✓ |
12 |
if (options->identity_file_userprovided[i] == userprovided && |
434 |
6 |
strcmp(options->identity_files[i], path) == 0) { |
|
435 |
debug2("%s: ignoring duplicate key %s", __func__, path); |
||
436 |
free(path); |
||
437 |
return; |
||
438 |
} |
||
439 |
} |
||
440 |
|||
441 |
4 |
options->identity_file_userprovided[options->num_identity_files] = |
|
442 |
userprovided; |
||
443 |
4 |
options->identity_files[options->num_identity_files++] = path; |
|
444 |
8 |
} |
|
445 |
|||
446 |
int |
||
447 |
default_ssh_port(void) |
||
448 |
{ |
||
449 |
static int port; |
||
450 |
struct servent *sp; |
||
451 |
|||
452 |
✓✗ | 2 |
if (port == 0) { |
453 |
1 |
sp = getservbyname(SSH_SERVICE_NAME, "tcp"); |
|
454 |
✓✗ | 3 |
port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT; |
455 |
1 |
} |
|
456 |
1 |
return port; |
|
457 |
} |
||
458 |
|||
459 |
/* |
||
460 |
* Execute a command in a shell. |
||
461 |
* Return its exit status or -1 on abnormal exit. |
||
462 |
*/ |
||
463 |
static int |
||
464 |
execute_in_shell(const char *cmd) |
||
465 |
{ |
||
466 |
char *shell; |
||
467 |
pid_t pid; |
||
468 |
int devnull, status; |
||
469 |
extern uid_t original_real_uid; |
||
470 |
|||
471 |
if ((shell = getenv("SHELL")) == NULL) |
||
472 |
shell = _PATH_BSHELL; |
||
473 |
|||
474 |
/* Need this to redirect subprocess stdin/out */ |
||
475 |
if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) |
||
476 |
fatal("open(/dev/null): %s", strerror(errno)); |
||
477 |
|||
478 |
debug("Executing command: '%.500s'", cmd); |
||
479 |
|||
480 |
/* Fork and execute the command. */ |
||
481 |
if ((pid = fork()) == 0) { |
||
482 |
char *argv[4]; |
||
483 |
|||
484 |
/* Child. Permanently give up superuser privileges. */ |
||
485 |
permanently_drop_suid(original_real_uid); |
||
486 |
|||
487 |
/* Redirect child stdin and stdout. Leave stderr */ |
||
488 |
if (dup2(devnull, STDIN_FILENO) == -1) |
||
489 |
fatal("dup2: %s", strerror(errno)); |
||
490 |
if (dup2(devnull, STDOUT_FILENO) == -1) |
||
491 |
fatal("dup2: %s", strerror(errno)); |
||
492 |
if (devnull > STDERR_FILENO) |
||
493 |
close(devnull); |
||
494 |
closefrom(STDERR_FILENO + 1); |
||
495 |
|||
496 |
argv[0] = shell; |
||
497 |
argv[1] = "-c"; |
||
498 |
argv[2] = xstrdup(cmd); |
||
499 |
argv[3] = NULL; |
||
500 |
|||
501 |
execv(argv[0], argv); |
||
502 |
error("Unable to execute '%.100s': %s", cmd, strerror(errno)); |
||
503 |
/* Die with signal to make this error apparent to parent. */ |
||
504 |
signal(SIGTERM, SIG_DFL); |
||
505 |
kill(getpid(), SIGTERM); |
||
506 |
_exit(1); |
||
507 |
} |
||
508 |
/* Parent. */ |
||
509 |
if (pid < 0) |
||
510 |
fatal("%s: fork: %.100s", __func__, strerror(errno)); |
||
511 |
|||
512 |
close(devnull); |
||
513 |
|||
514 |
while (waitpid(pid, &status, 0) == -1) { |
||
515 |
if (errno != EINTR && errno != EAGAIN) |
||
516 |
fatal("%s: waitpid: %s", __func__, strerror(errno)); |
||
517 |
} |
||
518 |
if (!WIFEXITED(status)) { |
||
519 |
error("command '%.100s' exited abnormally", cmd); |
||
520 |
return -1; |
||
521 |
} |
||
522 |
debug3("command returned status %d", WEXITSTATUS(status)); |
||
523 |
return WEXITSTATUS(status); |
||
524 |
} |
||
525 |
|||
526 |
/* |
||
527 |
* Parse and execute a Match directive. |
||
528 |
*/ |
||
529 |
static int |
||
530 |
match_cfg_line(Options *options, char **condition, struct passwd *pw, |
||
531 |
const char *host_arg, const char *original_host, int post_canon, |
||
532 |
const char *filename, int linenum) |
||
533 |
{ |
||
534 |
char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria; |
||
535 |
const char *ruser; |
||
536 |
int r, port, this_result, result = 1, attributes = 0, negate; |
||
537 |
char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; |
||
538 |
|||
539 |
/* |
||
540 |
* Configuration is likely to be incomplete at this point so we |
||
541 |
* must be prepared to use default values. |
||
542 |
*/ |
||
543 |
port = options->port <= 0 ? default_ssh_port() : options->port; |
||
544 |
ruser = options->user == NULL ? pw->pw_name : options->user; |
||
545 |
if (post_canon) { |
||
546 |
host = xstrdup(options->hostname); |
||
547 |
} else if (options->hostname != NULL) { |
||
548 |
/* NB. Please keep in sync with ssh.c:main() */ |
||
549 |
host = percent_expand(options->hostname, |
||
550 |
"h", host_arg, (char *)NULL); |
||
551 |
} else { |
||
552 |
host = xstrdup(host_arg); |
||
553 |
} |
||
554 |
|||
555 |
debug2("checking match for '%s' host %s originally %s", |
||
556 |
cp, host, original_host); |
||
557 |
while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') { |
||
558 |
criteria = NULL; |
||
559 |
this_result = 1; |
||
560 |
if ((negate = attrib[0] == '!')) |
||
561 |
attrib++; |
||
562 |
/* criteria "all" and "canonical" have no argument */ |
||
563 |
if (strcasecmp(attrib, "all") == 0) { |
||
564 |
if (attributes > 1 || |
||
565 |
((arg = strdelim(&cp)) != NULL && *arg != '\0')) { |
||
566 |
error("%.200s line %d: '%s' cannot be combined " |
||
567 |
"with other Match attributes", |
||
568 |
filename, linenum, oattrib); |
||
569 |
result = -1; |
||
570 |
goto out; |
||
571 |
} |
||
572 |
if (result) |
||
573 |
result = negate ? 0 : 1; |
||
574 |
goto out; |
||
575 |
} |
||
576 |
attributes++; |
||
577 |
if (strcasecmp(attrib, "canonical") == 0) { |
||
578 |
r = !!post_canon; /* force bitmask member to boolean */ |
||
579 |
if (r == (negate ? 1 : 0)) |
||
580 |
this_result = result = 0; |
||
581 |
debug3("%.200s line %d: %smatched '%s'", |
||
582 |
filename, linenum, |
||
583 |
this_result ? "" : "not ", oattrib); |
||
584 |
continue; |
||
585 |
} |
||
586 |
/* All other criteria require an argument */ |
||
587 |
if ((arg = strdelim(&cp)) == NULL || *arg == '\0') { |
||
588 |
error("Missing Match criteria for %s", attrib); |
||
589 |
result = -1; |
||
590 |
goto out; |
||
591 |
} |
||
592 |
if (strcasecmp(attrib, "host") == 0) { |
||
593 |
criteria = xstrdup(host); |
||
594 |
r = match_hostname(host, arg) == 1; |
||
595 |
if (r == (negate ? 1 : 0)) |
||
596 |
this_result = result = 0; |
||
597 |
} else if (strcasecmp(attrib, "originalhost") == 0) { |
||
598 |
criteria = xstrdup(original_host); |
||
599 |
r = match_hostname(original_host, arg) == 1; |
||
600 |
if (r == (negate ? 1 : 0)) |
||
601 |
this_result = result = 0; |
||
602 |
} else if (strcasecmp(attrib, "user") == 0) { |
||
603 |
criteria = xstrdup(ruser); |
||
604 |
r = match_pattern_list(ruser, arg, 0) == 1; |
||
605 |
if (r == (negate ? 1 : 0)) |
||
606 |
this_result = result = 0; |
||
607 |
} else if (strcasecmp(attrib, "localuser") == 0) { |
||
608 |
criteria = xstrdup(pw->pw_name); |
||
609 |
r = match_pattern_list(pw->pw_name, arg, 0) == 1; |
||
610 |
if (r == (negate ? 1 : 0)) |
||
611 |
this_result = result = 0; |
||
612 |
} else if (strcasecmp(attrib, "exec") == 0) { |
||
613 |
if (gethostname(thishost, sizeof(thishost)) == -1) |
||
614 |
fatal("gethostname: %s", strerror(errno)); |
||
615 |
strlcpy(shorthost, thishost, sizeof(shorthost)); |
||
616 |
shorthost[strcspn(thishost, ".")] = '\0'; |
||
617 |
snprintf(portstr, sizeof(portstr), "%d", port); |
||
618 |
|||
619 |
cmd = percent_expand(arg, |
||
620 |
"L", shorthost, |
||
621 |
"d", pw->pw_dir, |
||
622 |
"h", host, |
||
623 |
"l", thishost, |
||
624 |
"n", original_host, |
||
625 |
"p", portstr, |
||
626 |
"r", ruser, |
||
627 |
"u", pw->pw_name, |
||
628 |
(char *)NULL); |
||
629 |
if (result != 1) { |
||
630 |
/* skip execution if prior predicate failed */ |
||
631 |
debug3("%.200s line %d: skipped exec " |
||
632 |
"\"%.100s\"", filename, linenum, cmd); |
||
633 |
free(cmd); |
||
634 |
continue; |
||
635 |
} |
||
636 |
r = execute_in_shell(cmd); |
||
637 |
if (r == -1) { |
||
638 |
fatal("%.200s line %d: match exec " |
||
639 |
"'%.100s' error", filename, |
||
640 |
linenum, cmd); |
||
641 |
} |
||
642 |
criteria = xstrdup(cmd); |
||
643 |
free(cmd); |
||
644 |
/* Force exit status to boolean */ |
||
645 |
r = r == 0; |
||
646 |
if (r == (negate ? 1 : 0)) |
||
647 |
this_result = result = 0; |
||
648 |
} else { |
||
649 |
error("Unsupported Match attribute %s", attrib); |
||
650 |
result = -1; |
||
651 |
goto out; |
||
652 |
} |
||
653 |
debug3("%.200s line %d: %smatched '%s \"%.100s\"' ", |
||
654 |
filename, linenum, this_result ? "": "not ", |
||
655 |
oattrib, criteria); |
||
656 |
free(criteria); |
||
657 |
} |
||
658 |
if (attributes == 0) { |
||
659 |
error("One or more attributes required for Match"); |
||
660 |
result = -1; |
||
661 |
goto out; |
||
662 |
} |
||
663 |
out: |
||
664 |
if (result != -1) |
||
665 |
debug2("match %sfound", result ? "" : "not "); |
||
666 |
*condition = cp; |
||
667 |
free(host); |
||
668 |
return result; |
||
669 |
} |
||
670 |
|||
671 |
/* Check and prepare a domain name: removes trailing '.' and lowercases */ |
||
672 |
static void |
||
673 |
valid_domain(char *name, const char *filename, int linenum) |
||
674 |
{ |
||
675 |
size_t i, l = strlen(name); |
||
676 |
u_char c, last = '\0'; |
||
677 |
|||
678 |
if (l == 0) |
||
679 |
fatal("%s line %d: empty hostname suffix", filename, linenum); |
||
680 |
if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0])) |
||
681 |
fatal("%s line %d: hostname suffix \"%.100s\" " |
||
682 |
"starts with invalid character", filename, linenum, name); |
||
683 |
for (i = 0; i < l; i++) { |
||
684 |
c = tolower((u_char)name[i]); |
||
685 |
name[i] = (char)c; |
||
686 |
if (last == '.' && c == '.') |
||
687 |
fatal("%s line %d: hostname suffix \"%.100s\" contains " |
||
688 |
"consecutive separators", filename, linenum, name); |
||
689 |
if (c != '.' && c != '-' && !isalnum(c) && |
||
690 |
c != '_') /* technically invalid, but common */ |
||
691 |
fatal("%s line %d: hostname suffix \"%.100s\" contains " |
||
692 |
"invalid characters", filename, linenum, name); |
||
693 |
last = c; |
||
694 |
} |
||
695 |
if (name[l - 1] == '.') |
||
696 |
name[l - 1] = '\0'; |
||
697 |
} |
||
698 |
|||
699 |
/* |
||
700 |
* Returns the number of the token pointed to by cp or oBadOption. |
||
701 |
*/ |
||
702 |
static OpCodes |
||
703 |
parse_token(const char *cp, const char *filename, int linenum, |
||
704 |
const char *ignored_unknown) |
||
705 |
{ |
||
706 |
int i; |
||
707 |
|||
708 |
✓✗ | 357 |
for (i = 0; keywords[i].name; i++) |
709 |
✓✓ | 177 |
if (strcmp(cp, keywords[i].name) == 0) |
710 |
3 |
return keywords[i].opcode; |
|
711 |
if (ignored_unknown != NULL && |
||
712 |
match_pattern_list(cp, ignored_unknown, 1) == 1) |
||
713 |
return oIgnoredUnknownOption; |
||
714 |
error("%s: line %d: Bad configuration option: %s", |
||
715 |
filename, linenum, cp); |
||
716 |
return oBadOption; |
||
717 |
3 |
} |
|
718 |
|||
719 |
/* Multistate option parsing */ |
||
720 |
struct multistate { |
||
721 |
char *key; |
||
722 |
int value; |
||
723 |
}; |
||
724 |
static const struct multistate multistate_flag[] = { |
||
725 |
{ "true", 1 }, |
||
726 |
{ "false", 0 }, |
||
727 |
{ "yes", 1 }, |
||
728 |
{ "no", 0 }, |
||
729 |
{ NULL, -1 } |
||
730 |
}; |
||
731 |
static const struct multistate multistate_yesnoask[] = { |
||
732 |
{ "true", 1 }, |
||
733 |
{ "false", 0 }, |
||
734 |
{ "yes", 1 }, |
||
735 |
{ "no", 0 }, |
||
736 |
{ "ask", 2 }, |
||
737 |
{ NULL, -1 } |
||
738 |
}; |
||
739 |
static const struct multistate multistate_strict_hostkey[] = { |
||
740 |
{ "true", SSH_STRICT_HOSTKEY_YES }, |
||
741 |
{ "false", SSH_STRICT_HOSTKEY_OFF }, |
||
742 |
{ "yes", SSH_STRICT_HOSTKEY_YES }, |
||
743 |
{ "no", SSH_STRICT_HOSTKEY_OFF }, |
||
744 |
{ "ask", SSH_STRICT_HOSTKEY_ASK }, |
||
745 |
{ "off", SSH_STRICT_HOSTKEY_OFF }, |
||
746 |
{ "accept-new", SSH_STRICT_HOSTKEY_NEW }, |
||
747 |
{ NULL, -1 } |
||
748 |
}; |
||
749 |
static const struct multistate multistate_yesnoaskconfirm[] = { |
||
750 |
{ "true", 1 }, |
||
751 |
{ "false", 0 }, |
||
752 |
{ "yes", 1 }, |
||
753 |
{ "no", 0 }, |
||
754 |
{ "ask", 2 }, |
||
755 |
{ "confirm", 3 }, |
||
756 |
{ NULL, -1 } |
||
757 |
}; |
||
758 |
static const struct multistate multistate_addressfamily[] = { |
||
759 |
{ "inet", AF_INET }, |
||
760 |
{ "inet6", AF_INET6 }, |
||
761 |
{ "any", AF_UNSPEC }, |
||
762 |
{ NULL, -1 } |
||
763 |
}; |
||
764 |
static const struct multistate multistate_controlmaster[] = { |
||
765 |
{ "true", SSHCTL_MASTER_YES }, |
||
766 |
{ "yes", SSHCTL_MASTER_YES }, |
||
767 |
{ "false", SSHCTL_MASTER_NO }, |
||
768 |
{ "no", SSHCTL_MASTER_NO }, |
||
769 |
{ "auto", SSHCTL_MASTER_AUTO }, |
||
770 |
{ "ask", SSHCTL_MASTER_ASK }, |
||
771 |
{ "autoask", SSHCTL_MASTER_AUTO_ASK }, |
||
772 |
{ NULL, -1 } |
||
773 |
}; |
||
774 |
static const struct multistate multistate_tunnel[] = { |
||
775 |
{ "ethernet", SSH_TUNMODE_ETHERNET }, |
||
776 |
{ "point-to-point", SSH_TUNMODE_POINTOPOINT }, |
||
777 |
{ "true", SSH_TUNMODE_DEFAULT }, |
||
778 |
{ "yes", SSH_TUNMODE_DEFAULT }, |
||
779 |
{ "false", SSH_TUNMODE_NO }, |
||
780 |
{ "no", SSH_TUNMODE_NO }, |
||
781 |
{ NULL, -1 } |
||
782 |
}; |
||
783 |
static const struct multistate multistate_requesttty[] = { |
||
784 |
{ "true", REQUEST_TTY_YES }, |
||
785 |
{ "yes", REQUEST_TTY_YES }, |
||
786 |
{ "false", REQUEST_TTY_NO }, |
||
787 |
{ "no", REQUEST_TTY_NO }, |
||
788 |
{ "force", REQUEST_TTY_FORCE }, |
||
789 |
{ "auto", REQUEST_TTY_AUTO }, |
||
790 |
{ NULL, -1 } |
||
791 |
}; |
||
792 |
static const struct multistate multistate_canonicalizehostname[] = { |
||
793 |
{ "true", SSH_CANONICALISE_YES }, |
||
794 |
{ "false", SSH_CANONICALISE_NO }, |
||
795 |
{ "yes", SSH_CANONICALISE_YES }, |
||
796 |
{ "no", SSH_CANONICALISE_NO }, |
||
797 |
{ "always", SSH_CANONICALISE_ALWAYS }, |
||
798 |
{ NULL, -1 } |
||
799 |
}; |
||
800 |
|||
801 |
/* |
||
802 |
* Processes a single option line as used in the configuration files. This |
||
803 |
* only sets those values that have not already been set. |
||
804 |
*/ |
||
805 |
int |
||
806 |
process_config_line(Options *options, struct passwd *pw, const char *host, |
||
807 |
const char *original_host, char *line, const char *filename, |
||
808 |
int linenum, int *activep, int flags) |
||
809 |
{ |
||
810 |
6 |
return process_config_line_depth(options, pw, host, original_host, |
|
811 |
line, filename, linenum, activep, flags, 0); |
||
812 |
} |
||
813 |
|||
814 |
#define WHITESPACE " \t\r\n" |
||
815 |
static int |
||
816 |
process_config_line_depth(Options *options, struct passwd *pw, const char *host, |
||
817 |
const char *original_host, char *line, const char *filename, |
||
818 |
int linenum, int *activep, int flags, int depth) |
||
819 |
{ |
||
820 |
94 |
char *s, **charptr, *endofnumber, *keyword, *arg, *arg2; |
|
821 |
47 |
char **cpptr, fwdarg[256]; |
|
822 |
u_int i, *uintptr, max_entries = 0; |
||
823 |
47 |
int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0; |
|
824 |
int remotefwd, dynamicfwd; |
||
825 |
LogLevel *log_level_ptr; |
||
826 |
SyslogFacility *log_facility_ptr; |
||
827 |
47 |
long long val64; |
|
828 |
size_t len; |
||
829 |
47 |
struct Forward fwd; |
|
830 |
const struct multistate *multistate_ptr; |
||
831 |
struct allowed_cname *cname; |
||
832 |
47 |
glob_t gl; |
|
833 |
|||
834 |
✓✓ | 47 |
if (activep == NULL) { /* We are processing a command line directive */ |
835 |
3 |
cmdline = 1; |
|
836 |
activep = &cmdline; |
||
837 |
3 |
} |
|
838 |
|||
839 |
/* Strip trailing whitespace. Allow \f (form feed) at EOL only */ |
||
840 |
✗✓ | 47 |
if ((len = strlen(line)) == 0) |
841 |
return 0; |
||
842 |
✓✓ | 174 |
for (len--; len > 0; len--) { |
843 |
✓✓ | 83 |
if (strchr(WHITESPACE "\f", line[len]) == NULL) |
844 |
break; |
||
845 |
40 |
line[len] = '\0'; |
|
846 |
} |
||
847 |
|||
848 |
47 |
s = line; |
|
849 |
/* Get the keyword. (Each line is supposed to begin with a keyword). */ |
||
850 |
✗✓ | 47 |
if ((keyword = strdelim(&s)) == NULL) |
851 |
return 0; |
||
852 |
/* Ignore leading whitespace. */ |
||
853 |
✓✓ | 47 |
if (*keyword == '\0') |
854 |
4 |
keyword = strdelim(&s); |
|
855 |
✓✗✓✓ ✓✗✓✓ |
180 |
if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#') |
856 |
44 |
return 0; |
|
857 |
/* Match lowercase keyword */ |
||
858 |
3 |
lowercase(keyword); |
|
859 |
|||
860 |
3 |
opcode = parse_token(keyword, filename, linenum, |
|
861 |
3 |
options->ignored_unknown); |
|
862 |
|||
863 |
✗✗✗✗ ✓✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✓✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✓✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗ |
3 |
switch (opcode) { |
864 |
case oBadOption: |
||
865 |
/* don't panic, but count bad options */ |
||
866 |
return -1; |
||
867 |
case oIgnore: |
||
868 |
return 0; |
||
869 |
case oIgnoredUnknownOption: |
||
870 |
debug("%s line %d: Ignored unknown option \"%s\"", |
||
871 |
filename, linenum, keyword); |
||
872 |
return 0; |
||
873 |
case oConnectTimeout: |
||
874 |
intptr = &options->connection_timeout; |
||
875 |
parse_time: |
||
876 |
arg = strdelim(&s); |
||
877 |
if (!arg || *arg == '\0') |
||
878 |
fatal("%s line %d: missing time value.", |
||
879 |
filename, linenum); |
||
880 |
if (strcmp(arg, "none") == 0) |
||
881 |
value = -1; |
||
882 |
else if ((value = convtime(arg)) == -1) |
||
883 |
fatal("%s line %d: invalid time value.", |
||
884 |
filename, linenum); |
||
885 |
if (*activep && *intptr == -1) |
||
886 |
*intptr = value; |
||
887 |
break; |
||
888 |
|||
889 |
case oForwardAgent: |
||
890 |
1 |
intptr = &options->forward_agent; |
|
891 |
parse_flag: |
||
892 |
3 |
multistate_ptr = multistate_flag; |
|
893 |
parse_multistate: |
||
894 |
3 |
arg = strdelim(&s); |
|
895 |
✓✗✗✓ |
6 |
if (!arg || *arg == '\0') |
896 |
fatal("%s line %d: missing argument.", |
||
897 |
filename, linenum); |
||
898 |
value = -1; |
||
899 |
✓✗ | 22 |
for (i = 0; multistate_ptr[i].key != NULL; i++) { |
900 |
✓✓ | 11 |
if (strcasecmp(arg, multistate_ptr[i].key) == 0) { |
901 |
3 |
value = multistate_ptr[i].value; |
|
902 |
3 |
break; |
|
903 |
} |
||
904 |
} |
||
905 |
✗✓ | 3 |
if (value == -1) |
906 |
fatal("%s line %d: unsupported option \"%s\".", |
||
907 |
filename, linenum, arg); |
||
908 |
✓✗✓✗ |
6 |
if (*activep && *intptr == -1) |
909 |
3 |
*intptr = value; |
|
910 |
break; |
||
911 |
|||
912 |
case oForwardX11: |
||
913 |
intptr = &options->forward_x11; |
||
914 |
goto parse_flag; |
||
915 |
|||
916 |
case oForwardX11Trusted: |
||
917 |
intptr = &options->forward_x11_trusted; |
||
918 |
goto parse_flag; |
||
919 |
|||
920 |
case oForwardX11Timeout: |
||
921 |
intptr = &options->forward_x11_timeout; |
||
922 |
goto parse_time; |
||
923 |
|||
924 |
case oGatewayPorts: |
||
925 |
intptr = &options->fwd_opts.gateway_ports; |
||
926 |
goto parse_flag; |
||
927 |
|||
928 |
case oExitOnForwardFailure: |
||
929 |
intptr = &options->exit_on_forward_failure; |
||
930 |
goto parse_flag; |
||
931 |
|||
932 |
case oUsePrivilegedPort: |
||
933 |
intptr = &options->use_privileged_port; |
||
934 |
goto parse_flag; |
||
935 |
|||
936 |
case oPasswordAuthentication: |
||
937 |
intptr = &options->password_authentication; |
||
938 |
goto parse_flag; |
||
939 |
|||
940 |
case oKbdInteractiveAuthentication: |
||
941 |
intptr = &options->kbd_interactive_authentication; |
||
942 |
goto parse_flag; |
||
943 |
|||
944 |
case oKbdInteractiveDevices: |
||
945 |
charptr = &options->kbd_interactive_devices; |
||
946 |
goto parse_string; |
||
947 |
|||
948 |
case oPubkeyAuthentication: |
||
949 |
intptr = &options->pubkey_authentication; |
||
950 |
goto parse_flag; |
||
951 |
|||
952 |
case oHostbasedAuthentication: |
||
953 |
intptr = &options->hostbased_authentication; |
||
954 |
goto parse_flag; |
||
955 |
|||
956 |
case oChallengeResponseAuthentication: |
||
957 |
intptr = &options->challenge_response_authentication; |
||
958 |
goto parse_flag; |
||
959 |
|||
960 |
case oGssAuthentication: |
||
961 |
intptr = &options->gss_authentication; |
||
962 |
goto parse_flag; |
||
963 |
|||
964 |
case oGssDelegateCreds: |
||
965 |
intptr = &options->gss_deleg_creds; |
||
966 |
goto parse_flag; |
||
967 |
|||
968 |
case oBatchMode: |
||
969 |
intptr = &options->batch_mode; |
||
970 |
goto parse_flag; |
||
971 |
|||
972 |
case oCheckHostIP: |
||
973 |
intptr = &options->check_host_ip; |
||
974 |
goto parse_flag; |
||
975 |
|||
976 |
case oVerifyHostKeyDNS: |
||
977 |
intptr = &options->verify_host_key_dns; |
||
978 |
multistate_ptr = multistate_yesnoask; |
||
979 |
goto parse_multistate; |
||
980 |
|||
981 |
case oStrictHostKeyChecking: |
||
982 |
intptr = &options->strict_host_key_checking; |
||
983 |
multistate_ptr = multistate_strict_hostkey; |
||
984 |
goto parse_multistate; |
||
985 |
|||
986 |
case oCompression: |
||
987 |
intptr = &options->compression; |
||
988 |
goto parse_flag; |
||
989 |
|||
990 |
case oTCPKeepAlive: |
||
991 |
intptr = &options->tcp_keep_alive; |
||
992 |
goto parse_flag; |
||
993 |
|||
994 |
case oNoHostAuthenticationForLocalhost: |
||
995 |
intptr = &options->no_host_authentication_for_localhost; |
||
996 |
goto parse_flag; |
||
997 |
|||
998 |
case oNumberOfPasswordPrompts: |
||
999 |
intptr = &options->number_of_password_prompts; |
||
1000 |
goto parse_int; |
||
1001 |
|||
1002 |
case oRekeyLimit: |
||
1003 |
arg = strdelim(&s); |
||
1004 |
if (!arg || *arg == '\0') |
||
1005 |
fatal("%.200s line %d: Missing argument.", filename, |
||
1006 |
linenum); |
||
1007 |
if (strcmp(arg, "default") == 0) { |
||
1008 |
val64 = 0; |
||
1009 |
} else { |
||
1010 |
if (scan_scaled(arg, &val64) == -1) |
||
1011 |
fatal("%.200s line %d: Bad number '%s': %s", |
||
1012 |
filename, linenum, arg, strerror(errno)); |
||
1013 |
if (val64 != 0 && val64 < 16) |
||
1014 |
fatal("%.200s line %d: RekeyLimit too small", |
||
1015 |
filename, linenum); |
||
1016 |
} |
||
1017 |
if (*activep && options->rekey_limit == -1) |
||
1018 |
options->rekey_limit = val64; |
||
1019 |
if (s != NULL) { /* optional rekey interval present */ |
||
1020 |
if (strcmp(s, "none") == 0) { |
||
1021 |
(void)strdelim(&s); /* discard */ |
||
1022 |
break; |
||
1023 |
} |
||
1024 |
intptr = &options->rekey_interval; |
||
1025 |
goto parse_time; |
||
1026 |
} |
||
1027 |
break; |
||
1028 |
|||
1029 |
case oIdentityFile: |
||
1030 |
arg = strdelim(&s); |
||
1031 |
if (!arg || *arg == '\0') |
||
1032 |
fatal("%.200s line %d: Missing argument.", filename, linenum); |
||
1033 |
if (*activep) { |
||
1034 |
intptr = &options->num_identity_files; |
||
1035 |
if (*intptr >= SSH_MAX_IDENTITY_FILES) |
||
1036 |
fatal("%.200s line %d: Too many identity files specified (max %d).", |
||
1037 |
filename, linenum, SSH_MAX_IDENTITY_FILES); |
||
1038 |
add_identity_file(options, NULL, |
||
1039 |
arg, flags & SSHCONF_USERCONF); |
||
1040 |
} |
||
1041 |
break; |
||
1042 |
|||
1043 |
case oCertificateFile: |
||
1044 |
arg = strdelim(&s); |
||
1045 |
if (!arg || *arg == '\0') |
||
1046 |
fatal("%.200s line %d: Missing argument.", |
||
1047 |
filename, linenum); |
||
1048 |
if (*activep) { |
||
1049 |
intptr = &options->num_certificate_files; |
||
1050 |
if (*intptr >= SSH_MAX_CERTIFICATE_FILES) { |
||
1051 |
fatal("%.200s line %d: Too many certificate " |
||
1052 |
"files specified (max %d).", |
||
1053 |
filename, linenum, |
||
1054 |
SSH_MAX_CERTIFICATE_FILES); |
||
1055 |
} |
||
1056 |
add_certificate_file(options, arg, |
||
1057 |
flags & SSHCONF_USERCONF); |
||
1058 |
} |
||
1059 |
break; |
||
1060 |
|||
1061 |
case oXAuthLocation: |
||
1062 |
charptr=&options->xauth_location; |
||
1063 |
goto parse_string; |
||
1064 |
|||
1065 |
case oUser: |
||
1066 |
charptr = &options->user; |
||
1067 |
parse_string: |
||
1068 |
arg = strdelim(&s); |
||
1069 |
if (!arg || *arg == '\0') |
||
1070 |
fatal("%.200s line %d: Missing argument.", |
||
1071 |
filename, linenum); |
||
1072 |
if (*activep && *charptr == NULL) |
||
1073 |
*charptr = xstrdup(arg); |
||
1074 |
break; |
||
1075 |
|||
1076 |
case oGlobalKnownHostsFile: |
||
1077 |
cpptr = (char **)&options->system_hostfiles; |
||
1078 |
uintptr = &options->num_system_hostfiles; |
||
1079 |
max_entries = SSH_MAX_HOSTS_FILES; |
||
1080 |
parse_char_array: |
||
1081 |
if (*activep && *uintptr == 0) { |
||
1082 |
while ((arg = strdelim(&s)) != NULL && *arg != '\0') { |
||
1083 |
if ((*uintptr) >= max_entries) |
||
1084 |
fatal("%s line %d: " |
||
1085 |
"too many authorized keys files.", |
||
1086 |
filename, linenum); |
||
1087 |
cpptr[(*uintptr)++] = xstrdup(arg); |
||
1088 |
} |
||
1089 |
} |
||
1090 |
return 0; |
||
1091 |
|||
1092 |
case oUserKnownHostsFile: |
||
1093 |
cpptr = (char **)&options->user_hostfiles; |
||
1094 |
uintptr = &options->num_user_hostfiles; |
||
1095 |
max_entries = SSH_MAX_HOSTS_FILES; |
||
1096 |
goto parse_char_array; |
||
1097 |
|||
1098 |
case oHostName: |
||
1099 |
charptr = &options->hostname; |
||
1100 |
goto parse_string; |
||
1101 |
|||
1102 |
case oHostKeyAlias: |
||
1103 |
charptr = &options->host_key_alias; |
||
1104 |
goto parse_string; |
||
1105 |
|||
1106 |
case oPreferredAuthentications: |
||
1107 |
charptr = &options->preferred_authentications; |
||
1108 |
goto parse_string; |
||
1109 |
|||
1110 |
case oBindAddress: |
||
1111 |
charptr = &options->bind_address; |
||
1112 |
goto parse_string; |
||
1113 |
|||
1114 |
case oPKCS11Provider: |
||
1115 |
charptr = &options->pkcs11_provider; |
||
1116 |
goto parse_string; |
||
1117 |
|||
1118 |
case oProxyCommand: |
||
1119 |
charptr = &options->proxy_command; |
||
1120 |
/* Ignore ProxyCommand if ProxyJump already specified */ |
||
1121 |
if (options->jump_host != NULL) |
||
1122 |
charptr = &options->jump_host; /* Skip below */ |
||
1123 |
parse_command: |
||
1124 |
if (s == NULL) |
||
1125 |
fatal("%.200s line %d: Missing argument.", filename, linenum); |
||
1126 |
len = strspn(s, WHITESPACE "="); |
||
1127 |
if (*activep && *charptr == NULL) |
||
1128 |
*charptr = xstrdup(s + len); |
||
1129 |
return 0; |
||
1130 |
|||
1131 |
case oProxyJump: |
||
1132 |
if (s == NULL) { |
||
1133 |
fatal("%.200s line %d: Missing argument.", |
||
1134 |
filename, linenum); |
||
1135 |
} |
||
1136 |
len = strspn(s, WHITESPACE "="); |
||
1137 |
if (parse_jump(s + len, options, *activep) == -1) { |
||
1138 |
fatal("%.200s line %d: Invalid ProxyJump \"%s\"", |
||
1139 |
filename, linenum, s + len); |
||
1140 |
} |
||
1141 |
return 0; |
||
1142 |
|||
1143 |
case oPort: |
||
1144 |
intptr = &options->port; |
||
1145 |
parse_int: |
||
1146 |
arg = strdelim(&s); |
||
1147 |
if (!arg || *arg == '\0') |
||
1148 |
fatal("%.200s line %d: Missing argument.", filename, linenum); |
||
1149 |
if (arg[0] < '0' || arg[0] > '9') |
||
1150 |
fatal("%.200s line %d: Bad number.", filename, linenum); |
||
1151 |
|||
1152 |
/* Octal, decimal, or hex format? */ |
||
1153 |
value = strtol(arg, &endofnumber, 0); |
||
1154 |
if (arg == endofnumber) |
||
1155 |
fatal("%.200s line %d: Bad number.", filename, linenum); |
||
1156 |
if (*activep && *intptr == -1) |
||
1157 |
*intptr = value; |
||
1158 |
break; |
||
1159 |
|||
1160 |
case oConnectionAttempts: |
||
1161 |
intptr = &options->connection_attempts; |
||
1162 |
goto parse_int; |
||
1163 |
|||
1164 |
case oCiphers: |
||
1165 |
arg = strdelim(&s); |
||
1166 |
if (!arg || *arg == '\0') |
||
1167 |
fatal("%.200s line %d: Missing argument.", filename, linenum); |
||
1168 |
if (*arg != '-' && !ciphers_valid(*arg == '+' ? arg + 1 : arg)) |
||
1169 |
fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.", |
||
1170 |
filename, linenum, arg ? arg : "<NONE>"); |
||
1171 |
if (*activep && options->ciphers == NULL) |
||
1172 |
options->ciphers = xstrdup(arg); |
||
1173 |
break; |
||
1174 |
|||
1175 |
case oMacs: |
||
1176 |
arg = strdelim(&s); |
||
1177 |
if (!arg || *arg == '\0') |
||
1178 |
fatal("%.200s line %d: Missing argument.", filename, linenum); |
||
1179 |
if (*arg != '-' && !mac_valid(*arg == '+' ? arg + 1 : arg)) |
||
1180 |
fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.", |
||
1181 |
filename, linenum, arg ? arg : "<NONE>"); |
||
1182 |
if (*activep && options->macs == NULL) |
||
1183 |
options->macs = xstrdup(arg); |
||
1184 |
break; |
||
1185 |
|||
1186 |
case oKexAlgorithms: |
||
1187 |
arg = strdelim(&s); |
||
1188 |
if (!arg || *arg == '\0') |
||
1189 |
fatal("%.200s line %d: Missing argument.", |
||
1190 |
filename, linenum); |
||
1191 |
if (*arg != '-' && |
||
1192 |
!kex_names_valid(*arg == '+' ? arg + 1 : arg)) |
||
1193 |
fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.", |
||
1194 |
filename, linenum, arg ? arg : "<NONE>"); |
||
1195 |
if (*activep && options->kex_algorithms == NULL) |
||
1196 |
options->kex_algorithms = xstrdup(arg); |
||
1197 |
break; |
||
1198 |
|||
1199 |
case oHostKeyAlgorithms: |
||
1200 |
charptr = &options->hostkeyalgorithms; |
||
1201 |
parse_keytypes: |
||
1202 |
arg = strdelim(&s); |
||
1203 |
if (!arg || *arg == '\0') |
||
1204 |
fatal("%.200s line %d: Missing argument.", |
||
1205 |
filename, linenum); |
||
1206 |
if (*arg != '-' && |
||
1207 |
!sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1)) |
||
1208 |
fatal("%s line %d: Bad key types '%s'.", |
||
1209 |
filename, linenum, arg ? arg : "<NONE>"); |
||
1210 |
if (*activep && *charptr == NULL) |
||
1211 |
*charptr = xstrdup(arg); |
||
1212 |
break; |
||
1213 |
|||
1214 |
case oLogLevel: |
||
1215 |
log_level_ptr = &options->log_level; |
||
1216 |
arg = strdelim(&s); |
||
1217 |
value = log_level_number(arg); |
||
1218 |
if (value == SYSLOG_LEVEL_NOT_SET) |
||
1219 |
fatal("%.200s line %d: unsupported log level '%s'", |
||
1220 |
filename, linenum, arg ? arg : "<NONE>"); |
||
1221 |
if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET) |
||
1222 |
*log_level_ptr = (LogLevel) value; |
||
1223 |
break; |
||
1224 |
|||
1225 |
case oLogFacility: |
||
1226 |
log_facility_ptr = &options->log_facility; |
||
1227 |
arg = strdelim(&s); |
||
1228 |
value = log_facility_number(arg); |
||
1229 |
if (value == SYSLOG_FACILITY_NOT_SET) |
||
1230 |
fatal("%.200s line %d: unsupported log facility '%s'", |
||
1231 |
filename, linenum, arg ? arg : "<NONE>"); |
||
1232 |
if (*log_facility_ptr == -1) |
||
1233 |
*log_facility_ptr = (SyslogFacility) value; |
||
1234 |
break; |
||
1235 |
|||
1236 |
case oLocalForward: |
||
1237 |
case oRemoteForward: |
||
1238 |
case oDynamicForward: |
||
1239 |
arg = strdelim(&s); |
||
1240 |
if (arg == NULL || *arg == '\0') |
||
1241 |
fatal("%.200s line %d: Missing port argument.", |
||
1242 |
filename, linenum); |
||
1243 |
|||
1244 |
remotefwd = (opcode == oRemoteForward); |
||
1245 |
dynamicfwd = (opcode == oDynamicForward); |
||
1246 |
|||
1247 |
if (!dynamicfwd) { |
||
1248 |
arg2 = strdelim(&s); |
||
1249 |
if (arg2 == NULL || *arg2 == '\0') { |
||
1250 |
if (remotefwd) |
||
1251 |
dynamicfwd = 1; |
||
1252 |
else |
||
1253 |
fatal("%.200s line %d: Missing target " |
||
1254 |
"argument.", filename, linenum); |
||
1255 |
} else { |
||
1256 |
/* construct a string for parse_forward */ |
||
1257 |
snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, |
||
1258 |
arg2); |
||
1259 |
} |
||
1260 |
} |
||
1261 |
if (dynamicfwd) |
||
1262 |
strlcpy(fwdarg, arg, sizeof(fwdarg)); |
||
1263 |
|||
1264 |
if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0) |
||
1265 |
fatal("%.200s line %d: Bad forwarding specification.", |
||
1266 |
filename, linenum); |
||
1267 |
|||
1268 |
if (*activep) { |
||
1269 |
if (remotefwd) { |
||
1270 |
add_remote_forward(options, &fwd); |
||
1271 |
} else { |
||
1272 |
add_local_forward(options, &fwd); |
||
1273 |
} |
||
1274 |
} |
||
1275 |
break; |
||
1276 |
|||
1277 |
case oClearAllForwardings: |
||
1278 |
1 |
intptr = &options->clear_forwardings; |
|
1279 |
1 |
goto parse_flag; |
|
1280 |
|||
1281 |
case oHost: |
||
1282 |
if (cmdline) |
||
1283 |
fatal("Host directive not supported as a command-line " |
||
1284 |
"option"); |
||
1285 |
*activep = 0; |
||
1286 |
arg2 = NULL; |
||
1287 |
while ((arg = strdelim(&s)) != NULL && *arg != '\0') { |
||
1288 |
if ((flags & SSHCONF_NEVERMATCH) != 0) |
||
1289 |
break; |
||
1290 |
negated = *arg == '!'; |
||
1291 |
if (negated) |
||
1292 |
arg++; |
||
1293 |
if (match_pattern(host, arg)) { |
||
1294 |
if (negated) { |
||
1295 |
debug("%.200s line %d: Skipping Host " |
||
1296 |
"block because of negated match " |
||
1297 |
"for %.100s", filename, linenum, |
||
1298 |
arg); |
||
1299 |
*activep = 0; |
||
1300 |
break; |
||
1301 |
} |
||
1302 |
if (!*activep) |
||
1303 |
arg2 = arg; /* logged below */ |
||
1304 |
*activep = 1; |
||
1305 |
} |
||
1306 |
} |
||
1307 |
if (*activep) |
||
1308 |
debug("%.200s line %d: Applying options for %.100s", |
||
1309 |
filename, linenum, arg2); |
||
1310 |
/* Avoid garbage check below, as strdelim is done. */ |
||
1311 |
return 0; |
||
1312 |
|||
1313 |
case oMatch: |
||
1314 |
if (cmdline) |
||
1315 |
fatal("Host directive not supported as a command-line " |
||
1316 |
"option"); |
||
1317 |
value = match_cfg_line(options, &s, pw, host, original_host, |
||
1318 |
flags & SSHCONF_POSTCANON, filename, linenum); |
||
1319 |
if (value < 0) |
||
1320 |
fatal("%.200s line %d: Bad Match condition", filename, |
||
1321 |
linenum); |
||
1322 |
*activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value; |
||
1323 |
break; |
||
1324 |
|||
1325 |
case oEscapeChar: |
||
1326 |
intptr = &options->escape_char; |
||
1327 |
arg = strdelim(&s); |
||
1328 |
if (!arg || *arg == '\0') |
||
1329 |
fatal("%.200s line %d: Missing argument.", filename, linenum); |
||
1330 |
if (strcmp(arg, "none") == 0) |
||
1331 |
value = SSH_ESCAPECHAR_NONE; |
||
1332 |
else if (arg[1] == '\0') |
||
1333 |
value = (u_char) arg[0]; |
||
1334 |
else if (arg[0] == '^' && arg[2] == 0 && |
||
1335 |
(u_char) arg[1] >= 64 && (u_char) arg[1] < 128) |
||
1336 |
value = (u_char) arg[1] & 31; |
||
1337 |
else { |
||
1338 |
fatal("%.200s line %d: Bad escape character.", |
||
1339 |
filename, linenum); |
||
1340 |
/* NOTREACHED */ |
||
1341 |
value = 0; /* Avoid compiler warning. */ |
||
1342 |
} |
||
1343 |
if (*activep && *intptr == -1) |
||
1344 |
*intptr = value; |
||
1345 |
break; |
||
1346 |
|||
1347 |
case oAddressFamily: |
||
1348 |
intptr = &options->address_family; |
||
1349 |
multistate_ptr = multistate_addressfamily; |
||
1350 |
goto parse_multistate; |
||
1351 |
|||
1352 |
case oEnableSSHKeysign: |
||
1353 |
intptr = &options->enable_ssh_keysign; |
||
1354 |
goto parse_flag; |
||
1355 |
|||
1356 |
case oIdentitiesOnly: |
||
1357 |
intptr = &options->identities_only; |
||
1358 |
goto parse_flag; |
||
1359 |
|||
1360 |
case oServerAliveInterval: |
||
1361 |
intptr = &options->server_alive_interval; |
||
1362 |
goto parse_time; |
||
1363 |
|||
1364 |
case oServerAliveCountMax: |
||
1365 |
intptr = &options->server_alive_count_max; |
||
1366 |
goto parse_int; |
||
1367 |
|||
1368 |
case oSendEnv: |
||
1369 |
while ((arg = strdelim(&s)) != NULL && *arg != '\0') { |
||
1370 |
if (strchr(arg, '=') != NULL) |
||
1371 |
fatal("%s line %d: Invalid environment name.", |
||
1372 |
filename, linenum); |
||
1373 |
if (!*activep) |
||
1374 |
continue; |
||
1375 |
if (options->num_send_env >= MAX_SEND_ENV) |
||
1376 |
fatal("%s line %d: too many send env.", |
||
1377 |
filename, linenum); |
||
1378 |
options->send_env[options->num_send_env++] = |
||
1379 |
xstrdup(arg); |
||
1380 |
} |
||
1381 |
break; |
||
1382 |
|||
1383 |
case oControlPath: |
||
1384 |
charptr = &options->control_path; |
||
1385 |
goto parse_string; |
||
1386 |
|||
1387 |
case oControlMaster: |
||
1388 |
intptr = &options->control_master; |
||
1389 |
multistate_ptr = multistate_controlmaster; |
||
1390 |
goto parse_multistate; |
||
1391 |
|||
1392 |
case oControlPersist: |
||
1393 |
/* no/false/yes/true, or a time spec */ |
||
1394 |
intptr = &options->control_persist; |
||
1395 |
arg = strdelim(&s); |
||
1396 |
if (!arg || *arg == '\0') |
||
1397 |
fatal("%.200s line %d: Missing ControlPersist" |
||
1398 |
" argument.", filename, linenum); |
||
1399 |
value = 0; |
||
1400 |
value2 = 0; /* timeout */ |
||
1401 |
if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) |
||
1402 |
value = 0; |
||
1403 |
else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) |
||
1404 |
value = 1; |
||
1405 |
else if ((value2 = convtime(arg)) >= 0) |
||
1406 |
value = 1; |
||
1407 |
else |
||
1408 |
fatal("%.200s line %d: Bad ControlPersist argument.", |
||
1409 |
filename, linenum); |
||
1410 |
if (*activep && *intptr == -1) { |
||
1411 |
*intptr = value; |
||
1412 |
options->control_persist_timeout = value2; |
||
1413 |
} |
||
1414 |
break; |
||
1415 |
|||
1416 |
case oHashKnownHosts: |
||
1417 |
intptr = &options->hash_known_hosts; |
||
1418 |
goto parse_flag; |
||
1419 |
|||
1420 |
case oTunnel: |
||
1421 |
intptr = &options->tun_open; |
||
1422 |
multistate_ptr = multistate_tunnel; |
||
1423 |
goto parse_multistate; |
||
1424 |
|||
1425 |
case oTunnelDevice: |
||
1426 |
arg = strdelim(&s); |
||
1427 |
if (!arg || *arg == '\0') |
||
1428 |
fatal("%.200s line %d: Missing argument.", filename, linenum); |
||
1429 |
value = a2tun(arg, &value2); |
||
1430 |
if (value == SSH_TUNID_ERR) |
||
1431 |
fatal("%.200s line %d: Bad tun device.", filename, linenum); |
||
1432 |
if (*activep) { |
||
1433 |
options->tun_local = value; |
||
1434 |
options->tun_remote = value2; |
||
1435 |
} |
||
1436 |
break; |
||
1437 |
|||
1438 |
case oLocalCommand: |
||
1439 |
charptr = &options->local_command; |
||
1440 |
goto parse_command; |
||
1441 |
|||
1442 |
case oPermitLocalCommand: |
||
1443 |
1 |
intptr = &options->permit_local_command; |
|
1444 |
1 |
goto parse_flag; |
|
1445 |
|||
1446 |
case oRemoteCommand: |
||
1447 |
charptr = &options->remote_command; |
||
1448 |
goto parse_command; |
||
1449 |
|||
1450 |
case oVisualHostKey: |
||
1451 |
intptr = &options->visual_host_key; |
||
1452 |
goto parse_flag; |
||
1453 |
|||
1454 |
case oInclude: |
||
1455 |
if (cmdline) |
||
1456 |
fatal("Include directive not supported as a " |
||
1457 |
"command-line option"); |
||
1458 |
value = 0; |
||
1459 |
while ((arg = strdelim(&s)) != NULL && *arg != '\0') { |
||
1460 |
/* |
||
1461 |
* Ensure all paths are anchored. User configuration |
||
1462 |
* files may begin with '~/' but system configurations |
||
1463 |
* must not. If the path is relative, then treat it |
||
1464 |
* as living in ~/.ssh for user configurations or |
||
1465 |
* /etc/ssh for system ones. |
||
1466 |
*/ |
||
1467 |
if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0) |
||
1468 |
fatal("%.200s line %d: bad include path %s.", |
||
1469 |
filename, linenum, arg); |
||
1470 |
if (*arg != '/' && *arg != '~') { |
||
1471 |
xasprintf(&arg2, "%s/%s", |
||
1472 |
(flags & SSHCONF_USERCONF) ? |
||
1473 |
"~/" _PATH_SSH_USER_DIR : SSHDIR, arg); |
||
1474 |
} else |
||
1475 |
arg2 = xstrdup(arg); |
||
1476 |
memset(&gl, 0, sizeof(gl)); |
||
1477 |
r = glob(arg2, GLOB_TILDE, NULL, &gl); |
||
1478 |
if (r == GLOB_NOMATCH) { |
||
1479 |
debug("%.200s line %d: include %s matched no " |
||
1480 |
"files",filename, linenum, arg2); |
||
1481 |
free(arg2); |
||
1482 |
continue; |
||
1483 |
} else if (r != 0 || gl.gl_pathc < 0) |
||
1484 |
fatal("%.200s line %d: glob failed for %s.", |
||
1485 |
filename, linenum, arg2); |
||
1486 |
free(arg2); |
||
1487 |
oactive = *activep; |
||
1488 |
for (i = 0; i < (u_int)gl.gl_pathc; i++) { |
||
1489 |
debug3("%.200s line %d: Including file %s " |
||
1490 |
"depth %d%s", filename, linenum, |
||
1491 |
gl.gl_pathv[i], depth, |
||
1492 |
oactive ? "" : " (parse only)"); |
||
1493 |
r = read_config_file_depth(gl.gl_pathv[i], |
||
1494 |
pw, host, original_host, options, |
||
1495 |
flags | SSHCONF_CHECKPERM | |
||
1496 |
(oactive ? 0 : SSHCONF_NEVERMATCH), |
||
1497 |
activep, depth + 1); |
||
1498 |
if (r != 1 && errno != ENOENT) { |
||
1499 |
fatal("Can't open user config file " |
||
1500 |
"%.100s: %.100s", gl.gl_pathv[i], |
||
1501 |
strerror(errno)); |
||
1502 |
} |
||
1503 |
/* |
||
1504 |
* don't let Match in includes clobber the |
||
1505 |
* containing file's Match state. |
||
1506 |
*/ |
||
1507 |
*activep = oactive; |
||
1508 |
if (r != 1) |
||
1509 |
value = -1; |
||
1510 |
} |
||
1511 |
globfree(&gl); |
||
1512 |
} |
||
1513 |
if (value != 0) |
||
1514 |
return value; |
||
1515 |
break; |
||
1516 |
|||
1517 |
case oIPQoS: |
||
1518 |
arg = strdelim(&s); |
||
1519 |
if ((value = parse_ipqos(arg)) == -1) |
||
1520 |
fatal("%s line %d: Bad IPQoS value: %s", |
||
1521 |
filename, linenum, arg); |
||
1522 |
arg = strdelim(&s); |
||
1523 |
if (arg == NULL) |
||
1524 |
value2 = value; |
||
1525 |
else if ((value2 = parse_ipqos(arg)) == -1) |
||
1526 |
fatal("%s line %d: Bad IPQoS value: %s", |
||
1527 |
filename, linenum, arg); |
||
1528 |
if (*activep) { |
||
1529 |
options->ip_qos_interactive = value; |
||
1530 |
options->ip_qos_bulk = value2; |
||
1531 |
} |
||
1532 |
break; |
||
1533 |
|||
1534 |
case oRequestTTY: |
||
1535 |
intptr = &options->request_tty; |
||
1536 |
multistate_ptr = multistate_requesttty; |
||
1537 |
goto parse_multistate; |
||
1538 |
|||
1539 |
case oIgnoreUnknown: |
||
1540 |
charptr = &options->ignored_unknown; |
||
1541 |
goto parse_string; |
||
1542 |
|||
1543 |
case oProxyUseFdpass: |
||
1544 |
intptr = &options->proxy_use_fdpass; |
||
1545 |
goto parse_flag; |
||
1546 |
|||
1547 |
case oCanonicalDomains: |
||
1548 |
value = options->num_canonical_domains != 0; |
||
1549 |
while ((arg = strdelim(&s)) != NULL && *arg != '\0') { |
||
1550 |
valid_domain(arg, filename, linenum); |
||
1551 |
if (!*activep || value) |
||
1552 |
continue; |
||
1553 |
if (options->num_canonical_domains >= MAX_CANON_DOMAINS) |
||
1554 |
fatal("%s line %d: too many hostname suffixes.", |
||
1555 |
filename, linenum); |
||
1556 |
options->canonical_domains[ |
||
1557 |
options->num_canonical_domains++] = xstrdup(arg); |
||
1558 |
} |
||
1559 |
break; |
||
1560 |
|||
1561 |
case oCanonicalizePermittedCNAMEs: |
||
1562 |
value = options->num_permitted_cnames != 0; |
||
1563 |
while ((arg = strdelim(&s)) != NULL && *arg != '\0') { |
||
1564 |
/* Either '*' for everything or 'list:list' */ |
||
1565 |
if (strcmp(arg, "*") == 0) |
||
1566 |
arg2 = arg; |
||
1567 |
else { |
||
1568 |
lowercase(arg); |
||
1569 |
if ((arg2 = strchr(arg, ':')) == NULL || |
||
1570 |
arg2[1] == '\0') { |
||
1571 |
fatal("%s line %d: " |
||
1572 |
"Invalid permitted CNAME \"%s\"", |
||
1573 |
filename, linenum, arg); |
||
1574 |
} |
||
1575 |
*arg2 = '\0'; |
||
1576 |
arg2++; |
||
1577 |
} |
||
1578 |
if (!*activep || value) |
||
1579 |
continue; |
||
1580 |
if (options->num_permitted_cnames >= MAX_CANON_DOMAINS) |
||
1581 |
fatal("%s line %d: too many permitted CNAMEs.", |
||
1582 |
filename, linenum); |
||
1583 |
cname = options->permitted_cnames + |
||
1584 |
options->num_permitted_cnames++; |
||
1585 |
cname->source_list = xstrdup(arg); |
||
1586 |
cname->target_list = xstrdup(arg2); |
||
1587 |
} |
||
1588 |
break; |
||
1589 |
|||
1590 |
case oCanonicalizeHostname: |
||
1591 |
intptr = &options->canonicalize_hostname; |
||
1592 |
multistate_ptr = multistate_canonicalizehostname; |
||
1593 |
goto parse_multistate; |
||
1594 |
|||
1595 |
case oCanonicalizeMaxDots: |
||
1596 |
intptr = &options->canonicalize_max_dots; |
||
1597 |
goto parse_int; |
||
1598 |
|||
1599 |
case oCanonicalizeFallbackLocal: |
||
1600 |
intptr = &options->canonicalize_fallback_local; |
||
1601 |
goto parse_flag; |
||
1602 |
|||
1603 |
case oStreamLocalBindMask: |
||
1604 |
arg = strdelim(&s); |
||
1605 |
if (!arg || *arg == '\0') |
||
1606 |
fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum); |
||
1607 |
/* Parse mode in octal format */ |
||
1608 |
value = strtol(arg, &endofnumber, 8); |
||
1609 |
if (arg == endofnumber || value < 0 || value > 0777) |
||
1610 |
fatal("%.200s line %d: Bad mask.", filename, linenum); |
||
1611 |
options->fwd_opts.streamlocal_bind_mask = (mode_t)value; |
||
1612 |
break; |
||
1613 |
|||
1614 |
case oStreamLocalBindUnlink: |
||
1615 |
intptr = &options->fwd_opts.streamlocal_bind_unlink; |
||
1616 |
goto parse_flag; |
||
1617 |
|||
1618 |
case oRevokedHostKeys: |
||
1619 |
charptr = &options->revoked_host_keys; |
||
1620 |
goto parse_string; |
||
1621 |
|||
1622 |
case oFingerprintHash: |
||
1623 |
intptr = &options->fingerprint_hash; |
||
1624 |
arg = strdelim(&s); |
||
1625 |
if (!arg || *arg == '\0') |
||
1626 |
fatal("%.200s line %d: Missing argument.", |
||
1627 |
filename, linenum); |
||
1628 |
if ((value = ssh_digest_alg_by_name(arg)) == -1) |
||
1629 |
fatal("%.200s line %d: Invalid hash algorithm \"%s\".", |
||
1630 |
filename, linenum, arg); |
||
1631 |
if (*activep && *intptr == -1) |
||
1632 |
*intptr = value; |
||
1633 |
break; |
||
1634 |
|||
1635 |
case oUpdateHostkeys: |
||
1636 |
intptr = &options->update_hostkeys; |
||
1637 |
multistate_ptr = multistate_yesnoask; |
||
1638 |
goto parse_multistate; |
||
1639 |
|||
1640 |
case oHostbasedKeyTypes: |
||
1641 |
charptr = &options->hostbased_key_types; |
||
1642 |
goto parse_keytypes; |
||
1643 |
|||
1644 |
case oPubkeyAcceptedKeyTypes: |
||
1645 |
charptr = &options->pubkey_key_types; |
||
1646 |
goto parse_keytypes; |
||
1647 |
|||
1648 |
case oAddKeysToAgent: |
||
1649 |
intptr = &options->add_keys_to_agent; |
||
1650 |
multistate_ptr = multistate_yesnoaskconfirm; |
||
1651 |
goto parse_multistate; |
||
1652 |
|||
1653 |
case oIdentityAgent: |
||
1654 |
charptr = &options->identity_agent; |
||
1655 |
goto parse_string; |
||
1656 |
|||
1657 |
case oDeprecated: |
||
1658 |
debug("%s line %d: Deprecated option \"%s\"", |
||
1659 |
filename, linenum, keyword); |
||
1660 |
return 0; |
||
1661 |
|||
1662 |
case oUnsupported: |
||
1663 |
error("%s line %d: Unsupported option \"%s\"", |
||
1664 |
filename, linenum, keyword); |
||
1665 |
return 0; |
||
1666 |
|||
1667 |
default: |
||
1668 |
fatal("%s: Unimplemented opcode %d", __func__, opcode); |
||
1669 |
} |
||
1670 |
|||
1671 |
/* Check that there is no garbage at end of line. */ |
||
1672 |
✗✓✗✗ |
3 |
if ((arg = strdelim(&s)) != NULL && *arg != '\0') { |
1673 |
fatal("%.200s line %d: garbage at end of line; \"%.200s\".", |
||
1674 |
filename, linenum, arg); |
||
1675 |
} |
||
1676 |
3 |
return 0; |
|
1677 |
47 |
} |
|
1678 |
|||
1679 |
/* |
||
1680 |
* Reads the config file and modifies the options accordingly. Options |
||
1681 |
* should already be initialized before this call. This never returns if |
||
1682 |
* there is an error. If the file does not exist, this returns 0. |
||
1683 |
*/ |
||
1684 |
int |
||
1685 |
read_config_file(const char *filename, struct passwd *pw, const char *host, |
||
1686 |
const char *original_host, Options *options, int flags) |
||
1687 |
{ |
||
1688 |
4 |
int active = 1; |
|
1689 |
|||
1690 |
4 |
return read_config_file_depth(filename, pw, host, original_host, |
|
1691 |
options, flags, &active, 0); |
||
1692 |
2 |
} |
|
1693 |
|||
1694 |
#define READCONF_MAX_DEPTH 16 |
||
1695 |
static int |
||
1696 |
read_config_file_depth(const char *filename, struct passwd *pw, |
||
1697 |
const char *host, const char *original_host, Options *options, |
||
1698 |
int flags, int *activep, int depth) |
||
1699 |
{ |
||
1700 |
FILE *f; |
||
1701 |
4 |
char line[4096]; |
|
1702 |
int linenum; |
||
1703 |
int bad_options = 0; |
||
1704 |
|||
1705 |
✗✓ | 2 |
if (depth < 0 || depth > READCONF_MAX_DEPTH) |
1706 |
fatal("Too many recursive configuration includes"); |
||
1707 |
|||
1708 |
✓✓ | 2 |
if ((f = fopen(filename, "r")) == NULL) |
1709 |
1 |
return 0; |
|
1710 |
|||
1711 |
✗✓ | 1 |
if (flags & SSHCONF_CHECKPERM) { |
1712 |
struct stat sb; |
||
1713 |
|||
1714 |
if (fstat(fileno(f), &sb) == -1) |
||
1715 |
fatal("fstat %s: %s", filename, strerror(errno)); |
||
1716 |
if (((sb.st_uid != 0 && sb.st_uid != getuid()) || |
||
1717 |
(sb.st_mode & 022) != 0)) |
||
1718 |
fatal("Bad owner or permissions on %s", filename); |
||
1719 |
} |
||
1720 |
|||
1721 |
1 |
debug("Reading configuration data %.200s", filename); |
|
1722 |
|||
1723 |
/* |
||
1724 |
* Mark that we are now processing the options. This flag is turned |
||
1725 |
* on/off by Host specifications. |
||
1726 |
*/ |
||
1727 |
linenum = 0; |
||
1728 |
✓✓ | 46 |
while (fgets(line, sizeof(line), f)) { |
1729 |
/* Update line number counter. */ |
||
1730 |
44 |
linenum++; |
|
1731 |
✗✓ | 44 |
if (strlen(line) == sizeof(line) - 1) |
1732 |
fatal("%s line %d too long", filename, linenum); |
||
1733 |
✓✗ | 88 |
if (process_config_line_depth(options, pw, host, original_host, |
1734 |
44 |
line, filename, linenum, activep, flags, depth) != 0) |
|
1735 |
bad_options++; |
||
1736 |
} |
||
1737 |
1 |
fclose(f); |
|
1738 |
✗✓ | 1 |
if (bad_options > 0) |
1739 |
fatal("%s: terminating, %d bad configuration options", |
||
1740 |
filename, bad_options); |
||
1741 |
1 |
return 1; |
|
1742 |
2 |
} |
|
1743 |
|||
1744 |
/* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ |
||
1745 |
int |
||
1746 |
option_clear_or_none(const char *o) |
||
1747 |
{ |
||
1748 |
✗✓ | 21 |
return o == NULL || strcasecmp(o, "none") == 0; |
1749 |
} |
||
1750 |
|||
1751 |
/* |
||
1752 |
* Initializes options to special values that indicate that they have not yet |
||
1753 |
* been set. Read_config_file will only set options with this value. Options |
||
1754 |
* are processed in the following order: command line, user config file, |
||
1755 |
* system config file. Last, fill_default_options is called. |
||
1756 |
*/ |
||
1757 |
|||
1758 |
void |
||
1759 |
initialize_options(Options * options) |
||
1760 |
{ |
||
1761 |
2 |
memset(options, 'X', sizeof(*options)); |
|
1762 |
1 |
options->forward_agent = -1; |
|
1763 |
1 |
options->forward_x11 = -1; |
|
1764 |
1 |
options->forward_x11_trusted = -1; |
|
1765 |
1 |
options->forward_x11_timeout = -1; |
|
1766 |
1 |
options->stdio_forward_host = NULL; |
|
1767 |
1 |
options->stdio_forward_port = 0; |
|
1768 |
1 |
options->clear_forwardings = -1; |
|
1769 |
1 |
options->exit_on_forward_failure = -1; |
|
1770 |
1 |
options->xauth_location = NULL; |
|
1771 |
1 |
options->fwd_opts.gateway_ports = -1; |
|
1772 |
1 |
options->fwd_opts.streamlocal_bind_mask = (mode_t)-1; |
|
1773 |
1 |
options->fwd_opts.streamlocal_bind_unlink = -1; |
|
1774 |
1 |
options->use_privileged_port = -1; |
|
1775 |
1 |
options->pubkey_authentication = -1; |
|
1776 |
1 |
options->challenge_response_authentication = -1; |
|
1777 |
1 |
options->gss_authentication = -1; |
|
1778 |
1 |
options->gss_deleg_creds = -1; |
|
1779 |
1 |
options->password_authentication = -1; |
|
1780 |
1 |
options->kbd_interactive_authentication = -1; |
|
1781 |
1 |
options->kbd_interactive_devices = NULL; |
|
1782 |
1 |
options->hostbased_authentication = -1; |
|
1783 |
1 |
options->batch_mode = -1; |
|
1784 |
1 |
options->check_host_ip = -1; |
|
1785 |
1 |
options->strict_host_key_checking = -1; |
|
1786 |
1 |
options->compression = -1; |
|
1787 |
1 |
options->tcp_keep_alive = -1; |
|
1788 |
1 |
options->port = -1; |
|
1789 |
1 |
options->address_family = -1; |
|
1790 |
1 |
options->connection_attempts = -1; |
|
1791 |
1 |
options->connection_timeout = -1; |
|
1792 |
1 |
options->number_of_password_prompts = -1; |
|
1793 |
1 |
options->ciphers = NULL; |
|
1794 |
1 |
options->macs = NULL; |
|
1795 |
1 |
options->kex_algorithms = NULL; |
|
1796 |
1 |
options->hostkeyalgorithms = NULL; |
|
1797 |
1 |
options->num_identity_files = 0; |
|
1798 |
1 |
options->num_certificate_files = 0; |
|
1799 |
1 |
options->hostname = NULL; |
|
1800 |
1 |
options->host_key_alias = NULL; |
|
1801 |
1 |
options->proxy_command = NULL; |
|
1802 |
1 |
options->jump_user = NULL; |
|
1803 |
1 |
options->jump_host = NULL; |
|
1804 |
1 |
options->jump_port = -1; |
|
1805 |
1 |
options->jump_extra = NULL; |
|
1806 |
1 |
options->user = NULL; |
|
1807 |
1 |
options->escape_char = -1; |
|
1808 |
1 |
options->num_system_hostfiles = 0; |
|
1809 |
1 |
options->num_user_hostfiles = 0; |
|
1810 |
1 |
options->local_forwards = NULL; |
|
1811 |
1 |
options->num_local_forwards = 0; |
|
1812 |
1 |
options->remote_forwards = NULL; |
|
1813 |
1 |
options->num_remote_forwards = 0; |
|
1814 |
1 |
options->log_facility = SYSLOG_FACILITY_NOT_SET; |
|
1815 |
1 |
options->log_level = SYSLOG_LEVEL_NOT_SET; |
|
1816 |
1 |
options->preferred_authentications = NULL; |
|
1817 |
1 |
options->bind_address = NULL; |
|
1818 |
1 |
options->pkcs11_provider = NULL; |
|
1819 |
1 |
options->enable_ssh_keysign = - 1; |
|
1820 |
1 |
options->no_host_authentication_for_localhost = - 1; |
|
1821 |
1 |
options->identities_only = - 1; |
|
1822 |
1 |
options->rekey_limit = - 1; |
|
1823 |
1 |
options->rekey_interval = -1; |
|
1824 |
1 |
options->verify_host_key_dns = -1; |
|
1825 |
1 |
options->server_alive_interval = -1; |
|
1826 |
1 |
options->server_alive_count_max = -1; |
|
1827 |
1 |
options->num_send_env = 0; |
|
1828 |
1 |
options->control_path = NULL; |
|
1829 |
1 |
options->control_master = -1; |
|
1830 |
1 |
options->control_persist = -1; |
|
1831 |
1 |
options->control_persist_timeout = 0; |
|
1832 |
1 |
options->hash_known_hosts = -1; |
|
1833 |
1 |
options->tun_open = -1; |
|
1834 |
1 |
options->tun_local = -1; |
|
1835 |
1 |
options->tun_remote = -1; |
|
1836 |
1 |
options->local_command = NULL; |
|
1837 |
1 |
options->permit_local_command = -1; |
|
1838 |
1 |
options->remote_command = NULL; |
|
1839 |
1 |
options->add_keys_to_agent = -1; |
|
1840 |
1 |
options->identity_agent = NULL; |
|
1841 |
1 |
options->visual_host_key = -1; |
|
1842 |
1 |
options->ip_qos_interactive = -1; |
|
1843 |
1 |
options->ip_qos_bulk = -1; |
|
1844 |
1 |
options->request_tty = -1; |
|
1845 |
1 |
options->proxy_use_fdpass = -1; |
|
1846 |
1 |
options->ignored_unknown = NULL; |
|
1847 |
1 |
options->num_canonical_domains = 0; |
|
1848 |
1 |
options->num_permitted_cnames = 0; |
|
1849 |
1 |
options->canonicalize_max_dots = -1; |
|
1850 |
1 |
options->canonicalize_fallback_local = -1; |
|
1851 |
1 |
options->canonicalize_hostname = -1; |
|
1852 |
1 |
options->revoked_host_keys = NULL; |
|
1853 |
1 |
options->fingerprint_hash = -1; |
|
1854 |
1 |
options->update_hostkeys = -1; |
|
1855 |
1 |
options->hostbased_key_types = NULL; |
|
1856 |
1 |
options->pubkey_key_types = NULL; |
|
1857 |
1 |
} |
|
1858 |
|||
1859 |
/* |
||
1860 |
* A petite version of fill_default_options() that just fills the options |
||
1861 |
* needed for hostname canonicalization to proceed. |
||
1862 |
*/ |
||
1863 |
void |
||
1864 |
fill_default_options_for_canonicalization(Options *options) |
||
1865 |
{ |
||
1866 |
✓✗ | 2 |
if (options->canonicalize_max_dots == -1) |
1867 |
1 |
options->canonicalize_max_dots = 1; |
|
1868 |
✓✗ | 1 |
if (options->canonicalize_fallback_local == -1) |
1869 |
1 |
options->canonicalize_fallback_local = 1; |
|
1870 |
✓✗ | 1 |
if (options->canonicalize_hostname == -1) |
1871 |
1 |
options->canonicalize_hostname = SSH_CANONICALISE_NO; |
|
1872 |
1 |
} |
|
1873 |
|||
1874 |
/* |
||
1875 |
* Called after processing other sources of option data, this fills those |
||
1876 |
* options for which no value has been specified with their default values. |
||
1877 |
*/ |
||
1878 |
void |
||
1879 |
fill_default_options(Options * options) |
||
1880 |
{ |
||
1881 |
✗✓ | 2 |
if (options->forward_agent == -1) |
1882 |
options->forward_agent = 0; |
||
1883 |
✗✓ | 1 |
if (options->forward_x11 == -1) |
1884 |
options->forward_x11 = 0; |
||
1885 |
✓✗ | 1 |
if (options->forward_x11_trusted == -1) |
1886 |
1 |
options->forward_x11_trusted = 0; |
|
1887 |
✓✗ | 1 |
if (options->forward_x11_timeout == -1) |
1888 |
1 |
options->forward_x11_timeout = 1200; |
|
1889 |
/* |
||
1890 |
* stdio forwarding (-W) changes the default for these but we defer |
||
1891 |
* setting the values so they can be overridden. |
||
1892 |
*/ |
||
1893 |
✓✗ | 1 |
if (options->exit_on_forward_failure == -1) |
1894 |
1 |
options->exit_on_forward_failure = |
|
1895 |
1 |
options->stdio_forward_host != NULL ? 1 : 0; |
|
1896 |
✗✓ | 1 |
if (options->clear_forwardings == -1) |
1897 |
options->clear_forwardings = |
||
1898 |
options->stdio_forward_host != NULL ? 1 : 0; |
||
1899 |
✓✗ | 1 |
if (options->clear_forwardings == 1) |
1900 |
1 |
clear_forwardings(options); |
|
1901 |
|||
1902 |
✓✗ | 1 |
if (options->xauth_location == NULL) |
1903 |
1 |
options->xauth_location = _PATH_XAUTH; |
|
1904 |
✓✗ | 1 |
if (options->fwd_opts.gateway_ports == -1) |
1905 |
1 |
options->fwd_opts.gateway_ports = 0; |
|
1906 |
✓✗ | 1 |
if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1) |
1907 |
1 |
options->fwd_opts.streamlocal_bind_mask = 0177; |
|
1908 |
✓✗ | 1 |
if (options->fwd_opts.streamlocal_bind_unlink == -1) |
1909 |
1 |
options->fwd_opts.streamlocal_bind_unlink = 0; |
|
1910 |
✓✗ | 1 |
if (options->use_privileged_port == -1) |
1911 |
1 |
options->use_privileged_port = 0; |
|
1912 |
✓✗ | 1 |
if (options->pubkey_authentication == -1) |
1913 |
1 |
options->pubkey_authentication = 1; |
|
1914 |
✓✗ | 1 |
if (options->challenge_response_authentication == -1) |
1915 |
1 |
options->challenge_response_authentication = 1; |
|
1916 |
✓✗ | 1 |
if (options->gss_authentication == -1) |
1917 |
1 |
options->gss_authentication = 0; |
|
1918 |
✓✗ | 1 |
if (options->gss_deleg_creds == -1) |
1919 |
1 |
options->gss_deleg_creds = 0; |
|
1920 |
✓✗ | 1 |
if (options->password_authentication == -1) |
1921 |
1 |
options->password_authentication = 1; |
|
1922 |
✓✗ | 1 |
if (options->kbd_interactive_authentication == -1) |
1923 |
1 |
options->kbd_interactive_authentication = 1; |
|
1924 |
✓✗ | 1 |
if (options->hostbased_authentication == -1) |
1925 |
1 |
options->hostbased_authentication = 0; |
|
1926 |
✓✗ | 1 |
if (options->batch_mode == -1) |
1927 |
1 |
options->batch_mode = 0; |
|
1928 |
✓✗ | 1 |
if (options->check_host_ip == -1) |
1929 |
1 |
options->check_host_ip = 1; |
|
1930 |
✓✗ | 1 |
if (options->strict_host_key_checking == -1) |
1931 |
1 |
options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK; |
|
1932 |
✓✗ | 1 |
if (options->compression == -1) |
1933 |
1 |
options->compression = 0; |
|
1934 |
✓✗ | 1 |
if (options->tcp_keep_alive == -1) |
1935 |
1 |
options->tcp_keep_alive = 1; |
|
1936 |
✓✗ | 1 |
if (options->port == -1) |
1937 |
1 |
options->port = 0; /* Filled in ssh_connect. */ |
|
1938 |
✓✗ | 1 |
if (options->address_family == -1) |
1939 |
1 |
options->address_family = AF_UNSPEC; |
|
1940 |
✓✗ | 1 |
if (options->connection_attempts == -1) |
1941 |
1 |
options->connection_attempts = 1; |
|
1942 |
✓✗ | 1 |
if (options->number_of_password_prompts == -1) |
1943 |
1 |
options->number_of_password_prompts = 3; |
|
1944 |
/* options->hostkeyalgorithms, default set in myproposals.h */ |
||
1945 |
✓✗ | 1 |
if (options->add_keys_to_agent == -1) |
1946 |
1 |
options->add_keys_to_agent = 0; |
|
1947 |
✓✗ | 1 |
if (options->num_identity_files == 0) { |
1948 |
1 |
add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0); |
|
1949 |
1 |
add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0); |
|
1950 |
1 |
add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0); |
|
1951 |
1 |
add_identity_file(options, "~/", |
|
1952 |
_PATH_SSH_CLIENT_ID_ED25519, 0); |
||
1953 |
1 |
} |
|
1954 |
✓✗ | 1 |
if (options->escape_char == -1) |
1955 |
1 |
options->escape_char = '~'; |
|
1956 |
✓✗ | 1 |
if (options->num_system_hostfiles == 0) { |
1957 |
1 |
options->system_hostfiles[options->num_system_hostfiles++] = |
|
1958 |
1 |
xstrdup(_PATH_SSH_SYSTEM_HOSTFILE); |
|
1959 |
1 |
options->system_hostfiles[options->num_system_hostfiles++] = |
|
1960 |
1 |
xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2); |
|
1961 |
1 |
} |
|
1962 |
✓✗ | 1 |
if (options->num_user_hostfiles == 0) { |
1963 |
1 |
options->user_hostfiles[options->num_user_hostfiles++] = |
|
1964 |
1 |
xstrdup(_PATH_SSH_USER_HOSTFILE); |
|
1965 |
1 |
options->user_hostfiles[options->num_user_hostfiles++] = |
|
1966 |
1 |
xstrdup(_PATH_SSH_USER_HOSTFILE2); |
|
1967 |
1 |
} |
|
1968 |
✓✗ | 1 |
if (options->log_level == SYSLOG_LEVEL_NOT_SET) |
1969 |
1 |
options->log_level = SYSLOG_LEVEL_INFO; |
|
1970 |
✓✗ | 1 |
if (options->log_facility == SYSLOG_FACILITY_NOT_SET) |
1971 |
1 |
options->log_facility = SYSLOG_FACILITY_USER; |
|
1972 |
✓✗ | 1 |
if (options->no_host_authentication_for_localhost == - 1) |
1973 |
1 |
options->no_host_authentication_for_localhost = 0; |
|
1974 |
✓✗ | 1 |
if (options->identities_only == -1) |
1975 |
1 |
options->identities_only = 0; |
|
1976 |
✓✗ | 1 |
if (options->enable_ssh_keysign == -1) |
1977 |
1 |
options->enable_ssh_keysign = 0; |
|
1978 |
✓✗ | 1 |
if (options->rekey_limit == -1) |
1979 |
1 |
options->rekey_limit = 0; |
|
1980 |
✓✗ | 1 |
if (options->rekey_interval == -1) |
1981 |
1 |
options->rekey_interval = 0; |
|
1982 |
✓✗ | 1 |
if (options->verify_host_key_dns == -1) |
1983 |
1 |
options->verify_host_key_dns = 0; |
|
1984 |
✓✗ | 1 |
if (options->server_alive_interval == -1) |
1985 |
1 |
options->server_alive_interval = 0; |
|
1986 |
✓✗ | 1 |
if (options->server_alive_count_max == -1) |
1987 |
1 |
options->server_alive_count_max = 3; |
|
1988 |
✓✗ | 1 |
if (options->control_master == -1) |
1989 |
1 |
options->control_master = 0; |
|
1990 |
✓✗ | 1 |
if (options->control_persist == -1) { |
1991 |
1 |
options->control_persist = 0; |
|
1992 |
1 |
options->control_persist_timeout = 0; |
|
1993 |
1 |
} |
|
1994 |
✓✗ | 1 |
if (options->hash_known_hosts == -1) |
1995 |
1 |
options->hash_known_hosts = 0; |
|
1996 |
✗✓ | 1 |
if (options->tun_open == -1) |
1997 |
options->tun_open = SSH_TUNMODE_NO; |
||
1998 |
✓✗ | 1 |
if (options->tun_local == -1) |
1999 |
1 |
options->tun_local = SSH_TUNID_ANY; |
|
2000 |
✓✗ | 1 |
if (options->tun_remote == -1) |
2001 |
1 |
options->tun_remote = SSH_TUNID_ANY; |
|
2002 |
✗✓ | 1 |
if (options->permit_local_command == -1) |
2003 |
options->permit_local_command = 0; |
||
2004 |
✓✗ | 1 |
if (options->visual_host_key == -1) |
2005 |
1 |
options->visual_host_key = 0; |
|
2006 |
✓✗ | 1 |
if (options->ip_qos_interactive == -1) |
2007 |
1 |
options->ip_qos_interactive = IPTOS_LOWDELAY; |
|
2008 |
✓✗ | 1 |
if (options->ip_qos_bulk == -1) |
2009 |
1 |
options->ip_qos_bulk = IPTOS_THROUGHPUT; |
|
2010 |
✓✗ | 1 |
if (options->request_tty == -1) |
2011 |
1 |
options->request_tty = REQUEST_TTY_AUTO; |
|
2012 |
✓✗ | 1 |
if (options->proxy_use_fdpass == -1) |
2013 |
1 |
options->proxy_use_fdpass = 0; |
|
2014 |
✗✓ | 1 |
if (options->canonicalize_max_dots == -1) |
2015 |
options->canonicalize_max_dots = 1; |
||
2016 |
✗✓ | 1 |
if (options->canonicalize_fallback_local == -1) |
2017 |
options->canonicalize_fallback_local = 1; |
||
2018 |
✗✓ | 1 |
if (options->canonicalize_hostname == -1) |
2019 |
options->canonicalize_hostname = SSH_CANONICALISE_NO; |
||
2020 |
✓✗ | 1 |
if (options->fingerprint_hash == -1) |
2021 |
1 |
options->fingerprint_hash = SSH_FP_HASH_DEFAULT; |
|
2022 |
✓✗ | 1 |
if (options->update_hostkeys == -1) |
2023 |
1 |
options->update_hostkeys = 0; |
|
2024 |
✓✗✗✓ |
2 |
if (kex_assemble_names(KEX_CLIENT_ENCRYPT, &options->ciphers) != 0 || |
2025 |
✓✗ | 1 |
kex_assemble_names(KEX_CLIENT_MAC, &options->macs) != 0 || |
2026 |
✓✗ | 1 |
kex_assemble_names(KEX_CLIENT_KEX, &options->kex_algorithms) != 0 || |
2027 |
1 |
kex_assemble_names(KEX_DEFAULT_PK_ALG, |
|
2028 |
✓✗ | 2 |
&options->hostbased_key_types) != 0 || |
2029 |
1 |
kex_assemble_names(KEX_DEFAULT_PK_ALG, |
|
2030 |
2 |
&options->pubkey_key_types) != 0) |
|
2031 |
fatal("%s: kex_assemble_names failed", __func__); |
||
2032 |
|||
2033 |
#define CLEAR_ON_NONE(v) \ |
||
2034 |
do { \ |
||
2035 |
if (option_clear_or_none(v)) { \ |
||
2036 |
free(v); \ |
||
2037 |
v = NULL; \ |
||
2038 |
} \ |
||
2039 |
} while(0) |
||
2040 |
✓✗ | 2 |
CLEAR_ON_NONE(options->local_command); |
2041 |
✓✗ | 2 |
CLEAR_ON_NONE(options->remote_command); |
2042 |
✓✗ | 2 |
CLEAR_ON_NONE(options->proxy_command); |
2043 |
✓✗ | 2 |
CLEAR_ON_NONE(options->control_path); |
2044 |
✓✗ | 2 |
CLEAR_ON_NONE(options->revoked_host_keys); |
2045 |
/* options->identity_agent distinguishes NULL from 'none' */ |
||
2046 |
/* options->user will be set in the main program if appropriate */ |
||
2047 |
/* options->hostname will be set in the main program if appropriate */ |
||
2048 |
/* options->host_key_alias should not be set by default */ |
||
2049 |
/* options->preferred_authentications will be set in ssh */ |
||
2050 |
1 |
} |
|
2051 |
|||
2052 |
struct fwdarg { |
||
2053 |
char *arg; |
||
2054 |
int ispath; |
||
2055 |
}; |
||
2056 |
|||
2057 |
/* |
||
2058 |
* parse_fwd_field |
||
2059 |
* parses the next field in a port forwarding specification. |
||
2060 |
* sets fwd to the parsed field and advances p past the colon |
||
2061 |
* or sets it to NULL at end of string. |
||
2062 |
* returns 0 on success, else non-zero. |
||
2063 |
*/ |
||
2064 |
static int |
||
2065 |
parse_fwd_field(char **p, struct fwdarg *fwd) |
||
2066 |
{ |
||
2067 |
char *ep, *cp = *p; |
||
2068 |
int ispath = 0; |
||
2069 |
|||
2070 |
if (*cp == '\0') { |
||
2071 |
*p = NULL; |
||
2072 |
return -1; /* end of string */ |
||
2073 |
} |
||
2074 |
|||
2075 |
/* |
||
2076 |
* A field escaped with square brackets is used literally. |
||
2077 |
* XXX - allow ']' to be escaped via backslash? |
||
2078 |
*/ |
||
2079 |
if (*cp == '[') { |
||
2080 |
/* find matching ']' */ |
||
2081 |
for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) { |
||
2082 |
if (*ep == '/') |
||
2083 |
ispath = 1; |
||
2084 |
} |
||
2085 |
/* no matching ']' or not at end of field. */ |
||
2086 |
if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0')) |
||
2087 |
return -1; |
||
2088 |
/* NUL terminate the field and advance p past the colon */ |
||
2089 |
*ep++ = '\0'; |
||
2090 |
if (*ep != '\0') |
||
2091 |
*ep++ = '\0'; |
||
2092 |
fwd->arg = cp + 1; |
||
2093 |
fwd->ispath = ispath; |
||
2094 |
*p = ep; |
||
2095 |
return 0; |
||
2096 |
} |
||
2097 |
|||
2098 |
for (cp = *p; *cp != '\0'; cp++) { |
||
2099 |
switch (*cp) { |
||
2100 |
case '\\': |
||
2101 |
memmove(cp, cp + 1, strlen(cp + 1) + 1); |
||
2102 |
if (*cp == '\0') |
||
2103 |
return -1; |
||
2104 |
break; |
||
2105 |
case '/': |
||
2106 |
ispath = 1; |
||
2107 |
break; |
||
2108 |
case ':': |
||
2109 |
*cp++ = '\0'; |
||
2110 |
goto done; |
||
2111 |
} |
||
2112 |
} |
||
2113 |
done: |
||
2114 |
fwd->arg = *p; |
||
2115 |
fwd->ispath = ispath; |
||
2116 |
*p = cp; |
||
2117 |
return 0; |
||
2118 |
} |
||
2119 |
|||
2120 |
/* |
||
2121 |
* parse_forward |
||
2122 |
* parses a string containing a port forwarding specification of the form: |
||
2123 |
* dynamicfwd == 0 |
||
2124 |
* [listenhost:]listenport|listenpath:connecthost:connectport|connectpath |
||
2125 |
* listenpath:connectpath |
||
2126 |
* dynamicfwd == 1 |
||
2127 |
* [listenhost:]listenport |
||
2128 |
* returns number of arguments parsed or zero on error |
||
2129 |
*/ |
||
2130 |
int |
||
2131 |
parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd) |
||
2132 |
{ |
||
2133 |
struct fwdarg fwdargs[4]; |
||
2134 |
char *p, *cp; |
||
2135 |
int i; |
||
2136 |
|||
2137 |
memset(fwd, 0, sizeof(*fwd)); |
||
2138 |
memset(fwdargs, 0, sizeof(fwdargs)); |
||
2139 |
|||
2140 |
cp = p = xstrdup(fwdspec); |
||
2141 |
|||
2142 |
/* skip leading spaces */ |
||
2143 |
while (isspace((u_char)*cp)) |
||
2144 |
cp++; |
||
2145 |
|||
2146 |
for (i = 0; i < 4; ++i) { |
||
2147 |
if (parse_fwd_field(&cp, &fwdargs[i]) != 0) |
||
2148 |
break; |
||
2149 |
} |
||
2150 |
|||
2151 |
/* Check for trailing garbage */ |
||
2152 |
if (cp != NULL && *cp != '\0') { |
||
2153 |
i = 0; /* failure */ |
||
2154 |
} |
||
2155 |
|||
2156 |
switch (i) { |
||
2157 |
case 1: |
||
2158 |
if (fwdargs[0].ispath) { |
||
2159 |
fwd->listen_path = xstrdup(fwdargs[0].arg); |
||
2160 |
fwd->listen_port = PORT_STREAMLOCAL; |
||
2161 |
} else { |
||
2162 |
fwd->listen_host = NULL; |
||
2163 |
fwd->listen_port = a2port(fwdargs[0].arg); |
||
2164 |
} |
||
2165 |
fwd->connect_host = xstrdup("socks"); |
||
2166 |
break; |
||
2167 |
|||
2168 |
case 2: |
||
2169 |
if (fwdargs[0].ispath && fwdargs[1].ispath) { |
||
2170 |
fwd->listen_path = xstrdup(fwdargs[0].arg); |
||
2171 |
fwd->listen_port = PORT_STREAMLOCAL; |
||
2172 |
fwd->connect_path = xstrdup(fwdargs[1].arg); |
||
2173 |
fwd->connect_port = PORT_STREAMLOCAL; |
||
2174 |
} else if (fwdargs[1].ispath) { |
||
2175 |
fwd->listen_host = NULL; |
||
2176 |
fwd->listen_port = a2port(fwdargs[0].arg); |
||
2177 |
fwd->connect_path = xstrdup(fwdargs[1].arg); |
||
2178 |
fwd->connect_port = PORT_STREAMLOCAL; |
||
2179 |
} else { |
||
2180 |
fwd->listen_host = xstrdup(fwdargs[0].arg); |
||
2181 |
fwd->listen_port = a2port(fwdargs[1].arg); |
||
2182 |
fwd->connect_host = xstrdup("socks"); |
||
2183 |
} |
||
2184 |
break; |
||
2185 |
|||
2186 |
case 3: |
||
2187 |
if (fwdargs[0].ispath) { |
||
2188 |
fwd->listen_path = xstrdup(fwdargs[0].arg); |
||
2189 |
fwd->listen_port = PORT_STREAMLOCAL; |
||
2190 |
fwd->connect_host = xstrdup(fwdargs[1].arg); |
||
2191 |
fwd->connect_port = a2port(fwdargs[2].arg); |
||
2192 |
} else if (fwdargs[2].ispath) { |
||
2193 |
fwd->listen_host = xstrdup(fwdargs[0].arg); |
||
2194 |
fwd->listen_port = a2port(fwdargs[1].arg); |
||
2195 |
fwd->connect_path = xstrdup(fwdargs[2].arg); |
||
2196 |
fwd->connect_port = PORT_STREAMLOCAL; |
||
2197 |
} else { |
||
2198 |
fwd->listen_host = NULL; |
||
2199 |
fwd->listen_port = a2port(fwdargs[0].arg); |
||
2200 |
fwd->connect_host = xstrdup(fwdargs[1].arg); |
||
2201 |
fwd->connect_port = a2port(fwdargs[2].arg); |
||
2202 |
} |
||
2203 |
break; |
||
2204 |
|||
2205 |
case 4: |
||
2206 |
fwd->listen_host = xstrdup(fwdargs[0].arg); |
||
2207 |
fwd->listen_port = a2port(fwdargs[1].arg); |
||
2208 |
fwd->connect_host = xstrdup(fwdargs[2].arg); |
||
2209 |
fwd->connect_port = a2port(fwdargs[3].arg); |
||
2210 |
break; |
||
2211 |
default: |
||
2212 |
i = 0; /* failure */ |
||
2213 |
} |
||
2214 |
|||
2215 |
free(p); |
||
2216 |
|||
2217 |
if (dynamicfwd) { |
||
2218 |
if (!(i == 1 || i == 2)) |
||
2219 |
goto fail_free; |
||
2220 |
} else { |
||
2221 |
if (!(i == 3 || i == 4)) { |
||
2222 |
if (fwd->connect_path == NULL && |
||
2223 |
fwd->listen_path == NULL) |
||
2224 |
goto fail_free; |
||
2225 |
} |
||
2226 |
if (fwd->connect_port <= 0 && fwd->connect_path == NULL) |
||
2227 |
goto fail_free; |
||
2228 |
} |
||
2229 |
|||
2230 |
if ((fwd->listen_port < 0 && fwd->listen_path == NULL) || |
||
2231 |
(!remotefwd && fwd->listen_port == 0)) |
||
2232 |
goto fail_free; |
||
2233 |
if (fwd->connect_host != NULL && |
||
2234 |
strlen(fwd->connect_host) >= NI_MAXHOST) |
||
2235 |
goto fail_free; |
||
2236 |
/* XXX - if connecting to a remote socket, max sun len may not match this host */ |
||
2237 |
if (fwd->connect_path != NULL && |
||
2238 |
strlen(fwd->connect_path) >= PATH_MAX_SUN) |
||
2239 |
goto fail_free; |
||
2240 |
if (fwd->listen_host != NULL && |
||
2241 |
strlen(fwd->listen_host) >= NI_MAXHOST) |
||
2242 |
goto fail_free; |
||
2243 |
if (fwd->listen_path != NULL && |
||
2244 |
strlen(fwd->listen_path) >= PATH_MAX_SUN) |
||
2245 |
goto fail_free; |
||
2246 |
|||
2247 |
return (i); |
||
2248 |
|||
2249 |
fail_free: |
||
2250 |
free(fwd->connect_host); |
||
2251 |
fwd->connect_host = NULL; |
||
2252 |
free(fwd->connect_path); |
||
2253 |
fwd->connect_path = NULL; |
||
2254 |
free(fwd->listen_host); |
||
2255 |
fwd->listen_host = NULL; |
||
2256 |
free(fwd->listen_path); |
||
2257 |
fwd->listen_path = NULL; |
||
2258 |
return (0); |
||
2259 |
} |
||
2260 |
|||
2261 |
int |
||
2262 |
parse_jump(const char *s, Options *o, int active) |
||
2263 |
{ |
||
2264 |
char *orig, *sdup, *cp; |
||
2265 |
char *host = NULL, *user = NULL; |
||
2266 |
int ret = -1, port = -1, first; |
||
2267 |
|||
2268 |
active &= o->proxy_command == NULL && o->jump_host == NULL; |
||
2269 |
|||
2270 |
orig = sdup = xstrdup(s); |
||
2271 |
first = active; |
||
2272 |
do { |
||
2273 |
if ((cp = strrchr(sdup, ',')) == NULL) |
||
2274 |
cp = sdup; /* last */ |
||
2275 |
else |
||
2276 |
*cp++ = '\0'; |
||
2277 |
|||
2278 |
if (first) { |
||
2279 |
/* First argument and configuration is active */ |
||
2280 |
if (parse_user_host_port(cp, &user, &host, &port) != 0) |
||
2281 |
goto out; |
||
2282 |
} else { |
||
2283 |
/* Subsequent argument or inactive configuration */ |
||
2284 |
if (parse_user_host_port(cp, NULL, NULL, NULL) != 0) |
||
2285 |
goto out; |
||
2286 |
} |
||
2287 |
first = 0; /* only check syntax for subsequent hosts */ |
||
2288 |
} while (cp != sdup); |
||
2289 |
/* success */ |
||
2290 |
if (active) { |
||
2291 |
o->jump_user = user; |
||
2292 |
o->jump_host = host; |
||
2293 |
o->jump_port = port; |
||
2294 |
o->proxy_command = xstrdup("none"); |
||
2295 |
user = host = NULL; |
||
2296 |
if ((cp = strrchr(s, ',')) != NULL && cp != s) { |
||
2297 |
o->jump_extra = xstrdup(s); |
||
2298 |
o->jump_extra[cp - s] = '\0'; |
||
2299 |
} |
||
2300 |
} |
||
2301 |
ret = 0; |
||
2302 |
out: |
||
2303 |
free(orig); |
||
2304 |
free(user); |
||
2305 |
free(host); |
||
2306 |
return ret; |
||
2307 |
} |
||
2308 |
|||
2309 |
/* XXX the following is a near-vebatim copy from servconf.c; refactor */ |
||
2310 |
static const char * |
||
2311 |
fmt_multistate_int(int val, const struct multistate *m) |
||
2312 |
{ |
||
2313 |
u_int i; |
||
2314 |
|||
2315 |
for (i = 0; m[i].key != NULL; i++) { |
||
2316 |
if (m[i].value == val) |
||
2317 |
return m[i].key; |
||
2318 |
} |
||
2319 |
return "UNKNOWN"; |
||
2320 |
} |
||
2321 |
|||
2322 |
static const char * |
||
2323 |
fmt_intarg(OpCodes code, int val) |
||
2324 |
{ |
||
2325 |
if (val == -1) |
||
2326 |
return "unset"; |
||
2327 |
switch (code) { |
||
2328 |
case oAddressFamily: |
||
2329 |
return fmt_multistate_int(val, multistate_addressfamily); |
||
2330 |
case oVerifyHostKeyDNS: |
||
2331 |
case oUpdateHostkeys: |
||
2332 |
return fmt_multistate_int(val, multistate_yesnoask); |
||
2333 |
case oStrictHostKeyChecking: |
||
2334 |
return fmt_multistate_int(val, multistate_strict_hostkey); |
||
2335 |
case oControlMaster: |
||
2336 |
return fmt_multistate_int(val, multistate_controlmaster); |
||
2337 |
case oTunnel: |
||
2338 |
return fmt_multistate_int(val, multistate_tunnel); |
||
2339 |
case oRequestTTY: |
||
2340 |
return fmt_multistate_int(val, multistate_requesttty); |
||
2341 |
case oCanonicalizeHostname: |
||
2342 |
return fmt_multistate_int(val, multistate_canonicalizehostname); |
||
2343 |
case oFingerprintHash: |
||
2344 |
return ssh_digest_alg_name(val); |
||
2345 |
default: |
||
2346 |
switch (val) { |
||
2347 |
case 0: |
||
2348 |
return "no"; |
||
2349 |
case 1: |
||
2350 |
return "yes"; |
||
2351 |
default: |
||
2352 |
return "UNKNOWN"; |
||
2353 |
} |
||
2354 |
} |
||
2355 |
} |
||
2356 |
|||
2357 |
static const char * |
||
2358 |
lookup_opcode_name(OpCodes code) |
||
2359 |
{ |
||
2360 |
u_int i; |
||
2361 |
|||
2362 |
for (i = 0; keywords[i].name != NULL; i++) |
||
2363 |
if (keywords[i].opcode == code) |
||
2364 |
return(keywords[i].name); |
||
2365 |
return "UNKNOWN"; |
||
2366 |
} |
||
2367 |
|||
2368 |
static void |
||
2369 |
dump_cfg_int(OpCodes code, int val) |
||
2370 |
{ |
||
2371 |
printf("%s %d\n", lookup_opcode_name(code), val); |
||
2372 |
} |
||
2373 |
|||
2374 |
static void |
||
2375 |
dump_cfg_fmtint(OpCodes code, int val) |
||
2376 |
{ |
||
2377 |
printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val)); |
||
2378 |
} |
||
2379 |
|||
2380 |
static void |
||
2381 |
dump_cfg_string(OpCodes code, const char *val) |
||
2382 |
{ |
||
2383 |
if (val == NULL) |
||
2384 |
return; |
||
2385 |
printf("%s %s\n", lookup_opcode_name(code), val); |
||
2386 |
} |
||
2387 |
|||
2388 |
static void |
||
2389 |
dump_cfg_strarray(OpCodes code, u_int count, char **vals) |
||
2390 |
{ |
||
2391 |
u_int i; |
||
2392 |
|||
2393 |
for (i = 0; i < count; i++) |
||
2394 |
printf("%s %s\n", lookup_opcode_name(code), vals[i]); |
||
2395 |
} |
||
2396 |
|||
2397 |
static void |
||
2398 |
dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals) |
||
2399 |
{ |
||
2400 |
u_int i; |
||
2401 |
|||
2402 |
printf("%s", lookup_opcode_name(code)); |
||
2403 |
for (i = 0; i < count; i++) |
||
2404 |
printf(" %s", vals[i]); |
||
2405 |
printf("\n"); |
||
2406 |
} |
||
2407 |
|||
2408 |
static void |
||
2409 |
dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds) |
||
2410 |
{ |
||
2411 |
const struct Forward *fwd; |
||
2412 |
u_int i; |
||
2413 |
|||
2414 |
/* oDynamicForward */ |
||
2415 |
for (i = 0; i < count; i++) { |
||
2416 |
fwd = &fwds[i]; |
||
2417 |
if (code == oDynamicForward && fwd->connect_host != NULL && |
||
2418 |
strcmp(fwd->connect_host, "socks") != 0) |
||
2419 |
continue; |
||
2420 |
if (code == oLocalForward && fwd->connect_host != NULL && |
||
2421 |
strcmp(fwd->connect_host, "socks") == 0) |
||
2422 |
continue; |
||
2423 |
printf("%s", lookup_opcode_name(code)); |
||
2424 |
if (fwd->listen_port == PORT_STREAMLOCAL) |
||
2425 |
printf(" %s", fwd->listen_path); |
||
2426 |
else if (fwd->listen_host == NULL) |
||
2427 |
printf(" %d", fwd->listen_port); |
||
2428 |
else { |
||
2429 |
printf(" [%s]:%d", |
||
2430 |
fwd->listen_host, fwd->listen_port); |
||
2431 |
} |
||
2432 |
if (code != oDynamicForward) { |
||
2433 |
if (fwd->connect_port == PORT_STREAMLOCAL) |
||
2434 |
printf(" %s", fwd->connect_path); |
||
2435 |
else if (fwd->connect_host == NULL) |
||
2436 |
printf(" %d", fwd->connect_port); |
||
2437 |
else { |
||
2438 |
printf(" [%s]:%d", |
||
2439 |
fwd->connect_host, fwd->connect_port); |
||
2440 |
} |
||
2441 |
} |
||
2442 |
printf("\n"); |
||
2443 |
} |
||
2444 |
} |
||
2445 |
|||
2446 |
void |
||
2447 |
dump_client_config(Options *o, const char *host) |
||
2448 |
{ |
||
2449 |
int i; |
||
2450 |
char buf[8]; |
||
2451 |
|||
2452 |
/* This is normally prepared in ssh_kex2 */ |
||
2453 |
if (kex_assemble_names(KEX_DEFAULT_PK_ALG, &o->hostkeyalgorithms) != 0) |
||
2454 |
fatal("%s: kex_assemble_names failed", __func__); |
||
2455 |
|||
2456 |
/* Most interesting options first: user, host, port */ |
||
2457 |
dump_cfg_string(oUser, o->user); |
||
2458 |
dump_cfg_string(oHostName, host); |
||
2459 |
dump_cfg_int(oPort, o->port); |
||
2460 |
|||
2461 |
/* Flag options */ |
||
2462 |
dump_cfg_fmtint(oAddressFamily, o->address_family); |
||
2463 |
dump_cfg_fmtint(oBatchMode, o->batch_mode); |
||
2464 |
dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local); |
||
2465 |
dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname); |
||
2466 |
dump_cfg_fmtint(oChallengeResponseAuthentication, o->challenge_response_authentication); |
||
2467 |
dump_cfg_fmtint(oCheckHostIP, o->check_host_ip); |
||
2468 |
dump_cfg_fmtint(oCompression, o->compression); |
||
2469 |
dump_cfg_fmtint(oControlMaster, o->control_master); |
||
2470 |
dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign); |
||
2471 |
dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings); |
||
2472 |
dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure); |
||
2473 |
dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash); |
||
2474 |
dump_cfg_fmtint(oForwardAgent, o->forward_agent); |
||
2475 |
dump_cfg_fmtint(oForwardX11, o->forward_x11); |
||
2476 |
dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted); |
||
2477 |
dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports); |
||
2478 |
#ifdef GSSAPI |
||
2479 |
dump_cfg_fmtint(oGssAuthentication, o->gss_authentication); |
||
2480 |
dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds); |
||
2481 |
#endif /* GSSAPI */ |
||
2482 |
dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts); |
||
2483 |
dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication); |
||
2484 |
dump_cfg_fmtint(oIdentitiesOnly, o->identities_only); |
||
2485 |
dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication); |
||
2486 |
dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost); |
||
2487 |
dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication); |
||
2488 |
dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command); |
||
2489 |
dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass); |
||
2490 |
dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication); |
||
2491 |
dump_cfg_fmtint(oRequestTTY, o->request_tty); |
||
2492 |
dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); |
||
2493 |
dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking); |
||
2494 |
dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive); |
||
2495 |
dump_cfg_fmtint(oTunnel, o->tun_open); |
||
2496 |
dump_cfg_fmtint(oUsePrivilegedPort, o->use_privileged_port); |
||
2497 |
dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns); |
||
2498 |
dump_cfg_fmtint(oVisualHostKey, o->visual_host_key); |
||
2499 |
dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys); |
||
2500 |
|||
2501 |
/* Integer options */ |
||
2502 |
dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots); |
||
2503 |
dump_cfg_int(oConnectionAttempts, o->connection_attempts); |
||
2504 |
dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout); |
||
2505 |
dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts); |
||
2506 |
dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max); |
||
2507 |
dump_cfg_int(oServerAliveInterval, o->server_alive_interval); |
||
2508 |
|||
2509 |
/* String options */ |
||
2510 |
dump_cfg_string(oBindAddress, o->bind_address); |
||
2511 |
dump_cfg_string(oCiphers, o->ciphers ? o->ciphers : KEX_CLIENT_ENCRYPT); |
||
2512 |
dump_cfg_string(oControlPath, o->control_path); |
||
2513 |
dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms); |
||
2514 |
dump_cfg_string(oHostKeyAlias, o->host_key_alias); |
||
2515 |
dump_cfg_string(oHostbasedKeyTypes, o->hostbased_key_types); |
||
2516 |
dump_cfg_string(oIdentityAgent, o->identity_agent); |
||
2517 |
dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices); |
||
2518 |
dump_cfg_string(oKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : KEX_CLIENT_KEX); |
||
2519 |
dump_cfg_string(oLocalCommand, o->local_command); |
||
2520 |
dump_cfg_string(oRemoteCommand, o->remote_command); |
||
2521 |
dump_cfg_string(oLogLevel, log_level_name(o->log_level)); |
||
2522 |
dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC); |
||
2523 |
#ifdef ENABLE_PKCS11 |
||
2524 |
dump_cfg_string(oPKCS11Provider, o->pkcs11_provider); |
||
2525 |
#endif |
||
2526 |
dump_cfg_string(oPreferredAuthentications, o->preferred_authentications); |
||
2527 |
dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types); |
||
2528 |
dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys); |
||
2529 |
dump_cfg_string(oXAuthLocation, o->xauth_location); |
||
2530 |
|||
2531 |
/* Forwards */ |
||
2532 |
dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards); |
||
2533 |
dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards); |
||
2534 |
dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards); |
||
2535 |
|||
2536 |
/* String array options */ |
||
2537 |
dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files); |
||
2538 |
dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains); |
||
2539 |
dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles); |
||
2540 |
dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles); |
||
2541 |
dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env); |
||
2542 |
|||
2543 |
/* Special cases */ |
||
2544 |
|||
2545 |
/* oConnectTimeout */ |
||
2546 |
if (o->connection_timeout == -1) |
||
2547 |
printf("connecttimeout none\n"); |
||
2548 |
else |
||
2549 |
dump_cfg_int(oConnectTimeout, o->connection_timeout); |
||
2550 |
|||
2551 |
/* oTunnelDevice */ |
||
2552 |
printf("tunneldevice"); |
||
2553 |
if (o->tun_local == SSH_TUNID_ANY) |
||
2554 |
printf(" any"); |
||
2555 |
else |
||
2556 |
printf(" %d", o->tun_local); |
||
2557 |
if (o->tun_remote == SSH_TUNID_ANY) |
||
2558 |
printf(":any"); |
||
2559 |
else |
||
2560 |
printf(":%d", o->tun_remote); |
||
2561 |
printf("\n"); |
||
2562 |
|||
2563 |
/* oCanonicalizePermittedCNAMEs */ |
||
2564 |
if ( o->num_permitted_cnames > 0) { |
||
2565 |
printf("canonicalizePermittedcnames"); |
||
2566 |
for (i = 0; i < o->num_permitted_cnames; i++) { |
||
2567 |
printf(" %s:%s", o->permitted_cnames[i].source_list, |
||
2568 |
o->permitted_cnames[i].target_list); |
||
2569 |
} |
||
2570 |
printf("\n"); |
||
2571 |
} |
||
2572 |
|||
2573 |
/* oControlPersist */ |
||
2574 |
if (o->control_persist == 0 || o->control_persist_timeout == 0) |
||
2575 |
dump_cfg_fmtint(oControlPersist, o->control_persist); |
||
2576 |
else |
||
2577 |
dump_cfg_int(oControlPersist, o->control_persist_timeout); |
||
2578 |
|||
2579 |
/* oEscapeChar */ |
||
2580 |
if (o->escape_char == SSH_ESCAPECHAR_NONE) |
||
2581 |
printf("escapechar none\n"); |
||
2582 |
else { |
||
2583 |
vis(buf, o->escape_char, VIS_WHITE, 0); |
||
2584 |
printf("escapechar %s\n", buf); |
||
2585 |
} |
||
2586 |
|||
2587 |
/* oIPQoS */ |
||
2588 |
printf("ipqos %s ", iptos2str(o->ip_qos_interactive)); |
||
2589 |
printf("%s\n", iptos2str(o->ip_qos_bulk)); |
||
2590 |
|||
2591 |
/* oRekeyLimit */ |
||
2592 |
printf("rekeylimit %llu %d\n", |
||
2593 |
(unsigned long long)o->rekey_limit, o->rekey_interval); |
||
2594 |
|||
2595 |
/* oStreamLocalBindMask */ |
||
2596 |
printf("streamlocalbindmask 0%o\n", |
||
2597 |
o->fwd_opts.streamlocal_bind_mask); |
||
2598 |
|||
2599 |
/* oProxyCommand / oProxyJump */ |
||
2600 |
if (o->jump_host == NULL) |
||
2601 |
dump_cfg_string(oProxyCommand, o->proxy_command); |
||
2602 |
else { |
||
2603 |
/* Check for numeric addresses */ |
||
2604 |
i = strchr(o->jump_host, ':') != NULL || |
||
2605 |
strspn(o->jump_host, "1234567890.") == strlen(o->jump_host); |
||
2606 |
snprintf(buf, sizeof(buf), "%d", o->jump_port); |
||
2607 |
printf("proxyjump %s%s%s%s%s%s%s%s%s\n", |
||
2608 |
/* optional additional jump spec */ |
||
2609 |
o->jump_extra == NULL ? "" : o->jump_extra, |
||
2610 |
o->jump_extra == NULL ? "" : ",", |
||
2611 |
/* optional user */ |
||
2612 |
o->jump_user == NULL ? "" : o->jump_user, |
||
2613 |
o->jump_user == NULL ? "" : "@", |
||
2614 |
/* opening [ if hostname is numeric */ |
||
2615 |
i ? "[" : "", |
||
2616 |
/* mandatory hostname */ |
||
2617 |
o->jump_host, |
||
2618 |
/* closing ] if hostname is numeric */ |
||
2619 |
i ? "]" : "", |
||
2620 |
/* optional port number */ |
||
2621 |
o->jump_port <= 0 ? "" : ":", |
||
2622 |
o->jump_port <= 0 ? "" : buf); |
||
2623 |
} |
||
2624 |
} |
Generated by: GCOVR (Version 3.3) |