hammer utility - Add force support to cleanup
[dragonfly.git] / crypto / openssh / readconf.c
blob0da667dbe0905314b9add41f5e6b230cda5ed270
1 /* $OpenBSD: readconf.c,v 1.187 2010/07/19 09:15:12 djm Exp $ */
2 /*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 * All rights reserved
6 * Functions for reading the configuration files.
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".
15 #include "includes.h"
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <sys/socket.h>
21 #include <netinet/in.h>
23 #include <ctype.h>
24 #include <errno.h>
25 #include <netdb.h>
26 #include <signal.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <unistd.h>
32 #include "xmalloc.h"
33 #include "ssh.h"
34 #include "compat.h"
35 #include "cipher.h"
36 #include "pathnames.h"
37 #include "log.h"
38 #include "key.h"
39 #include "readconf.h"
40 #include "match.h"
41 #include "misc.h"
42 #include "buffer.h"
43 #include "kex.h"
44 #include "mac.h"
45 #include "uidswap.h"
46 #include "version.h"
48 /* Format of the configuration file:
50 # Configuration data is parsed as follows:
51 # 1. command line options
52 # 2. user-specific file
53 # 3. system-wide file
54 # Any configuration value is only changed the first time it is set.
55 # Thus, host-specific definitions should be at the beginning of the
56 # configuration file, and defaults at the end.
58 # Host-specific declarations. These may override anything above. A single
59 # host may match multiple declarations; these are processed in the order
60 # that they are given in.
62 Host *.ngs.fi ngs.fi
63 User foo
65 Host fake.com
66 HostName another.host.name.real.org
67 User blaah
68 Port 34289
69 ForwardX11 no
70 ForwardAgent no
72 Host books.com
73 RemoteForward 9999 shadows.cs.hut.fi:9999
74 Cipher 3des
76 Host fascist.blob.com
77 Port 23123
78 User tylonen
79 PasswordAuthentication no
81 Host puukko.hut.fi
82 User t35124p
83 ProxyCommand ssh-proxy %h %p
85 Host *.fr
86 PublicKeyAuthentication no
88 Host *.su
89 Cipher none
90 PasswordAuthentication no
92 Host vpn.fake.com
93 Tunnel yes
94 TunnelDevice 3
96 # Defaults for various options
97 Host *
98 ForwardAgent no
99 ForwardX11 no
100 PasswordAuthentication yes
101 RSAAuthentication yes
102 RhostsRSAAuthentication yes
103 StrictHostKeyChecking yes
104 TcpKeepAlive no
105 IdentityFile ~/.ssh/identity
106 Port 22
107 EscapeChar ~
111 /* Keyword tokens. */
113 typedef enum {
114 oBadOption,
115 oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
116 oGatewayPorts, oExitOnForwardFailure,
117 oPasswordAuthentication, oRSAAuthentication,
118 oChallengeResponseAuthentication, oXAuthLocation,
119 oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
120 oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
121 oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
122 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
123 oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
124 oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
125 oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
126 oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
127 oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
128 oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
129 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
130 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
131 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
132 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
133 oVersionAddendum,
134 oSendEnv, oControlPath, oControlMaster, oControlPersist,
135 oHashKnownHosts,
136 oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
137 oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
138 oNoneEnabled, oTcpRcvBufPoll, oTcpRcvBuf, oNoneSwitch, oHPNDisabled,
139 oHPNBufferSize, oDeprecated, oUnsupported
140 } OpCodes;
142 /* Textual representations of the tokens. */
144 static struct {
145 const char *name;
146 OpCodes opcode;
147 } keywords[] = {
148 { "forwardagent", oForwardAgent },
149 { "forwardx11", oForwardX11 },
150 { "forwardx11trusted", oForwardX11Trusted },
151 { "forwardx11timeout", oForwardX11Timeout },
152 { "exitonforwardfailure", oExitOnForwardFailure },
153 { "xauthlocation", oXAuthLocation },
154 { "gatewayports", oGatewayPorts },
155 { "useprivilegedport", oUsePrivilegedPort },
156 { "rhostsauthentication", oDeprecated },
157 { "passwordauthentication", oPasswordAuthentication },
158 { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
159 { "kbdinteractivedevices", oKbdInteractiveDevices },
160 { "rsaauthentication", oRSAAuthentication },
161 { "pubkeyauthentication", oPubkeyAuthentication },
162 { "dsaauthentication", oPubkeyAuthentication }, /* alias */
163 { "rhostsrsaauthentication", oRhostsRSAAuthentication },
164 { "hostbasedauthentication", oHostbasedAuthentication },
165 { "challengeresponseauthentication", oChallengeResponseAuthentication },
166 { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
167 { "tisauthentication", oChallengeResponseAuthentication }, /* alias */
168 { "kerberosauthentication", oUnsupported },
169 { "kerberostgtpassing", oUnsupported },
170 { "afstokenpassing", oUnsupported },
171 #if defined(GSSAPI)
172 { "gssapiauthentication", oGssAuthentication },
173 { "gssapidelegatecredentials", oGssDelegateCreds },
174 #else
175 { "gssapiauthentication", oUnsupported },
176 { "gssapidelegatecredentials", oUnsupported },
177 #endif
178 { "fallbacktorsh", oDeprecated },
179 { "usersh", oDeprecated },
180 { "identityfile", oIdentityFile },
181 { "identityfile2", oIdentityFile }, /* obsolete */
182 { "identitiesonly", oIdentitiesOnly },
183 { "hostname", oHostName },
184 { "hostkeyalias", oHostKeyAlias },
185 { "proxycommand", oProxyCommand },
186 { "port", oPort },
187 { "cipher", oCipher },
188 { "ciphers", oCiphers },
189 { "macs", oMacs },
190 { "protocol", oProtocol },
191 { "remoteforward", oRemoteForward },
192 { "localforward", oLocalForward },
193 { "user", oUser },
194 { "host", oHost },
195 { "escapechar", oEscapeChar },
196 { "globalknownhostsfile", oGlobalKnownHostsFile },
197 { "globalknownhostsfile2", oGlobalKnownHostsFile2 }, /* obsolete */
198 { "userknownhostsfile", oUserKnownHostsFile },
199 { "userknownhostsfile2", oUserKnownHostsFile2 }, /* obsolete */
200 { "connectionattempts", oConnectionAttempts },
201 { "batchmode", oBatchMode },
202 { "checkhostip", oCheckHostIP },
203 { "stricthostkeychecking", oStrictHostKeyChecking },
204 { "compression", oCompression },
205 { "compressionlevel", oCompressionLevel },
206 { "tcpkeepalive", oTCPKeepAlive },
207 { "keepalive", oTCPKeepAlive }, /* obsolete */
208 { "numberofpasswordprompts", oNumberOfPasswordPrompts },
209 { "loglevel", oLogLevel },
210 { "dynamicforward", oDynamicForward },
211 { "preferredauthentications", oPreferredAuthentications },
212 { "hostkeyalgorithms", oHostKeyAlgorithms },
213 { "bindaddress", oBindAddress },
214 #ifdef ENABLE_PKCS11
215 { "smartcarddevice", oPKCS11Provider },
216 { "pkcs11provider", oPKCS11Provider },
217 #else
218 { "smartcarddevice", oUnsupported },
219 { "pkcs11provider", oUnsupported },
220 #endif
221 { "clearallforwardings", oClearAllForwardings },
222 { "enablesshkeysign", oEnableSSHKeysign },
223 { "verifyhostkeydns", oVerifyHostKeyDNS },
224 { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
225 { "rekeylimit", oRekeyLimit },
226 { "connecttimeout", oConnectTimeout },
227 { "addressfamily", oAddressFamily },
228 { "serveraliveinterval", oServerAliveInterval },
229 { "serveralivecountmax", oServerAliveCountMax },
230 { "versionaddendum", oVersionAddendum },
231 { "sendenv", oSendEnv },
232 { "controlpath", oControlPath },
233 { "controlmaster", oControlMaster },
234 { "controlpersist", oControlPersist },
235 { "hashknownhosts", oHashKnownHosts },
236 { "tunnel", oTunnel },
237 { "tunneldevice", oTunnelDevice },
238 { "localcommand", oLocalCommand },
239 { "permitlocalcommand", oPermitLocalCommand },
240 { "visualhostkey", oVisualHostKey },
241 { "useroaming", oUseRoaming },
242 #ifdef JPAKE
243 { "zeroknowledgepasswordauthentication",
244 oZeroKnowledgePasswordAuthentication },
245 #else
246 { "zeroknowledgepasswordauthentication", oUnsupported },
247 #endif
248 { "noneenabled", oNoneEnabled },
249 { "tcprcvbufpoll", oTcpRcvBufPoll },
250 { "tcprcvbuf", oTcpRcvBuf },
251 { "noneswitch", oNoneSwitch },
252 { "hpndisabled", oHPNDisabled },
253 { "hpnbuffersize", oHPNBufferSize },
255 { NULL, oBadOption }
259 * Adds a local TCP/IP port forward to options. Never returns if there is an
260 * error.
263 void
264 add_local_forward(Options *options, const Forward *newfwd)
266 Forward *fwd;
267 #ifndef NO_IPPORT_RESERVED_CONCEPT
268 extern uid_t original_real_uid;
269 if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
270 fatal("Privileged ports can only be forwarded by root.");
271 #endif
272 options->local_forwards = xrealloc(options->local_forwards,
273 options->num_local_forwards + 1,
274 sizeof(*options->local_forwards));
275 fwd = &options->local_forwards[options->num_local_forwards++];
277 fwd->listen_host = newfwd->listen_host;
278 fwd->listen_port = newfwd->listen_port;
279 fwd->connect_host = newfwd->connect_host;
280 fwd->connect_port = newfwd->connect_port;
284 * Adds a remote TCP/IP port forward to options. Never returns if there is
285 * an error.
288 void
289 add_remote_forward(Options *options, const Forward *newfwd)
291 Forward *fwd;
293 options->remote_forwards = xrealloc(options->remote_forwards,
294 options->num_remote_forwards + 1,
295 sizeof(*options->remote_forwards));
296 fwd = &options->remote_forwards[options->num_remote_forwards++];
298 fwd->listen_host = newfwd->listen_host;
299 fwd->listen_port = newfwd->listen_port;
300 fwd->connect_host = newfwd->connect_host;
301 fwd->connect_port = newfwd->connect_port;
302 fwd->allocated_port = 0;
305 static void
306 clear_forwardings(Options *options)
308 int i;
310 for (i = 0; i < options->num_local_forwards; i++) {
311 if (options->local_forwards[i].listen_host != NULL)
312 xfree(options->local_forwards[i].listen_host);
313 xfree(options->local_forwards[i].connect_host);
315 if (options->num_local_forwards > 0) {
316 xfree(options->local_forwards);
317 options->local_forwards = NULL;
319 options->num_local_forwards = 0;
320 for (i = 0; i < options->num_remote_forwards; i++) {
321 if (options->remote_forwards[i].listen_host != NULL)
322 xfree(options->remote_forwards[i].listen_host);
323 xfree(options->remote_forwards[i].connect_host);
325 if (options->num_remote_forwards > 0) {
326 xfree(options->remote_forwards);
327 options->remote_forwards = NULL;
329 options->num_remote_forwards = 0;
330 options->tun_open = SSH_TUNMODE_NO;
334 * Returns the number of the token pointed to by cp or oBadOption.
337 static OpCodes
338 parse_token(const char *cp, const char *filename, int linenum)
340 u_int i;
342 for (i = 0; keywords[i].name; i++)
343 if (strcasecmp(cp, keywords[i].name) == 0)
344 return keywords[i].opcode;
346 error("%s: line %d: Bad configuration option: %s",
347 filename, linenum, cp);
348 return oBadOption;
352 * Processes a single option line as used in the configuration files. This
353 * only sets those values that have not already been set.
355 #define WHITESPACE " \t\r\n"
358 process_config_line(Options *options, const char *host,
359 char *line, const char *filename, int linenum,
360 int *activep)
362 char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
363 int opcode, *intptr, value, value2, scale;
364 LogLevel *log_level_ptr;
365 long long orig, val64;
366 size_t len;
367 Forward fwd;
369 /* Strip trailing whitespace */
370 for (len = strlen(line) - 1; len > 0; len--) {
371 if (strchr(WHITESPACE, line[len]) == NULL)
372 break;
373 line[len] = '\0';
376 s = line;
377 /* Get the keyword. (Each line is supposed to begin with a keyword). */
378 if ((keyword = strdelim(&s)) == NULL)
379 return 0;
380 /* Ignore leading whitespace. */
381 if (*keyword == '\0')
382 keyword = strdelim(&s);
383 if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
384 return 0;
386 opcode = parse_token(keyword, filename, linenum);
388 switch (opcode) {
389 case oBadOption:
390 /* don't panic, but count bad options */
391 return -1;
392 /* NOTREACHED */
393 case oConnectTimeout:
394 intptr = &options->connection_timeout;
395 parse_time:
396 arg = strdelim(&s);
397 if (!arg || *arg == '\0')
398 fatal("%s line %d: missing time value.",
399 filename, linenum);
400 if ((value = convtime(arg)) == -1)
401 fatal("%s line %d: invalid time value.",
402 filename, linenum);
403 if (*activep && *intptr == -1)
404 *intptr = value;
405 break;
407 case oForwardAgent:
408 intptr = &options->forward_agent;
409 parse_flag:
410 arg = strdelim(&s);
411 if (!arg || *arg == '\0')
412 fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
413 value = 0; /* To avoid compiler warning... */
414 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
415 value = 1;
416 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
417 value = 0;
418 else
419 fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
420 if (*activep && *intptr == -1)
421 *intptr = value;
422 break;
424 case oForwardX11:
425 intptr = &options->forward_x11;
426 goto parse_flag;
428 case oForwardX11Trusted:
429 intptr = &options->forward_x11_trusted;
430 goto parse_flag;
432 case oForwardX11Timeout:
433 intptr = &options->forward_x11_timeout;
434 goto parse_time;
436 case oGatewayPorts:
437 intptr = &options->gateway_ports;
438 goto parse_flag;
440 case oExitOnForwardFailure:
441 intptr = &options->exit_on_forward_failure;
442 goto parse_flag;
444 case oUsePrivilegedPort:
445 intptr = &options->use_privileged_port;
446 goto parse_flag;
448 case oPasswordAuthentication:
449 intptr = &options->password_authentication;
450 goto parse_flag;
452 case oZeroKnowledgePasswordAuthentication:
453 intptr = &options->zero_knowledge_password_authentication;
454 goto parse_flag;
456 case oKbdInteractiveAuthentication:
457 intptr = &options->kbd_interactive_authentication;
458 goto parse_flag;
460 case oKbdInteractiveDevices:
461 charptr = &options->kbd_interactive_devices;
462 goto parse_string;
464 case oPubkeyAuthentication:
465 intptr = &options->pubkey_authentication;
466 goto parse_flag;
468 case oRSAAuthentication:
469 intptr = &options->rsa_authentication;
470 goto parse_flag;
472 case oRhostsRSAAuthentication:
473 intptr = &options->rhosts_rsa_authentication;
474 goto parse_flag;
476 case oHostbasedAuthentication:
477 intptr = &options->hostbased_authentication;
478 goto parse_flag;
480 case oChallengeResponseAuthentication:
481 intptr = &options->challenge_response_authentication;
482 goto parse_flag;
484 case oGssAuthentication:
485 intptr = &options->gss_authentication;
486 goto parse_flag;
488 case oGssDelegateCreds:
489 intptr = &options->gss_deleg_creds;
490 goto parse_flag;
492 case oBatchMode:
493 intptr = &options->batch_mode;
494 goto parse_flag;
496 case oCheckHostIP:
497 intptr = &options->check_host_ip;
498 goto parse_flag;
500 case oNoneEnabled:
501 intptr = &options->none_enabled;
502 goto parse_flag;
504 /* we check to see if the command comes from the */
505 /* command line or not. If it does then enable it */
506 /* otherwise fail. NONE should never be a default configuration */
507 case oNoneSwitch:
508 if(strcmp(filename,"command-line")==0)
510 intptr = &options->none_switch;
511 goto parse_flag;
512 } else {
513 error("NoneSwitch is found in %.200s.\nYou may only use this configuration option from the command line", filename);
514 error("Continuing...");
515 debug("NoneSwitch directive found in %.200s.", filename);
516 return 0;
519 case oHPNDisabled:
520 intptr = &options->hpn_disabled;
521 goto parse_flag;
523 case oHPNBufferSize:
524 intptr = &options->hpn_buffer_size;
525 goto parse_int;
527 case oTcpRcvBufPoll:
528 intptr = &options->tcp_rcv_buf_poll;
529 goto parse_flag;
531 case oVerifyHostKeyDNS:
532 intptr = &options->verify_host_key_dns;
533 goto parse_yesnoask;
535 case oStrictHostKeyChecking:
536 intptr = &options->strict_host_key_checking;
537 parse_yesnoask:
538 arg = strdelim(&s);
539 if (!arg || *arg == '\0')
540 fatal("%.200s line %d: Missing yes/no/ask argument.",
541 filename, linenum);
542 value = 0; /* To avoid compiler warning... */
543 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
544 value = 1;
545 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
546 value = 0;
547 else if (strcmp(arg, "ask") == 0)
548 value = 2;
549 else
550 fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
551 if (*activep && *intptr == -1)
552 *intptr = value;
553 break;
555 case oCompression:
556 intptr = &options->compression;
557 goto parse_flag;
559 case oTCPKeepAlive:
560 intptr = &options->tcp_keep_alive;
561 goto parse_flag;
563 case oNoHostAuthenticationForLocalhost:
564 intptr = &options->no_host_authentication_for_localhost;
565 goto parse_flag;
567 case oNumberOfPasswordPrompts:
568 intptr = &options->number_of_password_prompts;
569 goto parse_int;
571 case oCompressionLevel:
572 intptr = &options->compression_level;
573 goto parse_int;
575 case oRekeyLimit:
576 arg = strdelim(&s);
577 if (!arg || *arg == '\0')
578 fatal("%.200s line %d: Missing argument.", filename, linenum);
579 if (arg[0] < '0' || arg[0] > '9')
580 fatal("%.200s line %d: Bad number.", filename, linenum);
581 orig = val64 = strtoll(arg, &endofnumber, 10);
582 if (arg == endofnumber)
583 fatal("%.200s line %d: Bad number.", filename, linenum);
584 switch (toupper(*endofnumber)) {
585 case '\0':
586 scale = 1;
587 break;
588 case 'K':
589 scale = 1<<10;
590 break;
591 case 'M':
592 scale = 1<<20;
593 break;
594 case 'G':
595 scale = 1<<30;
596 break;
597 default:
598 fatal("%.200s line %d: Invalid RekeyLimit suffix",
599 filename, linenum);
601 val64 *= scale;
602 /* detect integer wrap and too-large limits */
603 if ((val64 / scale) != orig || val64 > UINT_MAX)
604 fatal("%.200s line %d: RekeyLimit too large",
605 filename, linenum);
606 if (val64 < 16)
607 fatal("%.200s line %d: RekeyLimit too small",
608 filename, linenum);
609 if (*activep && options->rekey_limit == -1)
610 options->rekey_limit = (u_int32_t)val64;
611 break;
613 case oIdentityFile:
614 arg = strdelim(&s);
615 if (!arg || *arg == '\0')
616 fatal("%.200s line %d: Missing argument.", filename, linenum);
617 if (*activep) {
618 intptr = &options->num_identity_files;
619 if (*intptr >= SSH_MAX_IDENTITY_FILES)
620 fatal("%.200s line %d: Too many identity files specified (max %d).",
621 filename, linenum, SSH_MAX_IDENTITY_FILES);
622 charptr = &options->identity_files[*intptr];
623 *charptr = xstrdup(arg);
624 *intptr = *intptr + 1;
626 break;
628 case oXAuthLocation:
629 charptr=&options->xauth_location;
630 goto parse_string;
632 case oUser:
633 charptr = &options->user;
634 parse_string:
635 arg = strdelim(&s);
636 if (!arg || *arg == '\0')
637 fatal("%.200s line %d: Missing argument.", filename, linenum);
638 if (*activep && *charptr == NULL)
639 *charptr = xstrdup(arg);
640 break;
642 case oGlobalKnownHostsFile:
643 charptr = &options->system_hostfile;
644 goto parse_string;
646 case oUserKnownHostsFile:
647 charptr = &options->user_hostfile;
648 goto parse_string;
650 case oGlobalKnownHostsFile2:
651 charptr = &options->system_hostfile2;
652 goto parse_string;
654 case oUserKnownHostsFile2:
655 charptr = &options->user_hostfile2;
656 goto parse_string;
658 case oHostName:
659 charptr = &options->hostname;
660 goto parse_string;
662 case oHostKeyAlias:
663 charptr = &options->host_key_alias;
664 goto parse_string;
666 case oPreferredAuthentications:
667 charptr = &options->preferred_authentications;
668 goto parse_string;
670 case oBindAddress:
671 charptr = &options->bind_address;
672 goto parse_string;
674 case oPKCS11Provider:
675 charptr = &options->pkcs11_provider;
676 goto parse_string;
678 case oProxyCommand:
679 charptr = &options->proxy_command;
680 parse_command:
681 if (s == NULL)
682 fatal("%.200s line %d: Missing argument.", filename, linenum);
683 len = strspn(s, WHITESPACE "=");
684 if (*activep && *charptr == NULL)
685 *charptr = xstrdup(s + len);
686 return 0;
688 case oPort:
689 intptr = &options->port;
690 parse_int:
691 arg = strdelim(&s);
692 if (!arg || *arg == '\0')
693 fatal("%.200s line %d: Missing argument.", filename, linenum);
694 if (arg[0] < '0' || arg[0] > '9')
695 fatal("%.200s line %d: Bad number.", filename, linenum);
697 /* Octal, decimal, or hex format? */
698 value = strtol(arg, &endofnumber, 0);
699 if (arg == endofnumber)
700 fatal("%.200s line %d: Bad number.", filename, linenum);
701 if (*activep && *intptr == -1)
702 *intptr = value;
703 break;
705 case oConnectionAttempts:
706 intptr = &options->connection_attempts;
707 goto parse_int;
709 case oTcpRcvBuf:
710 intptr = &options->tcp_rcv_buf;
711 goto parse_int;
713 case oCipher:
714 intptr = &options->cipher;
715 arg = strdelim(&s);
716 if (!arg || *arg == '\0')
717 fatal("%.200s line %d: Missing argument.", filename, linenum);
718 value = cipher_number(arg);
719 if (value == -1)
720 fatal("%.200s line %d: Bad cipher '%s'.",
721 filename, linenum, arg ? arg : "<NONE>");
722 if (*activep && *intptr == -1)
723 *intptr = value;
724 break;
726 case oCiphers:
727 arg = strdelim(&s);
728 if (!arg || *arg == '\0')
729 fatal("%.200s line %d: Missing argument.", filename, linenum);
730 if (!ciphers_valid(arg))
731 fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
732 filename, linenum, arg ? arg : "<NONE>");
733 if (*activep && options->ciphers == NULL)
734 options->ciphers = xstrdup(arg);
735 break;
737 case oMacs:
738 arg = strdelim(&s);
739 if (!arg || *arg == '\0')
740 fatal("%.200s line %d: Missing argument.", filename, linenum);
741 if (!mac_valid(arg))
742 fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
743 filename, linenum, arg ? arg : "<NONE>");
744 if (*activep && options->macs == NULL)
745 options->macs = xstrdup(arg);
746 break;
748 case oHostKeyAlgorithms:
749 arg = strdelim(&s);
750 if (!arg || *arg == '\0')
751 fatal("%.200s line %d: Missing argument.", filename, linenum);
752 if (!key_names_valid2(arg))
753 fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
754 filename, linenum, arg ? arg : "<NONE>");
755 if (*activep && options->hostkeyalgorithms == NULL)
756 options->hostkeyalgorithms = xstrdup(arg);
757 break;
759 case oProtocol:
760 intptr = &options->protocol;
761 arg = strdelim(&s);
762 if (!arg || *arg == '\0')
763 fatal("%.200s line %d: Missing argument.", filename, linenum);
764 value = proto_spec(arg);
765 if (value == SSH_PROTO_UNKNOWN)
766 fatal("%.200s line %d: Bad protocol spec '%s'.",
767 filename, linenum, arg ? arg : "<NONE>");
768 if (*activep && *intptr == SSH_PROTO_UNKNOWN)
769 *intptr = value;
770 break;
772 case oLogLevel:
773 log_level_ptr = &options->log_level;
774 arg = strdelim(&s);
775 value = log_level_number(arg);
776 if (value == SYSLOG_LEVEL_NOT_SET)
777 fatal("%.200s line %d: unsupported log level '%s'",
778 filename, linenum, arg ? arg : "<NONE>");
779 if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
780 *log_level_ptr = (LogLevel) value;
781 break;
783 case oLocalForward:
784 case oRemoteForward:
785 case oDynamicForward:
786 arg = strdelim(&s);
787 if (arg == NULL || *arg == '\0')
788 fatal("%.200s line %d: Missing port argument.",
789 filename, linenum);
791 if (opcode == oLocalForward ||
792 opcode == oRemoteForward) {
793 arg2 = strdelim(&s);
794 if (arg2 == NULL || *arg2 == '\0')
795 fatal("%.200s line %d: Missing target argument.",
796 filename, linenum);
798 /* construct a string for parse_forward */
799 snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
800 } else if (opcode == oDynamicForward) {
801 strlcpy(fwdarg, arg, sizeof(fwdarg));
804 if (parse_forward(&fwd, fwdarg,
805 opcode == oDynamicForward ? 1 : 0,
806 opcode == oRemoteForward ? 1 : 0) == 0)
807 fatal("%.200s line %d: Bad forwarding specification.",
808 filename, linenum);
810 if (*activep) {
811 if (opcode == oLocalForward ||
812 opcode == oDynamicForward)
813 add_local_forward(options, &fwd);
814 else if (opcode == oRemoteForward)
815 add_remote_forward(options, &fwd);
817 break;
819 case oClearAllForwardings:
820 intptr = &options->clear_forwardings;
821 goto parse_flag;
823 case oHost:
824 *activep = 0;
825 while ((arg = strdelim(&s)) != NULL && *arg != '\0')
826 if (match_pattern(host, arg)) {
827 debug("Applying options for %.100s", arg);
828 *activep = 1;
829 break;
831 /* Avoid garbage check below, as strdelim is done. */
832 return 0;
834 case oEscapeChar:
835 intptr = &options->escape_char;
836 arg = strdelim(&s);
837 if (!arg || *arg == '\0')
838 fatal("%.200s line %d: Missing argument.", filename, linenum);
839 if (arg[0] == '^' && arg[2] == 0 &&
840 (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
841 value = (u_char) arg[1] & 31;
842 else if (strlen(arg) == 1)
843 value = (u_char) arg[0];
844 else if (strcmp(arg, "none") == 0)
845 value = SSH_ESCAPECHAR_NONE;
846 else {
847 fatal("%.200s line %d: Bad escape character.",
848 filename, linenum);
849 /* NOTREACHED */
850 value = 0; /* Avoid compiler warning. */
852 if (*activep && *intptr == -1)
853 *intptr = value;
854 break;
856 case oAddressFamily:
857 arg = strdelim(&s);
858 if (!arg || *arg == '\0')
859 fatal("%s line %d: missing address family.",
860 filename, linenum);
861 intptr = &options->address_family;
862 if (strcasecmp(arg, "inet") == 0)
863 value = AF_INET;
864 else if (strcasecmp(arg, "inet6") == 0)
865 value = AF_INET6;
866 else if (strcasecmp(arg, "any") == 0)
867 value = AF_UNSPEC;
868 else
869 fatal("Unsupported AddressFamily \"%s\"", arg);
870 if (*activep && *intptr == -1)
871 *intptr = value;
872 break;
874 case oEnableSSHKeysign:
875 intptr = &options->enable_ssh_keysign;
876 goto parse_flag;
878 case oIdentitiesOnly:
879 intptr = &options->identities_only;
880 goto parse_flag;
882 case oServerAliveInterval:
883 intptr = &options->server_alive_interval;
884 goto parse_time;
886 case oServerAliveCountMax:
887 intptr = &options->server_alive_count_max;
888 goto parse_int;
890 case oVersionAddendum:
891 ssh_version_set_addendum(strtok(s, "\n"));
892 do {
893 arg = strdelim(&s);
894 } while (arg != NULL && *arg != '\0');
895 break;
897 case oSendEnv:
898 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
899 if (strchr(arg, '=') != NULL)
900 fatal("%s line %d: Invalid environment name.",
901 filename, linenum);
902 if (!*activep)
903 continue;
904 if (options->num_send_env >= MAX_SEND_ENV)
905 fatal("%s line %d: too many send env.",
906 filename, linenum);
907 options->send_env[options->num_send_env++] =
908 xstrdup(arg);
910 break;
912 case oControlPath:
913 charptr = &options->control_path;
914 goto parse_string;
916 case oControlMaster:
917 intptr = &options->control_master;
918 arg = strdelim(&s);
919 if (!arg || *arg == '\0')
920 fatal("%.200s line %d: Missing ControlMaster argument.",
921 filename, linenum);
922 value = 0; /* To avoid compiler warning... */
923 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
924 value = SSHCTL_MASTER_YES;
925 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
926 value = SSHCTL_MASTER_NO;
927 else if (strcmp(arg, "auto") == 0)
928 value = SSHCTL_MASTER_AUTO;
929 else if (strcmp(arg, "ask") == 0)
930 value = SSHCTL_MASTER_ASK;
931 else if (strcmp(arg, "autoask") == 0)
932 value = SSHCTL_MASTER_AUTO_ASK;
933 else
934 fatal("%.200s line %d: Bad ControlMaster argument.",
935 filename, linenum);
936 if (*activep && *intptr == -1)
937 *intptr = value;
938 break;
940 case oControlPersist:
941 /* no/false/yes/true, or a time spec */
942 intptr = &options->control_persist;
943 arg = strdelim(&s);
944 if (!arg || *arg == '\0')
945 fatal("%.200s line %d: Missing ControlPersist"
946 " argument.", filename, linenum);
947 value = 0;
948 value2 = 0; /* timeout */
949 if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
950 value = 0;
951 else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
952 value = 1;
953 else if ((value2 = convtime(arg)) >= 0)
954 value = 1;
955 else
956 fatal("%.200s line %d: Bad ControlPersist argument.",
957 filename, linenum);
958 if (*activep && *intptr == -1) {
959 *intptr = value;
960 options->control_persist_timeout = value2;
962 break;
964 case oHashKnownHosts:
965 intptr = &options->hash_known_hosts;
966 goto parse_flag;
968 case oTunnel:
969 intptr = &options->tun_open;
970 arg = strdelim(&s);
971 if (!arg || *arg == '\0')
972 fatal("%s line %d: Missing yes/point-to-point/"
973 "ethernet/no argument.", filename, linenum);
974 value = 0; /* silence compiler */
975 if (strcasecmp(arg, "ethernet") == 0)
976 value = SSH_TUNMODE_ETHERNET;
977 else if (strcasecmp(arg, "point-to-point") == 0)
978 value = SSH_TUNMODE_POINTOPOINT;
979 else if (strcasecmp(arg, "yes") == 0)
980 value = SSH_TUNMODE_DEFAULT;
981 else if (strcasecmp(arg, "no") == 0)
982 value = SSH_TUNMODE_NO;
983 else
984 fatal("%s line %d: Bad yes/point-to-point/ethernet/"
985 "no argument: %s", filename, linenum, arg);
986 if (*activep)
987 *intptr = value;
988 break;
990 case oTunnelDevice:
991 arg = strdelim(&s);
992 if (!arg || *arg == '\0')
993 fatal("%.200s line %d: Missing argument.", filename, linenum);
994 value = a2tun(arg, &value2);
995 if (value == SSH_TUNID_ERR)
996 fatal("%.200s line %d: Bad tun device.", filename, linenum);
997 if (*activep) {
998 options->tun_local = value;
999 options->tun_remote = value2;
1001 break;
1003 case oLocalCommand:
1004 charptr = &options->local_command;
1005 goto parse_command;
1007 case oPermitLocalCommand:
1008 intptr = &options->permit_local_command;
1009 goto parse_flag;
1011 case oVisualHostKey:
1012 intptr = &options->visual_host_key;
1013 goto parse_flag;
1015 case oUseRoaming:
1016 intptr = &options->use_roaming;
1017 goto parse_flag;
1019 case oDeprecated:
1020 debug("%s line %d: Deprecated option \"%s\"",
1021 filename, linenum, keyword);
1022 return 0;
1024 case oUnsupported:
1025 error("%s line %d: Unsupported option \"%s\"",
1026 filename, linenum, keyword);
1027 return 0;
1029 default:
1030 fatal("process_config_line: Unimplemented opcode %d", opcode);
1033 /* Check that there is no garbage at end of line. */
1034 if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1035 fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
1036 filename, linenum, arg);
1038 return 0;
1043 * Reads the config file and modifies the options accordingly. Options
1044 * should already be initialized before this call. This never returns if
1045 * there is an error. If the file does not exist, this returns 0.
1049 read_config_file(const char *filename, const char *host, Options *options,
1050 int checkperm)
1052 FILE *f;
1053 char line[1024];
1054 int active, linenum;
1055 int bad_options = 0;
1057 if ((f = fopen(filename, "r")) == NULL)
1058 return 0;
1060 if (checkperm) {
1061 struct stat sb;
1063 if (fstat(fileno(f), &sb) == -1)
1064 fatal("fstat %s: %s", filename, strerror(errno));
1065 if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
1066 (sb.st_mode & 022) != 0))
1067 fatal("Bad owner or permissions on %s", filename);
1070 debug("Reading configuration data %.200s", filename);
1073 * Mark that we are now processing the options. This flag is turned
1074 * on/off by Host specifications.
1076 active = 1;
1077 linenum = 0;
1078 while (fgets(line, sizeof(line), f)) {
1079 /* Update line number counter. */
1080 linenum++;
1081 if (process_config_line(options, host, line, filename, linenum, &active) != 0)
1082 bad_options++;
1084 fclose(f);
1085 if (bad_options > 0)
1086 fatal("%s: terminating, %d bad configuration options",
1087 filename, bad_options);
1088 return 1;
1092 * Initializes options to special values that indicate that they have not yet
1093 * been set. Read_config_file will only set options with this value. Options
1094 * are processed in the following order: command line, user config file,
1095 * system config file. Last, fill_default_options is called.
1098 void
1099 initialize_options(Options * options)
1101 memset(options, 'X', sizeof(*options));
1102 options->forward_agent = -1;
1103 options->forward_x11 = -1;
1104 options->forward_x11_trusted = -1;
1105 options->forward_x11_timeout = -1;
1106 options->exit_on_forward_failure = -1;
1107 options->xauth_location = NULL;
1108 options->gateway_ports = -1;
1109 options->use_privileged_port = -1;
1110 options->rsa_authentication = -1;
1111 options->pubkey_authentication = -1;
1112 options->challenge_response_authentication = -1;
1113 options->gss_authentication = -1;
1114 options->gss_deleg_creds = -1;
1115 options->password_authentication = -1;
1116 options->kbd_interactive_authentication = -1;
1117 options->kbd_interactive_devices = NULL;
1118 options->rhosts_rsa_authentication = -1;
1119 options->hostbased_authentication = -1;
1120 options->batch_mode = -1;
1121 options->check_host_ip = -1;
1122 options->strict_host_key_checking = -1;
1123 options->compression = -1;
1124 options->tcp_keep_alive = -1;
1125 options->compression_level = -1;
1126 options->port = -1;
1127 options->address_family = -1;
1128 options->connection_attempts = -1;
1129 options->connection_timeout = -1;
1130 options->number_of_password_prompts = -1;
1131 options->cipher = -1;
1132 options->ciphers = NULL;
1133 options->macs = NULL;
1134 options->hostkeyalgorithms = NULL;
1135 options->protocol = SSH_PROTO_UNKNOWN;
1136 options->num_identity_files = 0;
1137 options->hostname = NULL;
1138 options->host_key_alias = NULL;
1139 options->proxy_command = NULL;
1140 options->user = NULL;
1141 options->escape_char = -1;
1142 options->system_hostfile = NULL;
1143 options->user_hostfile = NULL;
1144 options->system_hostfile2 = NULL;
1145 options->user_hostfile2 = NULL;
1146 options->local_forwards = NULL;
1147 options->num_local_forwards = 0;
1148 options->remote_forwards = NULL;
1149 options->num_remote_forwards = 0;
1150 options->clear_forwardings = -1;
1151 options->log_level = SYSLOG_LEVEL_NOT_SET;
1152 options->preferred_authentications = NULL;
1153 options->bind_address = NULL;
1154 options->pkcs11_provider = NULL;
1155 options->enable_ssh_keysign = - 1;
1156 options->no_host_authentication_for_localhost = - 1;
1157 options->identities_only = - 1;
1158 options->rekey_limit = - 1;
1159 options->verify_host_key_dns = -1;
1160 options->server_alive_interval = -1;
1161 options->server_alive_count_max = -1;
1162 options->num_send_env = 0;
1163 options->control_path = NULL;
1164 options->control_master = -1;
1165 options->control_persist = -1;
1166 options->control_persist_timeout = 0;
1167 options->hash_known_hosts = -1;
1168 options->tun_open = -1;
1169 options->tun_local = -1;
1170 options->tun_remote = -1;
1171 options->local_command = NULL;
1172 options->permit_local_command = -1;
1173 options->use_roaming = -1;
1174 options->visual_host_key = -1;
1175 options->zero_knowledge_password_authentication = -1;
1176 options->none_switch = -1;
1177 options->none_enabled = -1;
1178 options->hpn_disabled = -1;
1179 options->hpn_buffer_size = -1;
1180 options->tcp_rcv_buf_poll = -1;
1181 options->tcp_rcv_buf = -1;
1185 * Called after processing other sources of option data, this fills those
1186 * options for which no value has been specified with their default values.
1189 void
1190 fill_default_options(Options * options)
1192 int len;
1194 if (options->forward_agent == -1)
1195 options->forward_agent = 0;
1196 if (options->forward_x11 == -1)
1197 options->forward_x11 = 0;
1198 if (options->forward_x11_trusted == -1)
1199 options->forward_x11_trusted = 0;
1200 if (options->forward_x11_timeout == -1)
1201 options->forward_x11_timeout = 1200;
1202 if (options->exit_on_forward_failure == -1)
1203 options->exit_on_forward_failure = 0;
1204 if (options->xauth_location == NULL)
1205 options->xauth_location = _PATH_XAUTH;
1206 if (options->gateway_ports == -1)
1207 options->gateway_ports = 0;
1208 if (options->use_privileged_port == -1)
1209 options->use_privileged_port = 0;
1210 if (options->rsa_authentication == -1)
1211 options->rsa_authentication = 1;
1212 if (options->pubkey_authentication == -1)
1213 options->pubkey_authentication = 1;
1214 if (options->challenge_response_authentication == -1)
1215 options->challenge_response_authentication = 1;
1216 if (options->gss_authentication == -1)
1217 options->gss_authentication = 0;
1218 if (options->gss_deleg_creds == -1)
1219 options->gss_deleg_creds = 0;
1220 if (options->password_authentication == -1)
1221 options->password_authentication = 1;
1222 if (options->kbd_interactive_authentication == -1)
1223 options->kbd_interactive_authentication = 1;
1224 if (options->rhosts_rsa_authentication == -1)
1225 options->rhosts_rsa_authentication = 0;
1226 if (options->hostbased_authentication == -1)
1227 options->hostbased_authentication = 0;
1228 if (options->batch_mode == -1)
1229 options->batch_mode = 0;
1230 if (options->check_host_ip == -1)
1231 options->check_host_ip = 0;
1232 if (options->strict_host_key_checking == -1)
1233 options->strict_host_key_checking = 2; /* 2 is default */
1234 if (options->compression == -1)
1235 options->compression = 0;
1236 if (options->tcp_keep_alive == -1)
1237 options->tcp_keep_alive = 1;
1238 if (options->compression_level == -1)
1239 options->compression_level = 6;
1240 if (options->port == -1)
1241 options->port = 0; /* Filled in ssh_connect. */
1242 if (options->address_family == -1)
1243 options->address_family = AF_UNSPEC;
1244 if (options->connection_attempts == -1)
1245 options->connection_attempts = 1;
1246 if (options->number_of_password_prompts == -1)
1247 options->number_of_password_prompts = 3;
1248 /* Selected in ssh_login(). */
1249 if (options->cipher == -1)
1250 options->cipher = SSH_CIPHER_NOT_SET;
1251 /* options->ciphers, default set in myproposals.h */
1252 /* options->macs, default set in myproposals.h */
1253 /* options->hostkeyalgorithms, default set in myproposals.h */
1254 if (options->protocol == SSH_PROTO_UNKNOWN)
1255 options->protocol = SSH_PROTO_2;
1256 if (options->num_identity_files == 0) {
1257 if (options->protocol & SSH_PROTO_1) {
1258 len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
1259 options->identity_files[options->num_identity_files] =
1260 xmalloc(len);
1261 snprintf(options->identity_files[options->num_identity_files++],
1262 len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
1264 if (options->protocol & SSH_PROTO_2) {
1265 len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
1266 options->identity_files[options->num_identity_files] =
1267 xmalloc(len);
1268 snprintf(options->identity_files[options->num_identity_files++],
1269 len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
1271 len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
1272 options->identity_files[options->num_identity_files] =
1273 xmalloc(len);
1274 snprintf(options->identity_files[options->num_identity_files++],
1275 len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
1278 if (options->escape_char == -1)
1279 options->escape_char = '~';
1280 if (options->system_hostfile == NULL)
1281 options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
1282 if (options->user_hostfile == NULL)
1283 options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
1284 if (options->system_hostfile2 == NULL)
1285 options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
1286 if (options->user_hostfile2 == NULL)
1287 options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
1288 if (options->log_level == SYSLOG_LEVEL_NOT_SET)
1289 options->log_level = SYSLOG_LEVEL_INFO;
1290 if (options->clear_forwardings == 1)
1291 clear_forwardings(options);
1292 if (options->no_host_authentication_for_localhost == - 1)
1293 options->no_host_authentication_for_localhost = 0;
1294 if (options->identities_only == -1)
1295 options->identities_only = 0;
1296 if (options->enable_ssh_keysign == -1)
1297 options->enable_ssh_keysign = 0;
1298 if (options->rekey_limit == -1)
1299 options->rekey_limit = 0;
1300 if (options->verify_host_key_dns == -1)
1301 options->verify_host_key_dns = 0;
1302 if (options->server_alive_interval == -1)
1303 options->server_alive_interval = 0;
1304 if (options->server_alive_count_max == -1)
1305 options->server_alive_count_max = 3;
1306 if (options->none_switch == -1)
1307 options->none_switch = 0;
1308 if (options->hpn_disabled == -1)
1309 options->hpn_disabled = 0;
1310 if (options->hpn_buffer_size > -1)
1312 /* if a user tries to set the size to 0 set it to 1KB */
1313 if (options->hpn_buffer_size == 0)
1314 options->hpn_buffer_size = 1024;
1315 /*limit the buffer to 64MB*/
1316 if (options->hpn_buffer_size > 65536)
1318 options->hpn_buffer_size = 65536*1024;
1319 debug("User requested buffer larger than 64MB. Request reverted to 64MB");
1321 debug("hpn_buffer_size set to %d", options->hpn_buffer_size);
1323 if (options->tcp_rcv_buf == 0)
1324 options->tcp_rcv_buf = 1;
1325 if (options->tcp_rcv_buf > -1)
1326 options->tcp_rcv_buf *=1024;
1327 if (options->tcp_rcv_buf_poll == -1)
1328 options->tcp_rcv_buf_poll = 1;
1329 if (options->control_master == -1)
1330 options->control_master = 0;
1331 if (options->control_persist == -1) {
1332 options->control_persist = 0;
1333 options->control_persist_timeout = 0;
1335 if (options->hash_known_hosts == -1)
1336 options->hash_known_hosts = 0;
1337 if (options->tun_open == -1)
1338 options->tun_open = SSH_TUNMODE_NO;
1339 if (options->tun_local == -1)
1340 options->tun_local = SSH_TUNID_ANY;
1341 if (options->tun_remote == -1)
1342 options->tun_remote = SSH_TUNID_ANY;
1343 if (options->permit_local_command == -1)
1344 options->permit_local_command = 0;
1345 if (options->use_roaming == -1)
1346 options->use_roaming = 1;
1347 if (options->visual_host_key == -1)
1348 options->visual_host_key = 0;
1349 if (options->zero_knowledge_password_authentication == -1)
1350 options->zero_knowledge_password_authentication = 0;
1351 /* options->local_command should not be set by default */
1352 /* options->proxy_command should not be set by default */
1353 /* options->user will be set in the main program if appropriate */
1354 /* options->hostname will be set in the main program if appropriate */
1355 /* options->host_key_alias should not be set by default */
1356 /* options->preferred_authentications will be set in ssh */
1360 * parse_forward
1361 * parses a string containing a port forwarding specification of the form:
1362 * dynamicfwd == 0
1363 * [listenhost:]listenport:connecthost:connectport
1364 * dynamicfwd == 1
1365 * [listenhost:]listenport
1366 * returns number of arguments parsed or zero on error
1369 parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
1371 int i;
1372 char *p, *cp, *fwdarg[4];
1374 memset(fwd, '\0', sizeof(*fwd));
1376 cp = p = xstrdup(fwdspec);
1378 /* skip leading spaces */
1379 while (isspace(*cp))
1380 cp++;
1382 for (i = 0; i < 4; ++i)
1383 if ((fwdarg[i] = hpdelim(&cp)) == NULL)
1384 break;
1386 /* Check for trailing garbage */
1387 if (cp != NULL)
1388 i = 0; /* failure */
1390 switch (i) {
1391 case 1:
1392 fwd->listen_host = NULL;
1393 fwd->listen_port = a2port(fwdarg[0]);
1394 fwd->connect_host = xstrdup("socks");
1395 break;
1397 case 2:
1398 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1399 fwd->listen_port = a2port(fwdarg[1]);
1400 fwd->connect_host = xstrdup("socks");
1401 break;
1403 case 3:
1404 fwd->listen_host = NULL;
1405 fwd->listen_port = a2port(fwdarg[0]);
1406 fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
1407 fwd->connect_port = a2port(fwdarg[2]);
1408 break;
1410 case 4:
1411 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1412 fwd->listen_port = a2port(fwdarg[1]);
1413 fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
1414 fwd->connect_port = a2port(fwdarg[3]);
1415 break;
1416 default:
1417 i = 0; /* failure */
1420 xfree(p);
1422 if (dynamicfwd) {
1423 if (!(i == 1 || i == 2))
1424 goto fail_free;
1425 } else {
1426 if (!(i == 3 || i == 4))
1427 goto fail_free;
1428 if (fwd->connect_port <= 0)
1429 goto fail_free;
1432 if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0))
1433 goto fail_free;
1435 if (fwd->connect_host != NULL &&
1436 strlen(fwd->connect_host) >= NI_MAXHOST)
1437 goto fail_free;
1438 if (fwd->listen_host != NULL &&
1439 strlen(fwd->listen_host) >= NI_MAXHOST)
1440 goto fail_free;
1443 return (i);
1445 fail_free:
1446 if (fwd->connect_host != NULL) {
1447 xfree(fwd->connect_host);
1448 fwd->connect_host = NULL;
1450 if (fwd->listen_host != NULL) {
1451 xfree(fwd->listen_host);
1452 fwd->listen_host = NULL;
1454 return (0);