- (djm) [loginrec.c] Relax permission requirement on btmp logs to allow
[openssh-git.git] / readconf.c
blobeb4a8b9eea6a6159bef5d74faebc545d035eff1b
1 /* $OpenBSD: readconf.c,v 1.190 2010/11/13 23:27:50 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>
22 #include <netinet/in_systm.h>
23 #include <netinet/ip.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <netdb.h>
28 #include <signal.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <unistd.h>
34 #include "xmalloc.h"
35 #include "ssh.h"
36 #include "compat.h"
37 #include "cipher.h"
38 #include "pathnames.h"
39 #include "log.h"
40 #include "key.h"
41 #include "readconf.h"
42 #include "match.h"
43 #include "misc.h"
44 #include "buffer.h"
45 #include "kex.h"
46 #include "mac.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 oSendEnv, oControlPath, oControlMaster, oControlPersist,
134 oHashKnownHosts,
135 oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
136 oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
137 oKexAlgorithms, oIPQoS,
138 oDeprecated, oUnsupported
139 } OpCodes;
141 /* Textual representations of the tokens. */
143 static struct {
144 const char *name;
145 OpCodes opcode;
146 } keywords[] = {
147 { "forwardagent", oForwardAgent },
148 { "forwardx11", oForwardX11 },
149 { "forwardx11trusted", oForwardX11Trusted },
150 { "forwardx11timeout", oForwardX11Timeout },
151 { "exitonforwardfailure", oExitOnForwardFailure },
152 { "xauthlocation", oXAuthLocation },
153 { "gatewayports", oGatewayPorts },
154 { "useprivilegedport", oUsePrivilegedPort },
155 { "rhostsauthentication", oDeprecated },
156 { "passwordauthentication", oPasswordAuthentication },
157 { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
158 { "kbdinteractivedevices", oKbdInteractiveDevices },
159 { "rsaauthentication", oRSAAuthentication },
160 { "pubkeyauthentication", oPubkeyAuthentication },
161 { "dsaauthentication", oPubkeyAuthentication }, /* alias */
162 { "rhostsrsaauthentication", oRhostsRSAAuthentication },
163 { "hostbasedauthentication", oHostbasedAuthentication },
164 { "challengeresponseauthentication", oChallengeResponseAuthentication },
165 { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
166 { "tisauthentication", oChallengeResponseAuthentication }, /* alias */
167 { "kerberosauthentication", oUnsupported },
168 { "kerberostgtpassing", oUnsupported },
169 { "afstokenpassing", oUnsupported },
170 #if defined(GSSAPI)
171 { "gssapiauthentication", oGssAuthentication },
172 { "gssapidelegatecredentials", oGssDelegateCreds },
173 #else
174 { "gssapiauthentication", oUnsupported },
175 { "gssapidelegatecredentials", oUnsupported },
176 #endif
177 { "fallbacktorsh", oDeprecated },
178 { "usersh", oDeprecated },
179 { "identityfile", oIdentityFile },
180 { "identityfile2", oIdentityFile }, /* obsolete */
181 { "identitiesonly", oIdentitiesOnly },
182 { "hostname", oHostName },
183 { "hostkeyalias", oHostKeyAlias },
184 { "proxycommand", oProxyCommand },
185 { "port", oPort },
186 { "cipher", oCipher },
187 { "ciphers", oCiphers },
188 { "macs", oMacs },
189 { "protocol", oProtocol },
190 { "remoteforward", oRemoteForward },
191 { "localforward", oLocalForward },
192 { "user", oUser },
193 { "host", oHost },
194 { "escapechar", oEscapeChar },
195 { "globalknownhostsfile", oGlobalKnownHostsFile },
196 { "globalknownhostsfile2", oGlobalKnownHostsFile2 }, /* obsolete */
197 { "userknownhostsfile", oUserKnownHostsFile },
198 { "userknownhostsfile2", oUserKnownHostsFile2 }, /* obsolete */
199 { "connectionattempts", oConnectionAttempts },
200 { "batchmode", oBatchMode },
201 { "checkhostip", oCheckHostIP },
202 { "stricthostkeychecking", oStrictHostKeyChecking },
203 { "compression", oCompression },
204 { "compressionlevel", oCompressionLevel },
205 { "tcpkeepalive", oTCPKeepAlive },
206 { "keepalive", oTCPKeepAlive }, /* obsolete */
207 { "numberofpasswordprompts", oNumberOfPasswordPrompts },
208 { "loglevel", oLogLevel },
209 { "dynamicforward", oDynamicForward },
210 { "preferredauthentications", oPreferredAuthentications },
211 { "hostkeyalgorithms", oHostKeyAlgorithms },
212 { "bindaddress", oBindAddress },
213 #ifdef ENABLE_PKCS11
214 { "smartcarddevice", oPKCS11Provider },
215 { "pkcs11provider", oPKCS11Provider },
216 #else
217 { "smartcarddevice", oUnsupported },
218 { "pkcs11provider", oUnsupported },
219 #endif
220 { "clearallforwardings", oClearAllForwardings },
221 { "enablesshkeysign", oEnableSSHKeysign },
222 { "verifyhostkeydns", oVerifyHostKeyDNS },
223 { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
224 { "rekeylimit", oRekeyLimit },
225 { "connecttimeout", oConnectTimeout },
226 { "addressfamily", oAddressFamily },
227 { "serveraliveinterval", oServerAliveInterval },
228 { "serveralivecountmax", oServerAliveCountMax },
229 { "sendenv", oSendEnv },
230 { "controlpath", oControlPath },
231 { "controlmaster", oControlMaster },
232 { "controlpersist", oControlPersist },
233 { "hashknownhosts", oHashKnownHosts },
234 { "tunnel", oTunnel },
235 { "tunneldevice", oTunnelDevice },
236 { "localcommand", oLocalCommand },
237 { "permitlocalcommand", oPermitLocalCommand },
238 { "visualhostkey", oVisualHostKey },
239 { "useroaming", oUseRoaming },
240 #ifdef JPAKE
241 { "zeroknowledgepasswordauthentication",
242 oZeroKnowledgePasswordAuthentication },
243 #else
244 { "zeroknowledgepasswordauthentication", oUnsupported },
245 #endif
246 { "kexalgorithms", oKexAlgorithms },
247 { "ipqos", oIPQoS },
249 { NULL, oBadOption }
253 * Adds a local TCP/IP port forward to options. Never returns if there is an
254 * error.
257 void
258 add_local_forward(Options *options, const Forward *newfwd)
260 Forward *fwd;
261 #ifndef NO_IPPORT_RESERVED_CONCEPT
262 extern uid_t original_real_uid;
263 if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
264 fatal("Privileged ports can only be forwarded by root.");
265 #endif
266 options->local_forwards = xrealloc(options->local_forwards,
267 options->num_local_forwards + 1,
268 sizeof(*options->local_forwards));
269 fwd = &options->local_forwards[options->num_local_forwards++];
271 fwd->listen_host = newfwd->listen_host;
272 fwd->listen_port = newfwd->listen_port;
273 fwd->connect_host = newfwd->connect_host;
274 fwd->connect_port = newfwd->connect_port;
278 * Adds a remote TCP/IP port forward to options. Never returns if there is
279 * an error.
282 void
283 add_remote_forward(Options *options, const Forward *newfwd)
285 Forward *fwd;
287 options->remote_forwards = xrealloc(options->remote_forwards,
288 options->num_remote_forwards + 1,
289 sizeof(*options->remote_forwards));
290 fwd = &options->remote_forwards[options->num_remote_forwards++];
292 fwd->listen_host = newfwd->listen_host;
293 fwd->listen_port = newfwd->listen_port;
294 fwd->connect_host = newfwd->connect_host;
295 fwd->connect_port = newfwd->connect_port;
296 fwd->allocated_port = 0;
299 static void
300 clear_forwardings(Options *options)
302 int i;
304 for (i = 0; i < options->num_local_forwards; i++) {
305 if (options->local_forwards[i].listen_host != NULL)
306 xfree(options->local_forwards[i].listen_host);
307 xfree(options->local_forwards[i].connect_host);
309 if (options->num_local_forwards > 0) {
310 xfree(options->local_forwards);
311 options->local_forwards = NULL;
313 options->num_local_forwards = 0;
314 for (i = 0; i < options->num_remote_forwards; i++) {
315 if (options->remote_forwards[i].listen_host != NULL)
316 xfree(options->remote_forwards[i].listen_host);
317 xfree(options->remote_forwards[i].connect_host);
319 if (options->num_remote_forwards > 0) {
320 xfree(options->remote_forwards);
321 options->remote_forwards = NULL;
323 options->num_remote_forwards = 0;
324 options->tun_open = SSH_TUNMODE_NO;
328 * Returns the number of the token pointed to by cp or oBadOption.
331 static OpCodes
332 parse_token(const char *cp, const char *filename, int linenum)
334 u_int i;
336 for (i = 0; keywords[i].name; i++)
337 if (strcasecmp(cp, keywords[i].name) == 0)
338 return keywords[i].opcode;
340 error("%s: line %d: Bad configuration option: %s",
341 filename, linenum, cp);
342 return oBadOption;
346 * Processes a single option line as used in the configuration files. This
347 * only sets those values that have not already been set.
349 #define WHITESPACE " \t\r\n"
352 process_config_line(Options *options, const char *host,
353 char *line, const char *filename, int linenum,
354 int *activep)
356 char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
357 int opcode, *intptr, value, value2, scale;
358 LogLevel *log_level_ptr;
359 long long orig, val64;
360 size_t len;
361 Forward fwd;
363 /* Strip trailing whitespace */
364 for (len = strlen(line) - 1; len > 0; len--) {
365 if (strchr(WHITESPACE, line[len]) == NULL)
366 break;
367 line[len] = '\0';
370 s = line;
371 /* Get the keyword. (Each line is supposed to begin with a keyword). */
372 if ((keyword = strdelim(&s)) == NULL)
373 return 0;
374 /* Ignore leading whitespace. */
375 if (*keyword == '\0')
376 keyword = strdelim(&s);
377 if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
378 return 0;
380 opcode = parse_token(keyword, filename, linenum);
382 switch (opcode) {
383 case oBadOption:
384 /* don't panic, but count bad options */
385 return -1;
386 /* NOTREACHED */
387 case oConnectTimeout:
388 intptr = &options->connection_timeout;
389 parse_time:
390 arg = strdelim(&s);
391 if (!arg || *arg == '\0')
392 fatal("%s line %d: missing time value.",
393 filename, linenum);
394 if ((value = convtime(arg)) == -1)
395 fatal("%s line %d: invalid time value.",
396 filename, linenum);
397 if (*activep && *intptr == -1)
398 *intptr = value;
399 break;
401 case oForwardAgent:
402 intptr = &options->forward_agent;
403 parse_flag:
404 arg = strdelim(&s);
405 if (!arg || *arg == '\0')
406 fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
407 value = 0; /* To avoid compiler warning... */
408 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
409 value = 1;
410 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
411 value = 0;
412 else
413 fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
414 if (*activep && *intptr == -1)
415 *intptr = value;
416 break;
418 case oForwardX11:
419 intptr = &options->forward_x11;
420 goto parse_flag;
422 case oForwardX11Trusted:
423 intptr = &options->forward_x11_trusted;
424 goto parse_flag;
426 case oForwardX11Timeout:
427 intptr = &options->forward_x11_timeout;
428 goto parse_time;
430 case oGatewayPorts:
431 intptr = &options->gateway_ports;
432 goto parse_flag;
434 case oExitOnForwardFailure:
435 intptr = &options->exit_on_forward_failure;
436 goto parse_flag;
438 case oUsePrivilegedPort:
439 intptr = &options->use_privileged_port;
440 goto parse_flag;
442 case oPasswordAuthentication:
443 intptr = &options->password_authentication;
444 goto parse_flag;
446 case oZeroKnowledgePasswordAuthentication:
447 intptr = &options->zero_knowledge_password_authentication;
448 goto parse_flag;
450 case oKbdInteractiveAuthentication:
451 intptr = &options->kbd_interactive_authentication;
452 goto parse_flag;
454 case oKbdInteractiveDevices:
455 charptr = &options->kbd_interactive_devices;
456 goto parse_string;
458 case oPubkeyAuthentication:
459 intptr = &options->pubkey_authentication;
460 goto parse_flag;
462 case oRSAAuthentication:
463 intptr = &options->rsa_authentication;
464 goto parse_flag;
466 case oRhostsRSAAuthentication:
467 intptr = &options->rhosts_rsa_authentication;
468 goto parse_flag;
470 case oHostbasedAuthentication:
471 intptr = &options->hostbased_authentication;
472 goto parse_flag;
474 case oChallengeResponseAuthentication:
475 intptr = &options->challenge_response_authentication;
476 goto parse_flag;
478 case oGssAuthentication:
479 intptr = &options->gss_authentication;
480 goto parse_flag;
482 case oGssDelegateCreds:
483 intptr = &options->gss_deleg_creds;
484 goto parse_flag;
486 case oBatchMode:
487 intptr = &options->batch_mode;
488 goto parse_flag;
490 case oCheckHostIP:
491 intptr = &options->check_host_ip;
492 goto parse_flag;
494 case oVerifyHostKeyDNS:
495 intptr = &options->verify_host_key_dns;
496 goto parse_yesnoask;
498 case oStrictHostKeyChecking:
499 intptr = &options->strict_host_key_checking;
500 parse_yesnoask:
501 arg = strdelim(&s);
502 if (!arg || *arg == '\0')
503 fatal("%.200s line %d: Missing yes/no/ask argument.",
504 filename, linenum);
505 value = 0; /* To avoid compiler warning... */
506 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
507 value = 1;
508 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
509 value = 0;
510 else if (strcmp(arg, "ask") == 0)
511 value = 2;
512 else
513 fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
514 if (*activep && *intptr == -1)
515 *intptr = value;
516 break;
518 case oCompression:
519 intptr = &options->compression;
520 goto parse_flag;
522 case oTCPKeepAlive:
523 intptr = &options->tcp_keep_alive;
524 goto parse_flag;
526 case oNoHostAuthenticationForLocalhost:
527 intptr = &options->no_host_authentication_for_localhost;
528 goto parse_flag;
530 case oNumberOfPasswordPrompts:
531 intptr = &options->number_of_password_prompts;
532 goto parse_int;
534 case oCompressionLevel:
535 intptr = &options->compression_level;
536 goto parse_int;
538 case oRekeyLimit:
539 arg = strdelim(&s);
540 if (!arg || *arg == '\0')
541 fatal("%.200s line %d: Missing argument.", filename, linenum);
542 if (arg[0] < '0' || arg[0] > '9')
543 fatal("%.200s line %d: Bad number.", filename, linenum);
544 orig = val64 = strtoll(arg, &endofnumber, 10);
545 if (arg == endofnumber)
546 fatal("%.200s line %d: Bad number.", filename, linenum);
547 switch (toupper(*endofnumber)) {
548 case '\0':
549 scale = 1;
550 break;
551 case 'K':
552 scale = 1<<10;
553 break;
554 case 'M':
555 scale = 1<<20;
556 break;
557 case 'G':
558 scale = 1<<30;
559 break;
560 default:
561 fatal("%.200s line %d: Invalid RekeyLimit suffix",
562 filename, linenum);
564 val64 *= scale;
565 /* detect integer wrap and too-large limits */
566 if ((val64 / scale) != orig || val64 > UINT_MAX)
567 fatal("%.200s line %d: RekeyLimit too large",
568 filename, linenum);
569 if (val64 < 16)
570 fatal("%.200s line %d: RekeyLimit too small",
571 filename, linenum);
572 if (*activep && options->rekey_limit == -1)
573 options->rekey_limit = (u_int32_t)val64;
574 break;
576 case oIdentityFile:
577 arg = strdelim(&s);
578 if (!arg || *arg == '\0')
579 fatal("%.200s line %d: Missing argument.", filename, linenum);
580 if (*activep) {
581 intptr = &options->num_identity_files;
582 if (*intptr >= SSH_MAX_IDENTITY_FILES)
583 fatal("%.200s line %d: Too many identity files specified (max %d).",
584 filename, linenum, SSH_MAX_IDENTITY_FILES);
585 charptr = &options->identity_files[*intptr];
586 *charptr = xstrdup(arg);
587 *intptr = *intptr + 1;
589 break;
591 case oXAuthLocation:
592 charptr=&options->xauth_location;
593 goto parse_string;
595 case oUser:
596 charptr = &options->user;
597 parse_string:
598 arg = strdelim(&s);
599 if (!arg || *arg == '\0')
600 fatal("%.200s line %d: Missing argument.", filename, linenum);
601 if (*activep && *charptr == NULL)
602 *charptr = xstrdup(arg);
603 break;
605 case oGlobalKnownHostsFile:
606 charptr = &options->system_hostfile;
607 goto parse_string;
609 case oUserKnownHostsFile:
610 charptr = &options->user_hostfile;
611 goto parse_string;
613 case oGlobalKnownHostsFile2:
614 charptr = &options->system_hostfile2;
615 goto parse_string;
617 case oUserKnownHostsFile2:
618 charptr = &options->user_hostfile2;
619 goto parse_string;
621 case oHostName:
622 charptr = &options->hostname;
623 goto parse_string;
625 case oHostKeyAlias:
626 charptr = &options->host_key_alias;
627 goto parse_string;
629 case oPreferredAuthentications:
630 charptr = &options->preferred_authentications;
631 goto parse_string;
633 case oBindAddress:
634 charptr = &options->bind_address;
635 goto parse_string;
637 case oPKCS11Provider:
638 charptr = &options->pkcs11_provider;
639 goto parse_string;
641 case oProxyCommand:
642 charptr = &options->proxy_command;
643 parse_command:
644 if (s == NULL)
645 fatal("%.200s line %d: Missing argument.", filename, linenum);
646 len = strspn(s, WHITESPACE "=");
647 if (*activep && *charptr == NULL)
648 *charptr = xstrdup(s + len);
649 return 0;
651 case oPort:
652 intptr = &options->port;
653 parse_int:
654 arg = strdelim(&s);
655 if (!arg || *arg == '\0')
656 fatal("%.200s line %d: Missing argument.", filename, linenum);
657 if (arg[0] < '0' || arg[0] > '9')
658 fatal("%.200s line %d: Bad number.", filename, linenum);
660 /* Octal, decimal, or hex format? */
661 value = strtol(arg, &endofnumber, 0);
662 if (arg == endofnumber)
663 fatal("%.200s line %d: Bad number.", filename, linenum);
664 if (*activep && *intptr == -1)
665 *intptr = value;
666 break;
668 case oConnectionAttempts:
669 intptr = &options->connection_attempts;
670 goto parse_int;
672 case oCipher:
673 intptr = &options->cipher;
674 arg = strdelim(&s);
675 if (!arg || *arg == '\0')
676 fatal("%.200s line %d: Missing argument.", filename, linenum);
677 value = cipher_number(arg);
678 if (value == -1)
679 fatal("%.200s line %d: Bad cipher '%s'.",
680 filename, linenum, arg ? arg : "<NONE>");
681 if (*activep && *intptr == -1)
682 *intptr = value;
683 break;
685 case oCiphers:
686 arg = strdelim(&s);
687 if (!arg || *arg == '\0')
688 fatal("%.200s line %d: Missing argument.", filename, linenum);
689 if (!ciphers_valid(arg))
690 fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
691 filename, linenum, arg ? arg : "<NONE>");
692 if (*activep && options->ciphers == NULL)
693 options->ciphers = xstrdup(arg);
694 break;
696 case oMacs:
697 arg = strdelim(&s);
698 if (!arg || *arg == '\0')
699 fatal("%.200s line %d: Missing argument.", filename, linenum);
700 if (!mac_valid(arg))
701 fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
702 filename, linenum, arg ? arg : "<NONE>");
703 if (*activep && options->macs == NULL)
704 options->macs = xstrdup(arg);
705 break;
707 case oKexAlgorithms:
708 arg = strdelim(&s);
709 if (!arg || *arg == '\0')
710 fatal("%.200s line %d: Missing argument.",
711 filename, linenum);
712 if (!kex_names_valid(arg))
713 fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
714 filename, linenum, arg ? arg : "<NONE>");
715 if (*activep && options->kex_algorithms == NULL)
716 options->kex_algorithms = xstrdup(arg);
717 break;
719 case oHostKeyAlgorithms:
720 arg = strdelim(&s);
721 if (!arg || *arg == '\0')
722 fatal("%.200s line %d: Missing argument.", filename, linenum);
723 if (!key_names_valid2(arg))
724 fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
725 filename, linenum, arg ? arg : "<NONE>");
726 if (*activep && options->hostkeyalgorithms == NULL)
727 options->hostkeyalgorithms = xstrdup(arg);
728 break;
730 case oProtocol:
731 intptr = &options->protocol;
732 arg = strdelim(&s);
733 if (!arg || *arg == '\0')
734 fatal("%.200s line %d: Missing argument.", filename, linenum);
735 value = proto_spec(arg);
736 if (value == SSH_PROTO_UNKNOWN)
737 fatal("%.200s line %d: Bad protocol spec '%s'.",
738 filename, linenum, arg ? arg : "<NONE>");
739 if (*activep && *intptr == SSH_PROTO_UNKNOWN)
740 *intptr = value;
741 break;
743 case oLogLevel:
744 log_level_ptr = &options->log_level;
745 arg = strdelim(&s);
746 value = log_level_number(arg);
747 if (value == SYSLOG_LEVEL_NOT_SET)
748 fatal("%.200s line %d: unsupported log level '%s'",
749 filename, linenum, arg ? arg : "<NONE>");
750 if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
751 *log_level_ptr = (LogLevel) value;
752 break;
754 case oLocalForward:
755 case oRemoteForward:
756 case oDynamicForward:
757 arg = strdelim(&s);
758 if (arg == NULL || *arg == '\0')
759 fatal("%.200s line %d: Missing port argument.",
760 filename, linenum);
762 if (opcode == oLocalForward ||
763 opcode == oRemoteForward) {
764 arg2 = strdelim(&s);
765 if (arg2 == NULL || *arg2 == '\0')
766 fatal("%.200s line %d: Missing target argument.",
767 filename, linenum);
769 /* construct a string for parse_forward */
770 snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
771 } else if (opcode == oDynamicForward) {
772 strlcpy(fwdarg, arg, sizeof(fwdarg));
775 if (parse_forward(&fwd, fwdarg,
776 opcode == oDynamicForward ? 1 : 0,
777 opcode == oRemoteForward ? 1 : 0) == 0)
778 fatal("%.200s line %d: Bad forwarding specification.",
779 filename, linenum);
781 if (*activep) {
782 if (opcode == oLocalForward ||
783 opcode == oDynamicForward)
784 add_local_forward(options, &fwd);
785 else if (opcode == oRemoteForward)
786 add_remote_forward(options, &fwd);
788 break;
790 case oClearAllForwardings:
791 intptr = &options->clear_forwardings;
792 goto parse_flag;
794 case oHost:
795 *activep = 0;
796 while ((arg = strdelim(&s)) != NULL && *arg != '\0')
797 if (match_pattern(host, arg)) {
798 debug("Applying options for %.100s", arg);
799 *activep = 1;
800 break;
802 /* Avoid garbage check below, as strdelim is done. */
803 return 0;
805 case oEscapeChar:
806 intptr = &options->escape_char;
807 arg = strdelim(&s);
808 if (!arg || *arg == '\0')
809 fatal("%.200s line %d: Missing argument.", filename, linenum);
810 if (arg[0] == '^' && arg[2] == 0 &&
811 (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
812 value = (u_char) arg[1] & 31;
813 else if (strlen(arg) == 1)
814 value = (u_char) arg[0];
815 else if (strcmp(arg, "none") == 0)
816 value = SSH_ESCAPECHAR_NONE;
817 else {
818 fatal("%.200s line %d: Bad escape character.",
819 filename, linenum);
820 /* NOTREACHED */
821 value = 0; /* Avoid compiler warning. */
823 if (*activep && *intptr == -1)
824 *intptr = value;
825 break;
827 case oAddressFamily:
828 arg = strdelim(&s);
829 if (!arg || *arg == '\0')
830 fatal("%s line %d: missing address family.",
831 filename, linenum);
832 intptr = &options->address_family;
833 if (strcasecmp(arg, "inet") == 0)
834 value = AF_INET;
835 else if (strcasecmp(arg, "inet6") == 0)
836 value = AF_INET6;
837 else if (strcasecmp(arg, "any") == 0)
838 value = AF_UNSPEC;
839 else
840 fatal("Unsupported AddressFamily \"%s\"", arg);
841 if (*activep && *intptr == -1)
842 *intptr = value;
843 break;
845 case oEnableSSHKeysign:
846 intptr = &options->enable_ssh_keysign;
847 goto parse_flag;
849 case oIdentitiesOnly:
850 intptr = &options->identities_only;
851 goto parse_flag;
853 case oServerAliveInterval:
854 intptr = &options->server_alive_interval;
855 goto parse_time;
857 case oServerAliveCountMax:
858 intptr = &options->server_alive_count_max;
859 goto parse_int;
861 case oSendEnv:
862 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
863 if (strchr(arg, '=') != NULL)
864 fatal("%s line %d: Invalid environment name.",
865 filename, linenum);
866 if (!*activep)
867 continue;
868 if (options->num_send_env >= MAX_SEND_ENV)
869 fatal("%s line %d: too many send env.",
870 filename, linenum);
871 options->send_env[options->num_send_env++] =
872 xstrdup(arg);
874 break;
876 case oControlPath:
877 charptr = &options->control_path;
878 goto parse_string;
880 case oControlMaster:
881 intptr = &options->control_master;
882 arg = strdelim(&s);
883 if (!arg || *arg == '\0')
884 fatal("%.200s line %d: Missing ControlMaster argument.",
885 filename, linenum);
886 value = 0; /* To avoid compiler warning... */
887 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
888 value = SSHCTL_MASTER_YES;
889 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
890 value = SSHCTL_MASTER_NO;
891 else if (strcmp(arg, "auto") == 0)
892 value = SSHCTL_MASTER_AUTO;
893 else if (strcmp(arg, "ask") == 0)
894 value = SSHCTL_MASTER_ASK;
895 else if (strcmp(arg, "autoask") == 0)
896 value = SSHCTL_MASTER_AUTO_ASK;
897 else
898 fatal("%.200s line %d: Bad ControlMaster argument.",
899 filename, linenum);
900 if (*activep && *intptr == -1)
901 *intptr = value;
902 break;
904 case oControlPersist:
905 /* no/false/yes/true, or a time spec */
906 intptr = &options->control_persist;
907 arg = strdelim(&s);
908 if (!arg || *arg == '\0')
909 fatal("%.200s line %d: Missing ControlPersist"
910 " argument.", filename, linenum);
911 value = 0;
912 value2 = 0; /* timeout */
913 if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
914 value = 0;
915 else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
916 value = 1;
917 else if ((value2 = convtime(arg)) >= 0)
918 value = 1;
919 else
920 fatal("%.200s line %d: Bad ControlPersist argument.",
921 filename, linenum);
922 if (*activep && *intptr == -1) {
923 *intptr = value;
924 options->control_persist_timeout = value2;
926 break;
928 case oHashKnownHosts:
929 intptr = &options->hash_known_hosts;
930 goto parse_flag;
932 case oTunnel:
933 intptr = &options->tun_open;
934 arg = strdelim(&s);
935 if (!arg || *arg == '\0')
936 fatal("%s line %d: Missing yes/point-to-point/"
937 "ethernet/no argument.", filename, linenum);
938 value = 0; /* silence compiler */
939 if (strcasecmp(arg, "ethernet") == 0)
940 value = SSH_TUNMODE_ETHERNET;
941 else if (strcasecmp(arg, "point-to-point") == 0)
942 value = SSH_TUNMODE_POINTOPOINT;
943 else if (strcasecmp(arg, "yes") == 0)
944 value = SSH_TUNMODE_DEFAULT;
945 else if (strcasecmp(arg, "no") == 0)
946 value = SSH_TUNMODE_NO;
947 else
948 fatal("%s line %d: Bad yes/point-to-point/ethernet/"
949 "no argument: %s", filename, linenum, arg);
950 if (*activep)
951 *intptr = value;
952 break;
954 case oTunnelDevice:
955 arg = strdelim(&s);
956 if (!arg || *arg == '\0')
957 fatal("%.200s line %d: Missing argument.", filename, linenum);
958 value = a2tun(arg, &value2);
959 if (value == SSH_TUNID_ERR)
960 fatal("%.200s line %d: Bad tun device.", filename, linenum);
961 if (*activep) {
962 options->tun_local = value;
963 options->tun_remote = value2;
965 break;
967 case oLocalCommand:
968 charptr = &options->local_command;
969 goto parse_command;
971 case oPermitLocalCommand:
972 intptr = &options->permit_local_command;
973 goto parse_flag;
975 case oVisualHostKey:
976 intptr = &options->visual_host_key;
977 goto parse_flag;
979 case oIPQoS:
980 arg = strdelim(&s);
981 if ((value = parse_ipqos(arg)) == -1)
982 fatal("%s line %d: Bad IPQoS value: %s",
983 filename, linenum, arg);
984 arg = strdelim(&s);
985 if (arg == NULL)
986 value2 = value;
987 else if ((value2 = parse_ipqos(arg)) == -1)
988 fatal("%s line %d: Bad IPQoS value: %s",
989 filename, linenum, arg);
990 if (*activep) {
991 options->ip_qos_interactive = value;
992 options->ip_qos_bulk = value2;
994 break;
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->forward_x11_timeout = -1;
1087 options->exit_on_forward_failure = -1;
1088 options->xauth_location = NULL;
1089 options->gateway_ports = -1;
1090 options->use_privileged_port = -1;
1091 options->rsa_authentication = -1;
1092 options->pubkey_authentication = -1;
1093 options->challenge_response_authentication = -1;
1094 options->gss_authentication = -1;
1095 options->gss_deleg_creds = -1;
1096 options->password_authentication = -1;
1097 options->kbd_interactive_authentication = -1;
1098 options->kbd_interactive_devices = NULL;
1099 options->rhosts_rsa_authentication = -1;
1100 options->hostbased_authentication = -1;
1101 options->batch_mode = -1;
1102 options->check_host_ip = -1;
1103 options->strict_host_key_checking = -1;
1104 options->compression = -1;
1105 options->tcp_keep_alive = -1;
1106 options->compression_level = -1;
1107 options->port = -1;
1108 options->address_family = -1;
1109 options->connection_attempts = -1;
1110 options->connection_timeout = -1;
1111 options->number_of_password_prompts = -1;
1112 options->cipher = -1;
1113 options->ciphers = NULL;
1114 options->macs = NULL;
1115 options->kex_algorithms = NULL;
1116 options->hostkeyalgorithms = NULL;
1117 options->protocol = SSH_PROTO_UNKNOWN;
1118 options->num_identity_files = 0;
1119 options->hostname = NULL;
1120 options->host_key_alias = NULL;
1121 options->proxy_command = NULL;
1122 options->user = NULL;
1123 options->escape_char = -1;
1124 options->system_hostfile = NULL;
1125 options->user_hostfile = NULL;
1126 options->system_hostfile2 = NULL;
1127 options->user_hostfile2 = NULL;
1128 options->local_forwards = NULL;
1129 options->num_local_forwards = 0;
1130 options->remote_forwards = NULL;
1131 options->num_remote_forwards = 0;
1132 options->clear_forwardings = -1;
1133 options->log_level = SYSLOG_LEVEL_NOT_SET;
1134 options->preferred_authentications = NULL;
1135 options->bind_address = NULL;
1136 options->pkcs11_provider = NULL;
1137 options->enable_ssh_keysign = - 1;
1138 options->no_host_authentication_for_localhost = - 1;
1139 options->identities_only = - 1;
1140 options->rekey_limit = - 1;
1141 options->verify_host_key_dns = -1;
1142 options->server_alive_interval = -1;
1143 options->server_alive_count_max = -1;
1144 options->num_send_env = 0;
1145 options->control_path = NULL;
1146 options->control_master = -1;
1147 options->control_persist = -1;
1148 options->control_persist_timeout = 0;
1149 options->hash_known_hosts = -1;
1150 options->tun_open = -1;
1151 options->tun_local = -1;
1152 options->tun_remote = -1;
1153 options->local_command = NULL;
1154 options->permit_local_command = -1;
1155 options->use_roaming = -1;
1156 options->visual_host_key = -1;
1157 options->zero_knowledge_password_authentication = -1;
1158 options->ip_qos_interactive = -1;
1159 options->ip_qos_bulk = -1;
1163 * Called after processing other sources of option data, this fills those
1164 * options for which no value has been specified with their default values.
1167 void
1168 fill_default_options(Options * options)
1170 int len;
1172 if (options->forward_agent == -1)
1173 options->forward_agent = 0;
1174 if (options->forward_x11 == -1)
1175 options->forward_x11 = 0;
1176 if (options->forward_x11_trusted == -1)
1177 options->forward_x11_trusted = 0;
1178 if (options->forward_x11_timeout == -1)
1179 options->forward_x11_timeout = 1200;
1180 if (options->exit_on_forward_failure == -1)
1181 options->exit_on_forward_failure = 0;
1182 if (options->xauth_location == NULL)
1183 options->xauth_location = _PATH_XAUTH;
1184 if (options->gateway_ports == -1)
1185 options->gateway_ports = 0;
1186 if (options->use_privileged_port == -1)
1187 options->use_privileged_port = 0;
1188 if (options->rsa_authentication == -1)
1189 options->rsa_authentication = 1;
1190 if (options->pubkey_authentication == -1)
1191 options->pubkey_authentication = 1;
1192 if (options->challenge_response_authentication == -1)
1193 options->challenge_response_authentication = 1;
1194 if (options->gss_authentication == -1)
1195 options->gss_authentication = 0;
1196 if (options->gss_deleg_creds == -1)
1197 options->gss_deleg_creds = 0;
1198 if (options->password_authentication == -1)
1199 options->password_authentication = 1;
1200 if (options->kbd_interactive_authentication == -1)
1201 options->kbd_interactive_authentication = 1;
1202 if (options->rhosts_rsa_authentication == -1)
1203 options->rhosts_rsa_authentication = 0;
1204 if (options->hostbased_authentication == -1)
1205 options->hostbased_authentication = 0;
1206 if (options->batch_mode == -1)
1207 options->batch_mode = 0;
1208 if (options->check_host_ip == -1)
1209 options->check_host_ip = 1;
1210 if (options->strict_host_key_checking == -1)
1211 options->strict_host_key_checking = 2; /* 2 is default */
1212 if (options->compression == -1)
1213 options->compression = 0;
1214 if (options->tcp_keep_alive == -1)
1215 options->tcp_keep_alive = 1;
1216 if (options->compression_level == -1)
1217 options->compression_level = 6;
1218 if (options->port == -1)
1219 options->port = 0; /* Filled in ssh_connect. */
1220 if (options->address_family == -1)
1221 options->address_family = AF_UNSPEC;
1222 if (options->connection_attempts == -1)
1223 options->connection_attempts = 1;
1224 if (options->number_of_password_prompts == -1)
1225 options->number_of_password_prompts = 3;
1226 /* Selected in ssh_login(). */
1227 if (options->cipher == -1)
1228 options->cipher = SSH_CIPHER_NOT_SET;
1229 /* options->ciphers, default set in myproposals.h */
1230 /* options->macs, default set in myproposals.h */
1231 /* options->kex_algorithms, default set in myproposals.h */
1232 /* options->hostkeyalgorithms, default set in myproposals.h */
1233 if (options->protocol == SSH_PROTO_UNKNOWN)
1234 options->protocol = SSH_PROTO_2;
1235 if (options->num_identity_files == 0) {
1236 if (options->protocol & SSH_PROTO_1) {
1237 len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
1238 options->identity_files[options->num_identity_files] =
1239 xmalloc(len);
1240 snprintf(options->identity_files[options->num_identity_files++],
1241 len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
1243 if (options->protocol & SSH_PROTO_2) {
1244 len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
1245 options->identity_files[options->num_identity_files] =
1246 xmalloc(len);
1247 snprintf(options->identity_files[options->num_identity_files++],
1248 len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
1250 len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
1251 options->identity_files[options->num_identity_files] =
1252 xmalloc(len);
1253 snprintf(options->identity_files[options->num_identity_files++],
1254 len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
1255 #ifdef OPENSSL_HAS_ECC
1256 len = 2 + strlen(_PATH_SSH_CLIENT_ID_ECDSA) + 1;
1257 options->identity_files[options->num_identity_files] =
1258 xmalloc(len);
1259 snprintf(options->identity_files[options->num_identity_files++],
1260 len, "~/%.100s", _PATH_SSH_CLIENT_ID_ECDSA);
1261 #endif
1264 if (options->escape_char == -1)
1265 options->escape_char = '~';
1266 if (options->system_hostfile == NULL)
1267 options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
1268 if (options->user_hostfile == NULL)
1269 options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
1270 if (options->system_hostfile2 == NULL)
1271 options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
1272 if (options->user_hostfile2 == NULL)
1273 options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
1274 if (options->log_level == SYSLOG_LEVEL_NOT_SET)
1275 options->log_level = SYSLOG_LEVEL_INFO;
1276 if (options->clear_forwardings == 1)
1277 clear_forwardings(options);
1278 if (options->no_host_authentication_for_localhost == - 1)
1279 options->no_host_authentication_for_localhost = 0;
1280 if (options->identities_only == -1)
1281 options->identities_only = 0;
1282 if (options->enable_ssh_keysign == -1)
1283 options->enable_ssh_keysign = 0;
1284 if (options->rekey_limit == -1)
1285 options->rekey_limit = 0;
1286 if (options->verify_host_key_dns == -1)
1287 options->verify_host_key_dns = 0;
1288 if (options->server_alive_interval == -1)
1289 options->server_alive_interval = 0;
1290 if (options->server_alive_count_max == -1)
1291 options->server_alive_count_max = 3;
1292 if (options->control_master == -1)
1293 options->control_master = 0;
1294 if (options->control_persist == -1) {
1295 options->control_persist = 0;
1296 options->control_persist_timeout = 0;
1298 if (options->hash_known_hosts == -1)
1299 options->hash_known_hosts = 0;
1300 if (options->tun_open == -1)
1301 options->tun_open = SSH_TUNMODE_NO;
1302 if (options->tun_local == -1)
1303 options->tun_local = SSH_TUNID_ANY;
1304 if (options->tun_remote == -1)
1305 options->tun_remote = SSH_TUNID_ANY;
1306 if (options->permit_local_command == -1)
1307 options->permit_local_command = 0;
1308 if (options->use_roaming == -1)
1309 options->use_roaming = 1;
1310 if (options->visual_host_key == -1)
1311 options->visual_host_key = 0;
1312 if (options->zero_knowledge_password_authentication == -1)
1313 options->zero_knowledge_password_authentication = 0;
1314 if (options->ip_qos_interactive == -1)
1315 options->ip_qos_interactive = IPTOS_LOWDELAY;
1316 if (options->ip_qos_bulk == -1)
1317 options->ip_qos_bulk = IPTOS_THROUGHPUT;
1318 /* options->local_command should not be set by default */
1319 /* options->proxy_command should not be set by default */
1320 /* options->user will be set in the main program if appropriate */
1321 /* options->hostname will be set in the main program if appropriate */
1322 /* options->host_key_alias should not be set by default */
1323 /* options->preferred_authentications will be set in ssh */
1327 * parse_forward
1328 * parses a string containing a port forwarding specification of the form:
1329 * dynamicfwd == 0
1330 * [listenhost:]listenport:connecthost:connectport
1331 * dynamicfwd == 1
1332 * [listenhost:]listenport
1333 * returns number of arguments parsed or zero on error
1336 parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
1338 int i;
1339 char *p, *cp, *fwdarg[4];
1341 memset(fwd, '\0', sizeof(*fwd));
1343 cp = p = xstrdup(fwdspec);
1345 /* skip leading spaces */
1346 while (isspace(*cp))
1347 cp++;
1349 for (i = 0; i < 4; ++i)
1350 if ((fwdarg[i] = hpdelim(&cp)) == NULL)
1351 break;
1353 /* Check for trailing garbage */
1354 if (cp != NULL)
1355 i = 0; /* failure */
1357 switch (i) {
1358 case 1:
1359 fwd->listen_host = NULL;
1360 fwd->listen_port = a2port(fwdarg[0]);
1361 fwd->connect_host = xstrdup("socks");
1362 break;
1364 case 2:
1365 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1366 fwd->listen_port = a2port(fwdarg[1]);
1367 fwd->connect_host = xstrdup("socks");
1368 break;
1370 case 3:
1371 fwd->listen_host = NULL;
1372 fwd->listen_port = a2port(fwdarg[0]);
1373 fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
1374 fwd->connect_port = a2port(fwdarg[2]);
1375 break;
1377 case 4:
1378 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1379 fwd->listen_port = a2port(fwdarg[1]);
1380 fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
1381 fwd->connect_port = a2port(fwdarg[3]);
1382 break;
1383 default:
1384 i = 0; /* failure */
1387 xfree(p);
1389 if (dynamicfwd) {
1390 if (!(i == 1 || i == 2))
1391 goto fail_free;
1392 } else {
1393 if (!(i == 3 || i == 4))
1394 goto fail_free;
1395 if (fwd->connect_port <= 0)
1396 goto fail_free;
1399 if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0))
1400 goto fail_free;
1402 if (fwd->connect_host != NULL &&
1403 strlen(fwd->connect_host) >= NI_MAXHOST)
1404 goto fail_free;
1405 if (fwd->listen_host != NULL &&
1406 strlen(fwd->listen_host) >= NI_MAXHOST)
1407 goto fail_free;
1410 return (i);
1412 fail_free:
1413 if (fwd->connect_host != NULL) {
1414 xfree(fwd->connect_host);
1415 fwd->connect_host = NULL;
1417 if (fwd->listen_host != NULL) {
1418 xfree(fwd->listen_host);
1419 fwd->listen_host = NULL;
1421 return (0);