]> The Tcpdump Group git mirrors - libpcap/blob - rpcapd/fileconf.c
8a35a7b98ca68c3d24330abdfa96ecd02f1e6ef1
[libpcap] / rpcapd / fileconf.c
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 <ctype.h>
43 #include <signal.h>
44 #include <pcap.h> // for PCAP_ERRBUF_SIZE
45
46 #include "sockutils.h" // for SOCK_DEBUG_MESSAGE
47 #include "portability.h"
48 #include "rpcapd.h"
49 #include "config_params.h" // configuration file parameters
50 #include "fileconf.h"
51 #include "rpcap-protocol.h"
52 #include "log.h"
53
54 //
55 // Parameter names.
56 //
57 #define PARAM_ACTIVECLIENT "ActiveClient"
58 #define PARAM_PASSIVECLIENT "PassiveClient"
59 #define PARAM_NULLAUTHPERMIT "NullAuthPermit"
60
61 static char *skipws(char *ptr);
62
63 void fileconf_read(void)
64 {
65 FILE *fp;
66 char msg[PCAP_ERRBUF_SIZE + 1];
67 unsigned int num_active_clients;
68
69 if ((fp = fopen(loadfile, "r")) != NULL)
70 {
71 char line[MAX_LINE + 1];
72 unsigned int lineno;
73
74 hostlist[0] = 0;
75 num_active_clients = 0;
76 lineno = 0;
77
78 while (fgets(line, MAX_LINE, fp) != NULL)
79 {
80 size_t linelen;
81 char *ptr;
82 char *param;
83 size_t result;
84 size_t toklen;
85
86 lineno++;
87
88 linelen = strlen(line);
89 if (line[linelen - 1] != '\n')
90 {
91 int c;
92
93 //
94 // Either the line doesn't fit in
95 // the buffer, or we got an EOF
96 // before the EOL. Assume it's the
97 // former.
98 //
99 rpcapd_log(LOGPRIO_ERROR,
100 "%s, line %u is longer than %u characters",
101 loadfile, lineno, MAX_LINE);
102
103 //
104 // Eat characters until we get an NL.
105 //
106 while ((c = getc(fp)) != '\n')
107 {
108 if (c == EOF)
109 goto done;
110 }
111
112 //
113 // Try the next line.
114 //
115 continue;
116 }
117 ptr = line;
118
119 //
120 // Skip leading white space, if any.
121 //
122 ptr = skipws(ptr);
123 if (ptr == NULL)
124 {
125 // Blank line.
126 continue;
127 }
128
129 //
130 // Is the next character a "#"? If so, this
131 // line is a comment; skip to the next line.
132 //
133 if (*ptr == '#')
134 continue;
135
136 //
137 // Is the next character alphabetic? If not,
138 // this isn't a valid parameter name.
139 //
140 if (!isascii(*ptr) || !isalpha(*ptr))
141 {
142 rpcapd_log(LOGPRIO_ERROR,
143 "%s, line %u doesn't have a valid parameter name",
144 loadfile, lineno);
145 continue;
146 }
147
148 //
149 // Grab the first token, which is made of
150 // alphanumerics, underscores, and hyphens.
151 // That's the name of the parameter being set.
152 //
153 param = ptr;
154 while (isascii(*ptr) &&
155 (isalnum(*ptr) || *ptr == '-' || *ptr == '_'))
156 ptr++;
157
158 //
159 // Skip over white space, if any.
160 //
161 ptr = skipws(ptr);
162 if (ptr == NULL || *ptr != '=')
163 {
164 //
165 // We hit the end of the line before
166 // finding a non-white space character,
167 // or we found one but it's not an "=".
168 // That means there's no "=", so this
169 // line is invalid. Complain and skip
170 // this line.
171 //
172 rpcapd_log(LOGPRIO_ERROR,
173 "%s, line %u has a parameter but no =",
174 loadfile, lineno);
175 continue;
176 }
177
178 //
179 // We found the '='; set it to '\0', and skip
180 // past it.
181 //
182 *ptr++ = '\0';
183
184 //
185 // Skip past any white space after the "=".
186 //
187 ptr = skipws(ptr);
188 if (ptr == NULL)
189 {
190 //
191 // The value is empty.
192 //
193 rpcapd_log(LOGPRIO_ERROR,
194 "%s, line %u has a parameter but no value",
195 loadfile, lineno);
196 continue;
197 }
198
199 //
200 // OK, what parameter is this?
201 //
202 if (strcmp(param, PARAM_ACTIVECLIENT) == 0) {
203 //
204 // Add this to the list of active clients.
205 //
206 char *address, *port;
207
208 //
209 // We can't have more than MAX_ACTIVE_LIST
210 // active clients.
211 //
212 if (num_active_clients >= MAX_ACTIVE_LIST)
213 {
214 //
215 // Too many entries for the active
216 // client list. Complain and
217 // ignore it.
218 //
219 rpcapd_log(LOGPRIO_ERROR,
220 "%s, line %u has an %s parameter, but we already have %u active clients",
221 loadfile, lineno, PARAM_ACTIVECLIENT,
222 MAX_ACTIVE_LIST);
223 continue;
224 }
225
226 //
227 // Get the address.
228 // It's terminated by a host list separator
229 // *or* a #; there *shouldn't* be a #, as
230 // that starts a comment, and that would
231 // mean that we have no port.
232 //
233 address = ptr;
234 toklen = strcspn(ptr, RPCAP_HOSTLIST_SEP "#");
235 ptr += toklen; // skip to the terminator
236 if (toklen == 0)
237 {
238 if (isascii(*ptr) &&
239 (isspace(*ptr) || *ptr == '#' || *ptr == '\0'))
240 {
241 //
242 // The first character it saw
243 // was a whitespace character
244 // or a comment character.
245 // This means that there's
246 // no value.
247 //
248 rpcapd_log(LOGPRIO_ERROR,
249 "%s, line %u has a parameter but no value",
250 loadfile, lineno);
251 }
252 else
253 {
254 //
255 // This means that the first
256 // character it saw was a
257 // separator. This means that
258 // there's no address in the
259 // value, just a port.
260 //
261 rpcapd_log(LOGPRIO_ERROR,
262 "%s, line %u has an %s parameter with a value containing no address",
263 loadfile, lineno, PARAM_ACTIVECLIENT);
264 }
265 continue;
266 }
267
268 //
269 // Null-terminate the address, and skip past
270 // it.
271 //
272 *ptr++ = '\0';
273
274 //
275 // Skip any white space following the
276 // separating character.
277 //
278 ptr = skipws(ptr);
279 if (ptr == NULL)
280 {
281 //
282 // The value is empty, so there's
283 // no port in the value.
284 //
285 rpcapd_log(LOGPRIO_ERROR,
286 "%s, line %u has an %s parameter with a value containing no port",
287 loadfile, lineno, PARAM_ACTIVECLIENT);
288 continue;
289 }
290
291 //
292 // Get the port.
293 // We look for a white space character
294 // or a # as a terminator; the # introduces
295 // a comment that runs to the end of the
296 // line.
297 //
298 port = ptr;
299 toklen = strcspn(ptr, " \t#\r\n");
300 ptr += toklen;
301 if (toklen == 0)
302 {
303 //
304 // The value is empty, so there's
305 // no port in the value.
306 //
307 rpcapd_log(LOGPRIO_ERROR,
308 "%s, line %u has an %s parameter with a value containing no port",
309 loadfile, lineno, PARAM_ACTIVECLIENT);
310 continue;
311 }
312
313 //
314 // Null-terminate the port, and skip past
315 // it.
316 //
317 *ptr++ = '\0';
318 result = strlcpy(activelist[num_active_clients].address, address, sizeof(activelist[num_active_clients].address));
319 if (result >= sizeof(activelist[num_active_clients].address))
320 {
321 //
322 // It didn't fit.
323 //
324 rpcapd_log(LOGPRIO_ERROR,
325 "%s, line %u has an %s parameter with an address with more than %u characters",
326 loadfile, lineno, PARAM_ACTIVECLIENT,
327 (unsigned int)(sizeof(activelist[num_active_clients].address) - 1));
328 continue;
329 }
330 if (strcmp(port, "DEFAULT") == 0) // the user choose a custom port
331 result = strlcpy(activelist[num_active_clients].port, RPCAP_DEFAULT_NETPORT_ACTIVE, sizeof(activelist[num_active_clients].port));
332 else
333 result = strlcpy(activelist[num_active_clients].port, port, sizeof(activelist[num_active_clients].port));
334 if (result >= sizeof(activelist[num_active_clients].address))
335 {
336 //
337 // It didn't fit.
338 //
339 rpcapd_log(LOGPRIO_ERROR,
340 "%s, line %u has an %s parameter with an port with more than %u characters",
341 loadfile, lineno, PARAM_ACTIVECLIENT,
342 (unsigned int)(sizeof(activelist[num_active_clients].port) - 1));
343 continue;
344 }
345
346 num_active_clients++;
347 }
348 else if (strcmp(param, PARAM_PASSIVECLIENT) == 0)
349 {
350 char *eos;
351 char *host;
352
353 //
354 // Get the host.
355 // We look for a white space character
356 // or a # as a terminator; the # introduces
357 // a comment that runs to the end of the
358 // line.
359 //
360 host = ptr;
361 toklen = strcspn(ptr, " \t#\r\n");
362 if (toklen == 0)
363 {
364 //
365 // The first character it saw
366 // was a whitespace character
367 // or a comment character.
368 // This means that there's
369 // no value.
370 //
371 rpcapd_log(LOGPRIO_ERROR,
372 "%s, line %u has a parameter but no value",
373 loadfile, lineno);
374 continue;
375 }
376 ptr += toklen;
377 *ptr++ = '\0';
378
379 //
380 // Append this to the host list.
381 // Save the curren end-of-string for the
382 // host list, in case the new host doesn't
383 // fit, so that we can discard the partially-
384 // copied host name.
385 //
386 eos = hostlist + strlen(hostlist);
387 if (eos != hostlist)
388 {
389 //
390 // The list is not empty, so prepend
391 // a comma before adding this host.
392 //
393 result = strlcat(hostlist, ",", sizeof(hostlist));
394 if (result >= sizeof(hostlist))
395 {
396 //
397 // It didn't fit. Discard
398 // the comma (which wasn't
399 // added, but...), complain,
400 // and ignore this line.
401 //
402 *eos = '\0';
403 rpcapd_log(LOGPRIO_ERROR,
404 "%s, line %u has a %s parameter with a host name that doesn't fit",
405 loadfile, lineno, PARAM_PASSIVECLIENT);
406 continue;
407 }
408 }
409 result = strlcat(hostlist, host, sizeof(hostlist));
410 if (result >= sizeof(hostlist))
411 {
412 //
413 // It didn't fit. Discard the comma,
414 // complain, and ignore this line.
415 //
416 *eos = '\0';
417 rpcapd_log(LOGPRIO_ERROR,
418 "%s, line %u has a %s parameter with a host name that doesn't fit",
419 loadfile, lineno, PARAM_PASSIVECLIENT);
420 continue;
421 }
422 }
423 else if (strcmp(param, PARAM_NULLAUTHPERMIT) == 0)
424 {
425 char *setting;
426
427 //
428 // Get the setting.
429 // We look for a white space character
430 // or a # as a terminator; the # introduces
431 // a comment that runs to the end of the
432 // line.
433 //
434 setting = ptr;
435 toklen = strcspn(ptr, " \t#\r\n");
436 ptr += toklen;
437 if (toklen == 0)
438 {
439 //
440 // The first character it saw
441 // was a whitespace character
442 // or a comment character.
443 // This means that there's
444 // no value.
445 //
446 rpcapd_log(LOGPRIO_ERROR,
447 "%s, line %u has a parameter but no value",
448 loadfile, lineno);
449 continue;
450 }
451 *ptr++ = '\0';
452
453 //
454 // XXX - should we complain if it's
455 // neither "yes" nor "no"?
456 //
457 if (strcmp(setting, "YES") == 0)
458 nullAuthAllowed = 1;
459 else
460 nullAuthAllowed = 0;
461 }
462 else
463 {
464 rpcapd_log(LOGPRIO_ERROR,
465 "%s, line %u has an unknown parameter %s",
466 loadfile, lineno, param);
467 continue;
468 }
469 }
470
471 done:
472 // clear the remaining fields of the active list
473 for (int i = num_active_clients; i < MAX_ACTIVE_LIST; i++)
474 {
475 activelist[i].address[0] = 0;
476 activelist[i].port[0] = 0;
477 num_active_clients++;
478 }
479
480 pcap_snprintf(msg, PCAP_ERRBUF_SIZE, "New passive host list: %s\n\n", hostlist);
481 SOCK_DEBUG_MESSAGE(msg);
482 fclose(fp);
483 }
484 }
485
486 int fileconf_save(const char *savefile)
487 {
488 FILE *fp;
489
490 if ((fp = fopen(savefile, "w")) != NULL)
491 {
492 char *token; /*, *port;*/ // temp, needed to separate items into the hostlist
493 char temphostlist[MAX_HOST_LIST + 1];
494 int i = 0;
495 char *lasts;
496
497 fprintf(fp, "# Configuration file help.\n\n");
498
499 // Save list of clients which are allowed to connect to us in passive mode
500 fprintf(fp, "# Hosts which are allowed to connect to this server (passive mode)\n");
501 fprintf(fp, "# Format: PassiveClient = <name or address>\n\n");
502
503 strncpy(temphostlist, hostlist, MAX_HOST_LIST);
504 temphostlist[MAX_HOST_LIST] = 0;
505
506 token = pcap_strtok_r(temphostlist, RPCAP_HOSTLIST_SEP, &lasts);
507 while(token != NULL)
508 {
509 fprintf(fp, "%s = %s\n", PARAM_PASSIVECLIENT, token);
510 token = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
511 }
512
513
514 // Save list of clients which are allowed to connect to us in active mode
515 fprintf(fp, "\n\n");
516 fprintf(fp, "# Hosts to which this server is trying to connect to (active mode)\n");
517 fprintf(fp, "# Format: ActiveClient = <name or address>, <port | DEFAULT>\n\n");
518
519
520 while ((i < MAX_ACTIVE_LIST) && (activelist[i].address[0] != 0))
521 {
522 fprintf(fp, "%s = %s, %s\n", PARAM_ACTIVECLIENT,
523 activelist[i].address, activelist[i].port);
524 i++;
525 }
526
527 // Save if we want to permit NULL authentication
528 fprintf(fp, "\n\n");
529 fprintf(fp, "# Permit NULL authentication: YES or NO\n\n");
530
531 fprintf(fp, "%s = %s\n", PARAM_NULLAUTHPERMIT,
532 nullAuthAllowed ? "YES" : "NO");
533
534 fclose(fp);
535 return 0;
536 }
537 else
538 {
539 return -1;
540 }
541
542 }
543
544 //
545 // Skip over white space.
546 // If we hit a CR or LF, return NULL, otherwise return a pointer to
547 // the first non-white space character. Replace white space characters
548 // other than CR or LF with '\0', so that, if we're skipping white space
549 // after a token, the token is null-terminated.
550 //
551 static char *skipws(char *ptr)
552 {
553 while (isascii(*ptr) && isspace(*ptr)) {
554 if (*ptr == '\r' || *ptr == '\n')
555 return NULL;
556 *ptr++ = '\0';
557 }
558 return ptr;
559 }