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