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