xref: /netbsd-src/usr.sbin/ldpd/conffile.c (revision 2d8c8469e2f80b8e1cf2954618770d28e3700001)
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