You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
566 lines
14 KiB
566 lines
14 KiB
/*
|
|
* Copyright (c) 1987, 1993, 1994
|
|
* The Regents of the University of California. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the University of
|
|
* California, Berkeley and its contributors.
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include "ftmacros.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <pcap.h> // for PCAP_ERRBUF_SIZE
|
|
|
|
#include "portability.h"
|
|
#include "rpcapd.h"
|
|
#include "config_params.h" // configuration file parameters
|
|
#include "fileconf.h"
|
|
#include "rpcap-protocol.h"
|
|
#include "log.h"
|
|
|
|
//
|
|
// Parameter names.
|
|
//
|
|
#define PARAM_ACTIVECLIENT "ActiveClient"
|
|
#define PARAM_PASSIVECLIENT "PassiveClient"
|
|
#define PARAM_NULLAUTHPERMIT "NullAuthPermit"
|
|
|
|
static char *skipws(char *ptr);
|
|
|
|
/*
|
|
* Locale-independent version checks for alphabetical and alphanumerical
|
|
* characters that also can handle being handed a char value that might
|
|
* be negative.
|
|
*/
|
|
#define FILECONF_ISALPHA(c) \
|
|
(((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
|
|
#define FILECONF_ISALNUM(c) \
|
|
(FILECONF_ISALPHA(c) || ((c) >= '0' && (c) <= '9'))
|
|
|
|
void fileconf_read(void)
|
|
{
|
|
FILE *fp;
|
|
unsigned int num_active_clients;
|
|
|
|
if ((fp = fopen(loadfile, "r")) != NULL)
|
|
{
|
|
char line[MAX_LINE + 1];
|
|
unsigned int lineno;
|
|
|
|
hostlist[0] = 0;
|
|
num_active_clients = 0;
|
|
lineno = 0;
|
|
|
|
while (fgets(line, MAX_LINE, fp) != NULL)
|
|
{
|
|
size_t linelen;
|
|
char *ptr;
|
|
char *param;
|
|
size_t result;
|
|
size_t toklen;
|
|
|
|
lineno++;
|
|
|
|
linelen = strlen(line);
|
|
if (line[linelen - 1] != '\n')
|
|
{
|
|
int c;
|
|
|
|
//
|
|
// Either the line doesn't fit in
|
|
// the buffer, or we got an EOF
|
|
// before the EOL. Assume it's the
|
|
// former.
|
|
//
|
|
rpcapd_log(LOGPRIO_ERROR,
|
|
"%s, line %u is longer than %u characters",
|
|
loadfile, lineno, MAX_LINE);
|
|
|
|
//
|
|
// Eat characters until we get an NL.
|
|
//
|
|
while ((c = getc(fp)) != '\n')
|
|
{
|
|
if (c == EOF)
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Try the next line.
|
|
//
|
|
continue;
|
|
}
|
|
ptr = line;
|
|
|
|
//
|
|
// Skip leading white space, if any.
|
|
//
|
|
ptr = skipws(ptr);
|
|
if (ptr == NULL)
|
|
{
|
|
// Blank line.
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Is the next character a "#"? If so, this
|
|
// line is a comment; skip to the next line.
|
|
//
|
|
if (*ptr == '#')
|
|
continue;
|
|
|
|
//
|
|
// Is the next character alphabetic? If not,
|
|
// this isn't a valid parameter name.
|
|
//
|
|
if (FILECONF_ISALPHA(*ptr))
|
|
{
|
|
rpcapd_log(LOGPRIO_ERROR,
|
|
"%s, line %u doesn't have a valid parameter name",
|
|
loadfile, lineno);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Grab the first token, which is made of
|
|
// alphanumerics, underscores, and hyphens.
|
|
// That's the name of the parameter being set.
|
|
//
|
|
param = ptr;
|
|
while (FILECONF_ISALNUM(*ptr) || *ptr == '-' || *ptr == '_')
|
|
ptr++;
|
|
|
|
//
|
|
// Skip over white space, if any.
|
|
//
|
|
ptr = skipws(ptr);
|
|
if (ptr == NULL || *ptr != '=')
|
|
{
|
|
//
|
|
// We hit the end of the line before
|
|
// finding a non-white space character,
|
|
// or we found one but it's not an "=".
|
|
// That means there's no "=", so this
|
|
// line is invalid. Complain and skip
|
|
// this line.
|
|
//
|
|
rpcapd_log(LOGPRIO_ERROR,
|
|
"%s, line %u has a parameter but no =",
|
|
loadfile, lineno);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// We found the '='; set it to '\0', and skip
|
|
// past it.
|
|
//
|
|
*ptr++ = '\0';
|
|
|
|
//
|
|
// Skip past any white space after the "=".
|
|
//
|
|
ptr = skipws(ptr);
|
|
if (ptr == NULL)
|
|
{
|
|
//
|
|
// The value is empty.
|
|
//
|
|
rpcapd_log(LOGPRIO_ERROR,
|
|
"%s, line %u has a parameter but no value",
|
|
loadfile, lineno);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// OK, what parameter is this?
|
|
//
|
|
if (strcmp(param, PARAM_ACTIVECLIENT) == 0) {
|
|
//
|
|
// Add this to the list of active clients.
|
|
//
|
|
char *address, *port;
|
|
|
|
//
|
|
// We can't have more than MAX_ACTIVE_LIST
|
|
// active clients.
|
|
//
|
|
if (num_active_clients >= MAX_ACTIVE_LIST)
|
|
{
|
|
//
|
|
// Too many entries for the active
|
|
// client list. Complain and
|
|
// ignore it.
|
|
//
|
|
rpcapd_log(LOGPRIO_ERROR,
|
|
"%s, line %u has an %s parameter, but we already have %u active clients",
|
|
loadfile, lineno, PARAM_ACTIVECLIENT,
|
|
MAX_ACTIVE_LIST);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Get the address.
|
|
// It's terminated by a host list separator
|
|
// *or* a #; there *shouldn't* be a #, as
|
|
// that starts a comment, and that would
|
|
// mean that we have no port.
|
|
//
|
|
address = ptr;
|
|
toklen = strcspn(ptr, RPCAP_HOSTLIST_SEP "#");
|
|
ptr += toklen; // skip to the terminator
|
|
if (toklen == 0)
|
|
{
|
|
if (*ptr == ' ' || *ptr == '\t' ||
|
|
*ptr == '\r' || *ptr == '\n' ||
|
|
*ptr == '#' || *ptr == '\0')
|
|
{
|
|
//
|
|
// The first character it saw
|
|
// was a whitespace character
|
|
// or a comment character,
|
|
// or we ran out of characters.
|
|
// This means that there's
|
|
// no value.
|
|
//
|
|
rpcapd_log(LOGPRIO_ERROR,
|
|
"%s, line %u has a parameter but no value",
|
|
loadfile, lineno);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This means that the first
|
|
// character it saw was a
|
|
// separator. This means that
|
|
// there's no address in the
|
|
// value, just a port.
|
|
//
|
|
rpcapd_log(LOGPRIO_ERROR,
|
|
"%s, line %u has an %s parameter with a value containing no address",
|
|
loadfile, lineno, PARAM_ACTIVECLIENT);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Null-terminate the address, and skip past
|
|
// it.
|
|
//
|
|
*ptr++ = '\0';
|
|
|
|
//
|
|
// Skip any white space following the
|
|
// separating character.
|
|
//
|
|
ptr = skipws(ptr);
|
|
if (ptr == NULL)
|
|
{
|
|
//
|
|
// The value is empty, so there's
|
|
// no port in the value.
|
|
//
|
|
rpcapd_log(LOGPRIO_ERROR,
|
|
"%s, line %u has an %s parameter with a value containing no port",
|
|
loadfile, lineno, PARAM_ACTIVECLIENT);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Get the port.
|
|
// We look for a white space character
|
|
// or a # as a terminator; the # introduces
|
|
// a comment that runs to the end of the
|
|
// line.
|
|
//
|
|
port = ptr;
|
|
toklen = strcspn(ptr, " \t#\r\n");
|
|
ptr += toklen;
|
|
if (toklen == 0)
|
|
{
|
|
//
|
|
// The value is empty, so there's
|
|
// no port in the value.
|
|
//
|
|
rpcapd_log(LOGPRIO_ERROR,
|
|
"%s, line %u has an %s parameter with a value containing no port",
|
|
loadfile, lineno, PARAM_ACTIVECLIENT);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Null-terminate the port, and skip past
|
|
// it.
|
|
//
|
|
*ptr++ = '\0';
|
|
result = pcap_strlcpy(activelist[num_active_clients].address, address, sizeof(activelist[num_active_clients].address));
|
|
if (result >= sizeof(activelist[num_active_clients].address))
|
|
{
|
|
//
|
|
// It didn't fit.
|
|
//
|
|
rpcapd_log(LOGPRIO_ERROR,
|
|
"%s, line %u has an %s parameter with an address with more than %u characters",
|
|
loadfile, lineno, PARAM_ACTIVECLIENT,
|
|
(unsigned int)(sizeof(activelist[num_active_clients].address) - 1));
|
|
continue;
|
|
}
|
|
if (strcmp(port, "DEFAULT") == 0) // the user choose a custom port
|
|
result = pcap_strlcpy(activelist[num_active_clients].port, RPCAP_DEFAULT_NETPORT_ACTIVE, sizeof(activelist[num_active_clients].port));
|
|
else
|
|
result = pcap_strlcpy(activelist[num_active_clients].port, port, sizeof(activelist[num_active_clients].port));
|
|
if (result >= sizeof(activelist[num_active_clients].address))
|
|
{
|
|
//
|
|
// It didn't fit.
|
|
//
|
|
rpcapd_log(LOGPRIO_ERROR,
|
|
"%s, line %u has an %s parameter with an port with more than %u characters",
|
|
loadfile, lineno, PARAM_ACTIVECLIENT,
|
|
(unsigned int)(sizeof(activelist[num_active_clients].port) - 1));
|
|
continue;
|
|
}
|
|
|
|
num_active_clients++;
|
|
}
|
|
else if (strcmp(param, PARAM_PASSIVECLIENT) == 0)
|
|
{
|
|
char *eos;
|
|
char *host;
|
|
|
|
//
|
|
// Get the host.
|
|
// We look for a white space character
|
|
// or a # as a terminator; the # introduces
|
|
// a comment that runs to the end of the
|
|
// line.
|
|
//
|
|
host = ptr;
|
|
toklen = strcspn(ptr, " \t#\r\n");
|
|
if (toklen == 0)
|
|
{
|
|
//
|
|
// The first character it saw
|
|
// was a whitespace character
|
|
// or a comment character.
|
|
// This means that there's
|
|
// no value.
|
|
//
|
|
rpcapd_log(LOGPRIO_ERROR,
|
|
"%s, line %u has a parameter but no value",
|
|
loadfile, lineno);
|
|
continue;
|
|
}
|
|
ptr += toklen;
|
|
*ptr++ = '\0';
|
|
|
|
//
|
|
// Append this to the host list.
|
|
// Save the curren end-of-string for the
|
|
// host list, in case the new host doesn't
|
|
// fit, so that we can discard the partially-
|
|
// copied host name.
|
|
//
|
|
eos = hostlist + strlen(hostlist);
|
|
if (eos != hostlist)
|
|
{
|
|
//
|
|
// The list is not empty, so prepend
|
|
// a comma before adding this host.
|
|
//
|
|
result = pcap_strlcat(hostlist, ",", sizeof(hostlist));
|
|
if (result >= sizeof(hostlist))
|
|
{
|
|
//
|
|
// It didn't fit. Discard
|
|
// the comma (which wasn't
|
|
// added, but...), complain,
|
|
// and ignore this line.
|
|
//
|
|
*eos = '\0';
|
|
rpcapd_log(LOGPRIO_ERROR,
|
|
"%s, line %u has a %s parameter with a host name that doesn't fit",
|
|
loadfile, lineno, PARAM_PASSIVECLIENT);
|
|
continue;
|
|
}
|
|
}
|
|
result = pcap_strlcat(hostlist, host, sizeof(hostlist));
|
|
if (result >= sizeof(hostlist))
|
|
{
|
|
//
|
|
// It didn't fit. Discard the comma,
|
|
// complain, and ignore this line.
|
|
//
|
|
*eos = '\0';
|
|
rpcapd_log(LOGPRIO_ERROR,
|
|
"%s, line %u has a %s parameter with a host name that doesn't fit",
|
|
loadfile, lineno, PARAM_PASSIVECLIENT);
|
|
continue;
|
|
}
|
|
}
|
|
else if (strcmp(param, PARAM_NULLAUTHPERMIT) == 0)
|
|
{
|
|
char *setting;
|
|
|
|
//
|
|
// Get the setting.
|
|
// We look for a white space character
|
|
// or a # as a terminator; the # introduces
|
|
// a comment that runs to the end of the
|
|
// line.
|
|
//
|
|
setting = ptr;
|
|
toklen = strcspn(ptr, " \t#\r\n");
|
|
ptr += toklen;
|
|
if (toklen == 0)
|
|
{
|
|
//
|
|
// The first character it saw
|
|
// was a whitespace character
|
|
// or a comment character.
|
|
// This means that there's
|
|
// no value.
|
|
//
|
|
rpcapd_log(LOGPRIO_ERROR,
|
|
"%s, line %u has a parameter but no value",
|
|
loadfile, lineno);
|
|
continue;
|
|
}
|
|
*ptr++ = '\0';
|
|
|
|
//
|
|
// XXX - should we complain if it's
|
|
// neither "yes" nor "no"?
|
|
//
|
|
if (strcmp(setting, "YES") == 0)
|
|
nullAuthAllowed = 1;
|
|
else
|
|
nullAuthAllowed = 0;
|
|
}
|
|
else
|
|
{
|
|
rpcapd_log(LOGPRIO_ERROR,
|
|
"%s, line %u has an unknown parameter %s",
|
|
loadfile, lineno, param);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
done:
|
|
// clear the remaining fields of the active list
|
|
for (int i = num_active_clients; i < MAX_ACTIVE_LIST; i++)
|
|
{
|
|
activelist[i].address[0] = 0;
|
|
activelist[i].port[0] = 0;
|
|
num_active_clients++;
|
|
}
|
|
|
|
rpcapd_log(LOGPRIO_DEBUG, "New passive host list: %s", hostlist);
|
|
fclose(fp);
|
|
}
|
|
}
|
|
|
|
int fileconf_save(const char *savefile)
|
|
{
|
|
FILE *fp;
|
|
|
|
if ((fp = fopen(savefile, "w")) != NULL)
|
|
{
|
|
char *token; /*, *port;*/ // temp, needed to separate items into the hostlist
|
|
char temphostlist[MAX_HOST_LIST + 1];
|
|
int i = 0;
|
|
char *lasts;
|
|
|
|
fprintf(fp, "# Configuration file help.\n\n");
|
|
|
|
// Save list of clients which are allowed to connect to us in passive mode
|
|
fprintf(fp, "# Hosts which are allowed to connect to this server (passive mode)\n");
|
|
fprintf(fp, "# Format: PassiveClient = <name or address>\n\n");
|
|
|
|
pcap_strlcpy(temphostlist, hostlist, sizeof (temphostlist));
|
|
|
|
token = pcap_strtok_r(temphostlist, RPCAP_HOSTLIST_SEP, &lasts);
|
|
while(token != NULL)
|
|
{
|
|
fprintf(fp, "%s = %s\n", PARAM_PASSIVECLIENT, token);
|
|
token = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
|
|
}
|
|
|
|
|
|
// Save list of clients which are allowed to connect to us in active mode
|
|
fprintf(fp, "\n\n");
|
|
fprintf(fp, "# Hosts to which this server is trying to connect to (active mode)\n");
|
|
fprintf(fp, "# Format: ActiveClient = <name or address>, <port | DEFAULT>\n\n");
|
|
|
|
|
|
while ((i < MAX_ACTIVE_LIST) && (activelist[i].address[0] != 0))
|
|
{
|
|
fprintf(fp, "%s = %s, %s\n", PARAM_ACTIVECLIENT,
|
|
activelist[i].address, activelist[i].port);
|
|
i++;
|
|
}
|
|
|
|
// Save if we want to permit NULL authentication
|
|
fprintf(fp, "\n\n");
|
|
fprintf(fp, "# Permit NULL authentication: YES or NO\n\n");
|
|
|
|
fprintf(fp, "%s = %s\n", PARAM_NULLAUTHPERMIT,
|
|
nullAuthAllowed ? "YES" : "NO");
|
|
|
|
fclose(fp);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Skip over white space.
|
|
// If we hit a CR or LF, return NULL, otherwise return a pointer to
|
|
// the first non-white space character. Replace white space characters
|
|
// other than CR or LF with '\0', so that, if we're skipping white space
|
|
// after a token, the token is null-terminated.
|
|
//
|
|
static char *skipws(char *ptr)
|
|
{
|
|
while (*ptr == ' ' || *ptr == '\t' || *ptr == '\r' || *ptr == '\n') {
|
|
if (*ptr == '\r' || *ptr == '\n')
|
|
return NULL;
|
|
*ptr++ = '\0';
|
|
}
|
|
return ptr;
|
|
}
|