xref: /netbsd-src/usr.sbin/ldpd/conffile.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /* $NetBSD: conffile.c,v 1.12 2017/01/10 21:02:38 christos 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 char *mapped, *nextline;
51 size_t mapsize;
52 
53 extern int ldp_hello_time, ldp_keepalive_time, ldp_holddown_time, command_port,
54 	min_label, max_label, no_default_route, loop_detection;
55 struct in_addr conf_ldp_id;
56 
57 static int conf_dispatch(char*);
58 static char * conf_getlinelimit(void);
59 static int checkeol(char*);
60 static int Fhellotime(char*);
61 static int Fport(char*);
62 static int Fholddown(char*);
63 static int Fkeepalive(char*);
64 static int Fmaxlabel(char*);
65 static int Fminlabel(char*);
66 static int Fldpid(char*);
67 static int Fneighbour(char*);
68 static int Gneighbour(struct conf_neighbour *, char *);
69 static int Fnodefault(char*);
70 static int Floopdetection(char*);
71 static int Finterface(char*);
72 static int Ginterface(struct conf_interface *, char *);
73 static int Ipassive(struct conf_interface *, char *);
74 static int Itaddr(struct conf_interface *, char *);
75 
76 struct conf_func {
77 	char com[64];
78 	int (* func)(char *);
79 };
80 
81 struct intf_func {
82 	char com[64];
83 	int (* func)(struct conf_interface *, char *);
84 };
85 
86 struct conf_func main_commands[] = {
87 	{ "hello-time", Fhellotime },
88 	{ "keepalive-time", Fkeepalive },
89 	{ "holddown-time", Fholddown },
90 	{ "command-port", Fport },
91 	{ "min-label", Fminlabel },
92 	{ "max-label", Fmaxlabel },
93 	{ "ldp-id", Fldpid },
94 	{ "neighbor", Fneighbour },
95 	{ "neighbour", Fneighbour },
96 	{ "no-default-route", Fnodefault },
97 	{ "loop-detection", Floopdetection },
98 	{ "interface", Finterface },
99 	{ "", NULL },
100 };
101 
102 struct intf_func intf_commands[] = {
103 	{ "passive", Ipassive },
104 	{ "transport-address", Itaddr },
105 	{ "", NULL },
106 };
107 
108 static int parseline;
109 
110 /*
111  * Parses config file
112  */
113 int
114 conf_parsefile(const char *fname)
115 {
116 	char line[LINEMAXSIZE+1];
117 	struct stat fs;
118 
119 	SLIST_INIT(&conei_head);
120 	SLIST_INIT(&coifs_head);
121 	conf_ldp_id.s_addr = 0;
122 
123 	int confh = open(fname, O_RDONLY, 0);
124 
125 	if (confh == -1 || fstat(confh, &fs) == -1 ||
126 	    (mapped = mmap(NULL, fs.st_size, PROT_READ, MAP_SHARED, confh, 0))
127 	    == MAP_FAILED) {
128 		if (confh != -1)
129 			close(confh);
130 		return E_CONF_IO;
131 	}
132 
133 	mapsize = fs.st_size;
134 	nextline = mapped;
135 	for (parseline = 1; ; parseline++) {
136 		char *prev = nextline;
137 		if ((nextline = conf_getlinelimit()) == NULL)
138 			break;
139 		while (isspace((int)*prev) != 0 && prev < nextline)
140 			prev++;
141 		if (nextline - prev < 2)
142 			continue;
143 		else if (nextline - prev > LINEMAXSIZE)
144 			goto parerr;
145 		memcpy(line, prev, nextline - prev);
146 		if (line[0] == '#')
147 			continue;
148 		else
149 			line[nextline - prev] = '\0';
150 		if (conf_dispatch(line) != 0)
151 			goto parerr;
152 	}
153 	munmap(mapped, mapsize);
154 	close(confh);
155 	return 0;
156 parerr:
157 	munmap(mapped, mapsize);
158 	close(confh);
159 	return parseline;
160 }
161 
162 char *
163 conf_getlinelimit(void)
164 {
165 	char *p = nextline;
166 
167 	if (nextline < mapped || (size_t)(nextline - mapped) >= mapsize)
168 		return NULL;
169 
170 	for (p = nextline; *p != '\n' && (size_t)(p - mapped) < mapsize; p++);
171 	return p + 1;
172 }
173 
174 /*
175  * Looks for a matching command on a line
176  */
177 int
178 conf_dispatch(char *line)
179 {
180 	int i, last_match = -1, matched = 0;
181 	char *command, *nline = line;
182 
183 	if (strlen(line) == 0 || line[0] == '#')
184 		return E_CONF_OK;
185 	command = NextCommand(nline);
186 	for (i = 0; main_commands[i].func != NULL; i++)
187 		if (strncasecmp(main_commands[i].com, command,
188 		    strlen(main_commands[i].com)) == 0) {
189 			matched++;
190 			last_match = i;
191 		}
192 	if (matched == 0)
193 		return E_CONF_NOMATCH;
194 	else if (matched > 1)
195 		return E_CONF_AMBIGUOUS;
196 
197 	if (nline == NULL || checkeol(nline) != 0)
198 		return E_CONF_PARAM;
199 	return main_commands[last_match].func(nline);
200 }
201 
202 /*
203  * Checks if a line is terminated or else if it contains
204  * a start block bracket. If it's semicolon terminated
205  * then trim it.
206  */
207 int
208 checkeol(char *line)
209 {
210 	size_t len = strlen(line);
211 	if (len > 0 && line[len - 1] == '\n') {
212 		line[len - 1] = '\0';
213 		len--;
214 	}
215 	if (len > 0 && line[len - 1] == ';') {
216 		line[len - 1] = '\0';
217 		return 0;
218 	}
219 	for (size_t i = 0; i < len; i++)
220 		if (line[i] == '{')
221 			return 0;
222 	return -1;
223 }
224 
225 /*
226  * Sets hello time
227  */
228 int
229 Fhellotime(char *line)
230 {
231 	int ht = atoi(line);
232 	if (ht <= 0)
233 		return E_CONF_PARAM;
234 	ldp_hello_time = ht;
235 	return 0;
236 }
237 
238 /*
239  * Sets command port
240  */
241 int
242 Fport(char *line)
243 {
244 	int cp = atoi(line);
245 	if (cp <= 0 || cp > 65535)
246 		return E_CONF_PARAM;
247 	command_port = cp;
248 	return 0;
249 }
250 
251 /*
252  * Sets neighbour keepalive
253  */
254 int
255 Fkeepalive(char *line)
256 {
257 	int kt = atoi(line);
258 	if (kt <= 0)
259 		return E_CONF_PARAM;
260 	ldp_keepalive_time = kt;
261 	return 0;
262 }
263 
264 /*
265  * Sets neighbour holddown timer
266  */
267 int
268 Fholddown(char *line)
269 {
270 	int hdt = atoi(line);
271 	if (hdt <= 0)
272 		return E_CONF_PARAM;
273 	ldp_holddown_time = hdt;
274 	return 0;
275 }
276 
277 int
278 Fminlabel(char *line)
279 {
280 	int ml = atoi(line);
281 	if (ml <= 0)
282 		return E_CONF_PARAM;
283 	min_label = ml;
284 	return 0;
285 }
286 
287 int
288 Fmaxlabel(char *line)
289 {
290 	int ml = atoi(line);
291 	if (ml <= 0)
292 		return E_CONF_PARAM;
293 	max_label = ml;
294 	return 0;
295 }
296 
297 int
298 Fldpid(char *line)
299 {
300 	if (inet_pton(AF_INET, line, &conf_ldp_id) != 1)
301 		return E_CONF_PARAM;
302 	return 0;
303 }
304 
305 int
306 Fneighbour(char *line)
307 {
308 	char *peer;
309 	struct conf_neighbour *nei;
310 	struct in_addr ad;
311 	char buf[LINEMAXSIZE];
312 
313 	peer = NextCommand(line);
314 	if (inet_pton(AF_INET, peer, &ad) != 1)
315 		return E_CONF_PARAM;
316 
317 	nei = calloc(1, sizeof(*nei));
318 	if (nei == NULL)
319 		return E_CONF_MEM;
320 	nei->address.s_addr = ad.s_addr;
321 	SLIST_INSERT_HEAD(&conei_head, nei, neilist);
322 
323 	for ( ; ; ) {
324 		char *prev = nextline;
325 		parseline++;
326 		nextline = conf_getlinelimit();
327 		if (nextline == NULL || (size_t)(nextline - prev) > LINEMAXSIZE)
328 			return -1;
329 		while (isspace((int)*prev) != 0 && prev < nextline)
330 			prev++;
331 		memcpy(buf, prev, nextline - prev);
332 		if (nextline - prev < 2 || buf[0] == '#')
333 			continue;
334 		else if (buf[0] == '}')
335 			break;
336 		else
337 			buf[nextline - prev] = '\0';
338 		if (Gneighbour(nei, buf) == -1)
339 			return -1;
340 	}
341 	return -1;
342 }
343 
344 /*
345  * neighbour { } sub-commands
346  */
347 int
348 Gneighbour(struct conf_neighbour *nei, char *line)
349 {
350 	if (strncasecmp("authenticate", line, 12) == 0) {
351 		nei->authenticate = 1;
352 		return 0;
353 	}
354 	return -1;
355 }
356 
357 int
358 Fnodefault(char *line)
359 {
360 	int nd = atoi(line);
361 	if (nd < 0)
362 		return E_CONF_PARAM;
363 	no_default_route = nd;
364 	return 0;
365 }
366 
367 int
368 Floopdetection(char *line)
369 {
370 	int loopd = atoi(line);
371 	if (loopd < 0)
372 		return E_CONF_PARAM;
373 	loop_detection = loopd;
374 	return 0;
375 }
376 
377 /*
378  * Interface sub-commands
379  */
380 int
381 Finterface(char *line)
382 {
383 	char *ifname;
384 	struct conf_interface *conf_if;
385 	char buf[LINEMAXSIZE];
386 
387 	if ((ifname = NextCommand(line)) == NULL)
388 		return -1;
389 	if ((conf_if = calloc(1, sizeof(*conf_if))) == NULL)
390 		return -1;
391 
392 	strlcpy(conf_if->if_name, ifname, IF_NAMESIZE);
393 	SLIST_INSERT_HEAD(&coifs_head, conf_if, iflist);
394 
395 	for ( ; ; ) {
396 		char *prev = nextline;
397 		parseline++;
398 		nextline = conf_getlinelimit();
399 		if (nextline == NULL || (size_t)(nextline - prev) > LINEMAXSIZE)
400 			return -1;
401 		while (isspace((int)*prev) != 0 && prev < nextline)
402 			prev++;
403 		memcpy(buf, prev, nextline - prev);
404 		if (nextline - prev < 2 || buf[0] == '#')
405 			continue;
406 		else if (buf[0] == '}')
407 			break;
408 		else
409 			buf[nextline - prev] = '\0';
410 		if (Ginterface(conf_if, buf) == -1)
411 			return -1;
412 	}
413 	return 0;
414 }
415 
416 int
417 Ginterface(struct conf_interface *conf_if, char *buf)
418 {
419 	int i;
420 
421 	for (i = 0; intf_commands[i].func != NULL; i++)
422 		if (strncasecmp(buf, intf_commands[i].com,
423 		    strlen(intf_commands[i].com)) == 0)
424 			return intf_commands[i].func(conf_if, buf +
425 			    strlen(intf_commands[i].com) + 1);
426 	/* command not found */
427 	return -1;
428 }
429 
430 /* sets transport address */
431 int
432 Itaddr(struct conf_interface *conf_if, char *buf)
433 {
434 	if (inet_pton(AF_INET, buf, &conf_if->tr_addr) != 1)
435 		return -1;
436 	return 0;
437 }
438 
439 /* sets passive-interface on */
440 int
441 Ipassive(struct conf_interface *conf_if, char *buf)
442 {
443 	conf_if->passive = 1;
444 	return 0;
445 }
446