libpcap  1.10.1
About: libpcap is a packet filter library used by tools like tcpdump.
  Fossies Dox: libpcap-1.10.1.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

fileconf.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 1987, 1993, 1994
3  * The Regents of the University of California. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  * must display the following acknowledgement:
15  * This product includes software developed by the University of
16  * California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  * may be used to endorse or promote products derived from this software
19  * without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37 
38 #include "ftmacros.h"
39 
40 #include <stdio.h>
41 #include <string.h>
42 #include <signal.h>
43 #include <pcap.h> // for PCAP_ERRBUF_SIZE
44 
45 #include "portability.h"
46 #include "rpcapd.h"
47 #include "config_params.h" // configuration file parameters
48 #include "fileconf.h"
49 #include "rpcap-protocol.h"
50 #include "log.h"
51 
52 //
53 // Parameter names.
54 //
55 #define PARAM_ACTIVECLIENT "ActiveClient"
56 #define PARAM_PASSIVECLIENT "PassiveClient"
57 #define PARAM_NULLAUTHPERMIT "NullAuthPermit"
58 
59 static char *skipws(char *ptr);
60 
61 /*
62  * Locale-independent version checks for alphabetical and alphanumerical
63  * characters that also can handle being handed a char value that might
64  * be negative.
65  */
66 #define FILECONF_ISALPHA(c) \
67  (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
68 #define FILECONF_ISALNUM(c) \
69  (FILECONF_ISALPHA(c) || ((c) >= '0' && (c) <= '9'))
70 
71 void fileconf_read(void)
72 {
73  FILE *fp;
74  unsigned int num_active_clients;
75 
76  if ((fp = fopen(loadfile, "r")) != NULL)
77  {
78  char line[MAX_LINE + 1];
79  unsigned int lineno;
80 
81  hostlist[0] = 0;
82  num_active_clients = 0;
83  lineno = 0;
84 
85  while (fgets(line, MAX_LINE, fp) != NULL)
86  {
87  size_t linelen;
88  char *ptr;
89  char *param;
90  size_t result;
91  size_t toklen;
92 
93  lineno++;
94 
95  linelen = strlen(line);
96  if (line[linelen - 1] != '\n')
97  {
98  int c;
99 
100  //
101  // Either the line doesn't fit in
102  // the buffer, or we got an EOF
103  // before the EOL. Assume it's the
104  // former.
105  //
107  "%s, line %u is longer than %u characters",
108  loadfile, lineno, MAX_LINE);
109 
110  //
111  // Eat characters until we get an NL.
112  //
113  while ((c = getc(fp)) != '\n')
114  {
115  if (c == EOF)
116  goto done;
117  }
118 
119  //
120  // Try the next line.
121  //
122  continue;
123  }
124  ptr = line;
125 
126  //
127  // Skip leading white space, if any.
128  //
129  ptr = skipws(ptr);
130  if (ptr == NULL)
131  {
132  // Blank line.
133  continue;
134  }
135 
136  //
137  // Is the next character a "#"? If so, this
138  // line is a comment; skip to the next line.
139  //
140  if (*ptr == '#')
141  continue;
142 
143  //
144  // Is the next character alphabetic? If not,
145  // this isn't a valid parameter name.
146  //
147  if (FILECONF_ISALPHA(*ptr))
148  {
150  "%s, line %u doesn't have a valid parameter name",
151  loadfile, lineno);
152  continue;
153  }
154 
155  //
156  // Grab the first token, which is made of
157  // alphanumerics, underscores, and hyphens.
158  // That's the name of the parameter being set.
159  //
160  param = ptr;
161  while (FILECONF_ISALNUM(*ptr) || *ptr == '-' || *ptr == '_')
162  ptr++;
163 
164  //
165  // Skip over white space, if any.
166  //
167  ptr = skipws(ptr);
168  if (ptr == NULL || *ptr != '=')
169  {
170  //
171  // We hit the end of the line before
172  // finding a non-white space character,
173  // or we found one but it's not an "=".
174  // That means there's no "=", so this
175  // line is invalid. Complain and skip
176  // this line.
177  //
179  "%s, line %u has a parameter but no =",
180  loadfile, lineno);
181  continue;
182  }
183 
184  //
185  // We found the '='; set it to '\0', and skip
186  // past it.
187  //
188  *ptr++ = '\0';
189 
190  //
191  // Skip past any white space after the "=".
192  //
193  ptr = skipws(ptr);
194  if (ptr == NULL)
195  {
196  //
197  // The value is empty.
198  //
200  "%s, line %u has a parameter but no value",
201  loadfile, lineno);
202  continue;
203  }
204 
205  //
206  // OK, what parameter is this?
207  //
208  if (strcmp(param, PARAM_ACTIVECLIENT) == 0) {
209  //
210  // Add this to the list of active clients.
211  //
212  char *address, *port;
213 
214  //
215  // We can't have more than MAX_ACTIVE_LIST
216  // active clients.
217  //
218  if (num_active_clients >= MAX_ACTIVE_LIST)
219  {
220  //
221  // Too many entries for the active
222  // client list. Complain and
223  // ignore it.
224  //
226  "%s, line %u has an %s parameter, but we already have %u active clients",
227  loadfile, lineno, PARAM_ACTIVECLIENT,
229  continue;
230  }
231 
232  //
233  // Get the address.
234  // It's terminated by a host list separator
235  // *or* a #; there *shouldn't* be a #, as
236  // that starts a comment, and that would
237  // mean that we have no port.
238  //
239  address = ptr;
240  toklen = strcspn(ptr, RPCAP_HOSTLIST_SEP "#");
241  ptr += toklen; // skip to the terminator
242  if (toklen == 0)
243  {
244  if (*ptr == ' ' || *ptr == '\t' ||
245  *ptr == '\r' || *ptr == '\n' ||
246  *ptr == '#' || *ptr == '\0')
247  {
248  //
249  // The first character it saw
250  // was a whitespace character
251  // or a comment character,
252  // or we ran out of characters.
253  // This means that there's
254  // no value.
255  //
257  "%s, line %u has a parameter but no value",
258  loadfile, lineno);
259  }
260  else
261  {
262  //
263  // This means that the first
264  // character it saw was a
265  // separator. This means that
266  // there's no address in the
267  // value, just a port.
268  //
270  "%s, line %u has an %s parameter with a value containing no address",
271  loadfile, lineno, PARAM_ACTIVECLIENT);
272  }
273  continue;
274  }
275 
276  //
277  // Null-terminate the address, and skip past
278  // it.
279  //
280  *ptr++ = '\0';
281 
282  //
283  // Skip any white space following the
284  // separating character.
285  //
286  ptr = skipws(ptr);
287  if (ptr == NULL)
288  {
289  //
290  // The value is empty, so there's
291  // no port in the value.
292  //
294  "%s, line %u has an %s parameter with a value containing no port",
295  loadfile, lineno, PARAM_ACTIVECLIENT);
296  continue;
297  }
298 
299  //
300  // Get the port.
301  // We look for a white space character
302  // or a # as a terminator; the # introduces
303  // a comment that runs to the end of the
304  // line.
305  //
306  port = ptr;
307  toklen = strcspn(ptr, " \t#\r\n");
308  ptr += toklen;
309  if (toklen == 0)
310  {
311  //
312  // The value is empty, so there's
313  // no port in the value.
314  //
316  "%s, line %u has an %s parameter with a value containing no port",
317  loadfile, lineno, PARAM_ACTIVECLIENT);
318  continue;
319  }
320 
321  //
322  // Null-terminate the port, and skip past
323  // it.
324  //
325  *ptr++ = '\0';
326  result = pcap_strlcpy(activelist[num_active_clients].address, address, sizeof(activelist[num_active_clients].address));
327  if (result >= sizeof(activelist[num_active_clients].address))
328  {
329  //
330  // It didn't fit.
331  //
333  "%s, line %u has an %s parameter with an address with more than %u characters",
334  loadfile, lineno, PARAM_ACTIVECLIENT,
335  (unsigned int)(sizeof(activelist[num_active_clients].address) - 1));
336  continue;
337  }
338  if (strcmp(port, "DEFAULT") == 0) // the user choose a custom port
339  result = pcap_strlcpy(activelist[num_active_clients].port, RPCAP_DEFAULT_NETPORT_ACTIVE, sizeof(activelist[num_active_clients].port));
340  else
341  result = pcap_strlcpy(activelist[num_active_clients].port, port, sizeof(activelist[num_active_clients].port));
342  if (result >= sizeof(activelist[num_active_clients].address))
343  {
344  //
345  // It didn't fit.
346  //
348  "%s, line %u has an %s parameter with an port with more than %u characters",
349  loadfile, lineno, PARAM_ACTIVECLIENT,
350  (unsigned int)(sizeof(activelist[num_active_clients].port) - 1));
351  continue;
352  }
353 
354  num_active_clients++;
355  }
356  else if (strcmp(param, PARAM_PASSIVECLIENT) == 0)
357  {
358  char *eos;
359  char *host;
360 
361  //
362  // Get the host.
363  // We look for a white space character
364  // or a # as a terminator; the # introduces
365  // a comment that runs to the end of the
366  // line.
367  //
368  host = ptr;
369  toklen = strcspn(ptr, " \t#\r\n");
370  if (toklen == 0)
371  {
372  //
373  // The first character it saw
374  // was a whitespace character
375  // or a comment character.
376  // This means that there's
377  // no value.
378  //
380  "%s, line %u has a parameter but no value",
381  loadfile, lineno);
382  continue;
383  }
384  ptr += toklen;
385  *ptr++ = '\0';
386 
387  //
388  // Append this to the host list.
389  // Save the curren end-of-string for the
390  // host list, in case the new host doesn't
391  // fit, so that we can discard the partially-
392  // copied host name.
393  //
394  eos = hostlist + strlen(hostlist);
395  if (eos != hostlist)
396  {
397  //
398  // The list is not empty, so prepend
399  // a comma before adding this host.
400  //
401  result = pcap_strlcat(hostlist, ",", sizeof(hostlist));
402  if (result >= sizeof(hostlist))
403  {
404  //
405  // It didn't fit. Discard
406  // the comma (which wasn't
407  // added, but...), complain,
408  // and ignore this line.
409  //
410  *eos = '\0';
412  "%s, line %u has a %s parameter with a host name that doesn't fit",
413  loadfile, lineno, PARAM_PASSIVECLIENT);
414  continue;
415  }
416  }
417  result = pcap_strlcat(hostlist, host, sizeof(hostlist));
418  if (result >= sizeof(hostlist))
419  {
420  //
421  // It didn't fit. Discard the comma,
422  // complain, and ignore this line.
423  //
424  *eos = '\0';
426  "%s, line %u has a %s parameter with a host name that doesn't fit",
427  loadfile, lineno, PARAM_PASSIVECLIENT);
428  continue;
429  }
430  }
431  else if (strcmp(param, PARAM_NULLAUTHPERMIT) == 0)
432  {
433  char *setting;
434 
435  //
436  // Get the setting.
437  // We look for a white space character
438  // or a # as a terminator; the # introduces
439  // a comment that runs to the end of the
440  // line.
441  //
442  setting = ptr;
443  toklen = strcspn(ptr, " \t#\r\n");
444  ptr += toklen;
445  if (toklen == 0)
446  {
447  //
448  // The first character it saw
449  // was a whitespace character
450  // or a comment character.
451  // This means that there's
452  // no value.
453  //
455  "%s, line %u has a parameter but no value",
456  loadfile, lineno);
457  continue;
458  }
459  *ptr++ = '\0';
460 
461  //
462  // XXX - should we complain if it's
463  // neither "yes" nor "no"?
464  //
465  if (strcmp(setting, "YES") == 0)
466  nullAuthAllowed = 1;
467  else
468  nullAuthAllowed = 0;
469  }
470  else
471  {
473  "%s, line %u has an unknown parameter %s",
474  loadfile, lineno, param);
475  continue;
476  }
477  }
478 
479 done:
480  // clear the remaining fields of the active list
481  for (int i = num_active_clients; i < MAX_ACTIVE_LIST; i++)
482  {
483  activelist[i].address[0] = 0;
484  activelist[i].port[0] = 0;
485  num_active_clients++;
486  }
487 
488  rpcapd_log(LOGPRIO_DEBUG, "New passive host list: %s", hostlist);
489  fclose(fp);
490  }
491 }
492 
493 int fileconf_save(const char *savefile)
494 {
495  FILE *fp;
496 
497  if ((fp = fopen(savefile, "w")) != NULL)
498  {
499  char *token; /*, *port;*/ // temp, needed to separate items into the hostlist
500  char temphostlist[MAX_HOST_LIST + 1];
501  int i = 0;
502  char *lasts;
503 
504  fprintf(fp, "# Configuration file help.\n\n");
505 
506  // Save list of clients which are allowed to connect to us in passive mode
507  fprintf(fp, "# Hosts which are allowed to connect to this server (passive mode)\n");
508  fprintf(fp, "# Format: PassiveClient = <name or address>\n\n");
509 
510  pcap_strlcpy(temphostlist, hostlist, sizeof (temphostlist));
511 
512  token = pcap_strtok_r(temphostlist, RPCAP_HOSTLIST_SEP, &lasts);
513  while(token != NULL)
514  {
515  fprintf(fp, "%s = %s\n", PARAM_PASSIVECLIENT, token);
516  token = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
517  }
518 
519 
520  // Save list of clients which are allowed to connect to us in active mode
521  fprintf(fp, "\n\n");
522  fprintf(fp, "# Hosts to which this server is trying to connect to (active mode)\n");
523  fprintf(fp, "# Format: ActiveClient = <name or address>, <port | DEFAULT>\n\n");
524 
525 
526  while ((i < MAX_ACTIVE_LIST) && (activelist[i].address[0] != 0))
527  {
528  fprintf(fp, "%s = %s, %s\n", PARAM_ACTIVECLIENT,
530  i++;
531  }
532 
533  // Save if we want to permit NULL authentication
534  fprintf(fp, "\n\n");
535  fprintf(fp, "# Permit NULL authentication: YES or NO\n\n");
536 
537  fprintf(fp, "%s = %s\n", PARAM_NULLAUTHPERMIT,
538  nullAuthAllowed ? "YES" : "NO");
539 
540  fclose(fp);
541  return 0;
542  }
543  else
544  {
545  return -1;
546  }
547 
548 }
549 
550 //
551 // Skip over white space.
552 // If we hit a CR or LF, return NULL, otherwise return a pointer to
553 // the first non-white space character. Replace white space characters
554 // other than CR or LF with '\0', so that, if we're skipping white space
555 // after a token, the token is null-terminated.
556 //
557 static char *skipws(char *ptr)
558 {
559  while (*ptr == ' ' || *ptr == '\t' || *ptr == '\r' || *ptr == '\n') {
560  if (*ptr == '\r' || *ptr == '\n')
561  return NULL;
562  *ptr++ = '\0';
563  }
564  return ptr;
565 }
char hostlist[64000+1]
Keeps the list of the hosts that are allowed to connect to this server.
Definition: rpcapd.c:80
struct active_pars activelist[10]
Keeps the list of the hosts (host, port) on which I want to connect to (active mode)
Definition: rpcapd.c:81
int nullAuthAllowed
'1' if we permit NULL authentication, '0' otherwise
Definition: rpcapd.c:82
#define MAX_LINE
Definition: config_params.h:40
#define MAX_ACTIVE_LIST
Definition: config_params.h:42
char loadfile[2048+1]
Name of the file from which we have to load the configuration.
Definition: rpcapd.c:84
#define MAX_HOST_LIST
Definition: config_params.h:41
void fileconf_read(void)
Definition: fileconf.c:71
#define PARAM_NULLAUTHPERMIT
Definition: fileconf.c:57
#define PARAM_ACTIVECLIENT
Definition: fileconf.c:55
#define FILECONF_ISALNUM(c)
Definition: fileconf.c:68
#define PARAM_PASSIVECLIENT
Definition: fileconf.c:56
int fileconf_save(const char *savefile)
Definition: fileconf.c:493
static char * skipws(char *ptr)
Definition: fileconf.c:557
#define FILECONF_ISALPHA(c)
Definition: fileconf.c:66
void rpcapd_log(log_priority priority, const char *message,...)
Definition: log.c:244
@ LOGPRIO_DEBUG
Definition: log.h:27
@ LOGPRIO_ERROR
Definition: log.h:30
#define RPCAP_DEFAULT_NETPORT_ACTIVE
#define RPCAP_HOSTLIST_SEP
static char address[2048+1]
keeps the network address (either numeric or literal) to bind to
Definition: rpcapd.c:87
static char port[2048+1]
keeps the network port to bind to
Definition: rpcapd.c:88
size_t pcap_strlcat(char *restrict dst, const char *restrict src, size_t dsize)
Definition: strlcat.c:36
size_t pcap_strlcpy(char *restrict dst, const char *restrict src, size_t dsize)
Definition: strlcpy.c:34
char * pcap_strtok_r(char *s, const char *delim, char **last)
Definition: strtok_r.c:44
char port[2048+1]
Definition: config_params.h:47
char address[2048+1]
Definition: config_params.h:46