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