1 /* $NetBSD: conffile.c,v 1.13 2020/04/22 23:53:27 joerg Exp $ */
2 
3 /*
4  * Copyright (c) 2010 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Mihai Chelaru <kefren@NetBSD.org>
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/mman.h>
33 #include <sys/stat.h>
34 
35 #include <arpa/inet.h>
36 #include <netinet/in.h>
37 
38 #include <ctype.h>
39 #include <fcntl.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 
44 #include "conffile.h"
45 #include "ldp_errors.h"
46 
47 #define NextCommand(x) strsep(&x, " ")
48 #define LINEMAXSIZE 1024
49 
50 struct coifs_head coifs_head;
51 struct conei_head conei_head;
52 
53 char *mapped, *nextline;
54 size_t mapsize;
55 
56 extern int ldp_hello_time, ldp_keepalive_time, ldp_holddown_time, command_port,
57           min_label, max_label, no_default_route, loop_detection;
58 struct in_addr conf_ldp_id;
59 
60 static int conf_dispatch(char*);
61 static char * conf_getlinelimit(void);
62 static int checkeol(char*);
63 static int Fhellotime(char*);
64 static int Fport(char*);
65 static int Fholddown(char*);
66 static int Fkeepalive(char*);
67 static int Fmaxlabel(char*);
68 static int Fminlabel(char*);
69 static int Fldpid(char*);
70 static int Fneighbour(char*);
71 static int Gneighbour(struct conf_neighbour *, char *);
72 static int Fnodefault(char*);
73 static int Floopdetection(char*);
74 static int Finterface(char*);
75 static int Ginterface(struct conf_interface *, char *);
76 static int Ipassive(struct conf_interface *, char *);
77 static int Itaddr(struct conf_interface *, char *);
78 
79 struct conf_func {
80           char com[64];
81           int (* func)(char *);
82 };
83 
84 struct intf_func {
85           char com[64];
86           int (* func)(struct conf_interface *, char *);
87 };
88 
89 struct conf_func main_commands[] = {
90           { "hello-time", Fhellotime },
91           { "keepalive-time", Fkeepalive },
92           { "holddown-time", Fholddown },
93           { "command-port", Fport },
94           { "min-label", Fminlabel },
95           { "max-label", Fmaxlabel },
96           { "ldp-id", Fldpid },
97           { "neighbor", Fneighbour },
98           { "neighbour", Fneighbour },
99           { "no-default-route", Fnodefault },
100           { "loop-detection", Floopdetection },
101           { "interface", Finterface },
102           { "", NULL },
103 };
104 
105 struct intf_func intf_commands[] = {
106           { "passive", Ipassive },
107           { "transport-address", Itaddr },
108           { "", NULL },
109 };
110 
111 static int parseline;
112 
113 /*
114  * Parses config file
115  */
116 int
conf_parsefile(const char * fname)117 conf_parsefile(const char *fname)
118 {
119           char line[LINEMAXSIZE+1];
120           struct stat fs;
121 
122           SLIST_INIT(&conei_head);
123           SLIST_INIT(&coifs_head);
124           conf_ldp_id.s_addr = 0;
125 
126           int confh = open(fname, O_RDONLY, 0);
127 
128           if (confh == -1 || fstat(confh, &fs) == -1 ||
129               (mapped = mmap(NULL, fs.st_size, PROT_READ, MAP_SHARED, confh, 0))
130               == MAP_FAILED) {
131                     if (confh != -1)
132                               close(confh);
133                     return E_CONF_IO;
134           }
135 
136           mapsize = fs.st_size;
137           nextline = mapped;
138           for (parseline = 1; ; parseline++) {
139                     char *prev = nextline;
140                     if ((nextline = conf_getlinelimit()) == NULL)
141                               break;
142                     while (isspace((int)*prev) != 0 && prev < nextline)
143                               prev++;
144                     if (nextline - prev < 2)
145                               continue;
146                     else if (nextline - prev > LINEMAXSIZE)
147                               goto parerr;
148                     memcpy(line, prev, nextline - prev);
149                     if (line[0] == '#')
150                               continue;
151                     else
152                               line[nextline - prev] = '\0';
153                     if (conf_dispatch(line) != 0)
154                               goto parerr;
155           }
156           munmap(mapped, mapsize);
157           close(confh);
158           return 0;
159 parerr:
160           munmap(mapped, mapsize);
161           close(confh);
162           return parseline;
163 }
164 
165 char *
conf_getlinelimit(void)166 conf_getlinelimit(void)
167 {
168           char *p = nextline;
169 
170           if (nextline < mapped || (size_t)(nextline - mapped) >= mapsize)
171                     return NULL;
172 
173           for (p = nextline; *p != '\n' && (size_t)(p - mapped) < mapsize; p++);
174           return p + 1;
175 }
176 
177 /*
178  * Looks for a matching command on a line
179  */
180 int
conf_dispatch(char * line)181 conf_dispatch(char *line)
182 {
183           int i, last_match = -1, matched = 0;
184           char *command, *nline = line;
185 
186           if (strlen(line) == 0 || line[0] == '#')
187                     return E_CONF_OK;
188           command = NextCommand(nline);
189           for (i = 0; main_commands[i].func != NULL; i++)
190                     if (strncasecmp(main_commands[i].com, command,
191                         strlen(main_commands[i].com)) == 0) {
192                               matched++;
193                               last_match = i;
194                     }
195           if (matched == 0)
196                     return E_CONF_NOMATCH;
197           else if (matched > 1)
198                     return E_CONF_AMBIGUOUS;
199 
200           if (nline == NULL || checkeol(nline) != 0)
201                     return E_CONF_PARAM;
202           return main_commands[last_match].func(nline);
203 }
204 
205 /*
206  * Checks if a line is terminated or else if it contains
207  * a start block bracket. If it's semicolon terminated
208  * then trim it.
209  */
210 int
checkeol(char * line)211 checkeol(char *line)
212 {
213           size_t len = strlen(line);
214           if (len > 0 && line[len - 1] == '\n') {
215                     line[len - 1] = '\0';
216                     len--;
217           }
218           if (len > 0 && line[len - 1] == ';') {
219                     line[len - 1] = '\0';
220                     return 0;
221           }
222           for (size_t i = 0; i < len; i++)
223                     if (line[i] == '{')
224                               return 0;
225           return -1;
226 }
227 
228 /*
229  * Sets hello time
230  */
231 int
Fhellotime(char * line)232 Fhellotime(char *line)
233 {
234           int ht = atoi(line);
235           if (ht <= 0)
236                     return E_CONF_PARAM;
237           ldp_hello_time = ht;
238           return 0;
239 }
240 
241 /*
242  * Sets command port
243  */
244 int
Fport(char * line)245 Fport(char *line)
246 {
247           int cp = atoi(line);
248           if (cp <= 0 || cp > 65535)
249                     return E_CONF_PARAM;
250           command_port = cp;
251           return 0;
252 }
253 
254 /*
255  * Sets neighbour keepalive
256  */
257 int
Fkeepalive(char * line)258 Fkeepalive(char *line)
259 {
260           int kt = atoi(line);
261           if (kt <= 0)
262                     return E_CONF_PARAM;
263           ldp_keepalive_time = kt;
264           return 0;
265 }
266 
267 /*
268  * Sets neighbour holddown timer
269  */
270 int
Fholddown(char * line)271 Fholddown(char *line)
272 {
273           int hdt = atoi(line);
274           if (hdt <= 0)
275                     return E_CONF_PARAM;
276           ldp_holddown_time = hdt;
277           return 0;
278 }
279 
280 int
Fminlabel(char * line)281 Fminlabel(char *line)
282 {
283           int ml = atoi(line);
284           if (ml <= 0)
285                     return E_CONF_PARAM;
286           min_label = ml;
287           return 0;
288 }
289 
290 int
Fmaxlabel(char * line)291 Fmaxlabel(char *line)
292 {
293           int ml = atoi(line);
294           if (ml <= 0)
295                     return E_CONF_PARAM;
296           max_label = ml;
297           return 0;
298 }
299 
300 int
Fldpid(char * line)301 Fldpid(char *line)
302 {
303           if (inet_pton(AF_INET, line, &conf_ldp_id) != 1)
304                     return E_CONF_PARAM;
305           return 0;
306 }
307 
308 int
Fneighbour(char * line)309 Fneighbour(char *line)
310 {
311           char *peer;
312           struct conf_neighbour *nei;
313           struct in_addr ad;
314           char buf[LINEMAXSIZE];
315 
316           peer = NextCommand(line);
317           if (inet_pton(AF_INET, peer, &ad) != 1)
318                     return E_CONF_PARAM;
319 
320           nei = calloc(1, sizeof(*nei));
321           if (nei == NULL)
322                     return E_CONF_MEM;
323           nei->address.s_addr = ad.s_addr;
324           SLIST_INSERT_HEAD(&conei_head, nei, neilist);
325 
326           for ( ; ; ) {
327                     char *prev = nextline;
328                     parseline++;
329                     nextline = conf_getlinelimit();
330                     if (nextline == NULL || (size_t)(nextline - prev) > LINEMAXSIZE)
331                               return -1;
332                     while (isspace((int)*prev) != 0 && prev < nextline)
333                               prev++;
334                     memcpy(buf, prev, nextline - prev);
335                     if (nextline - prev < 2 || buf[0] == '#')
336                               continue;
337                     else if (buf[0] == '}')
338                               break;
339                     else
340                               buf[nextline - prev] = '\0';
341                     if (Gneighbour(nei, buf) == -1)
342                               return -1;
343           }
344           return -1;
345 }
346 
347 /*
348  * neighbour { } sub-commands
349  */
350 int
Gneighbour(struct conf_neighbour * nei,char * line)351 Gneighbour(struct conf_neighbour *nei, char *line)
352 {
353           if (strncasecmp("authenticate", line, 12) == 0) {
354                     nei->authenticate = 1;
355                     return 0;
356           }
357           return -1;
358 }
359 
360 int
Fnodefault(char * line)361 Fnodefault(char *line)
362 {
363           int nd = atoi(line);
364           if (nd < 0)
365                     return E_CONF_PARAM;
366           no_default_route = nd;
367           return 0;
368 }
369 
370 int
Floopdetection(char * line)371 Floopdetection(char *line)
372 {
373           int loopd = atoi(line);
374           if (loopd < 0)
375                     return E_CONF_PARAM;
376           loop_detection = loopd;
377           return 0;
378 }
379 
380 /*
381  * Interface sub-commands
382  */
383 int
Finterface(char * line)384 Finterface(char *line)
385 {
386           char *ifname;
387           struct conf_interface *conf_if;
388           char buf[LINEMAXSIZE];
389 
390           if ((ifname = NextCommand(line)) == NULL)
391                     return -1;
392           if ((conf_if = calloc(1, sizeof(*conf_if))) == NULL)
393                     return -1;
394 
395           strlcpy(conf_if->if_name, ifname, IF_NAMESIZE);
396           SLIST_INSERT_HEAD(&coifs_head, conf_if, iflist);
397 
398           for ( ; ; ) {
399                     char *prev = nextline;
400                     parseline++;
401                     nextline = conf_getlinelimit();
402                     if (nextline == NULL || (size_t)(nextline - prev) > LINEMAXSIZE)
403                               return -1;
404                     while (isspace((int)*prev) != 0 && prev < nextline)
405                               prev++;
406                     memcpy(buf, prev, nextline - prev);
407                     if (nextline - prev < 2 || buf[0] == '#')
408                               continue;
409                     else if (buf[0] == '}')
410                               break;
411                     else
412                               buf[nextline - prev] = '\0';
413                     if (Ginterface(conf_if, buf) == -1)
414                               return -1;
415           }
416           return 0;
417 }
418 
419 int
Ginterface(struct conf_interface * conf_if,char * buf)420 Ginterface(struct conf_interface *conf_if, char *buf)
421 {
422           int i;
423 
424           for (i = 0; intf_commands[i].func != NULL; i++)
425                     if (strncasecmp(buf, intf_commands[i].com,
426                         strlen(intf_commands[i].com)) == 0)
427                               return intf_commands[i].func(conf_if, buf +
428                                   strlen(intf_commands[i].com) + 1);
429           /* command not found */
430           return -1;
431 }
432 
433 /* sets transport address */
434 int
Itaddr(struct conf_interface * conf_if,char * buf)435 Itaddr(struct conf_interface *conf_if, char *buf)
436 {
437           if (inet_pton(AF_INET, buf, &conf_if->tr_addr) != 1)
438                     return -1;
439           return 0;
440 }
441 
442 /* sets passive-interface on */
443 int
Ipassive(struct conf_interface * conf_if,char * buf)444 Ipassive(struct conf_interface *conf_if, char *buf)
445 {
446           conf_if->passive = 1;
447           return 0;
448 }
449