xref: /netbsd-src/usr.sbin/ldpd/conffile.c (revision ba65fde2d7fefa7d39838fa5fa855e62bd606b5e)
1 /* $NetBSD: conffile.c,v 1.5 2013/01/26 21:07:49 kefren 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 <arpa/inet.h>
33 #include <netinet/in.h>
34 
35 #include <ctype.h>
36 #include <fcntl.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 #include "conffile.h"
42 #include "ldp_errors.h"
43 
44 #define NextCommand(x) strsep(&x, " ")
45 #define LINEMAXSIZE 1024
46 
47 extern int ldp_hello_time, ldp_keepalive_time, ldp_holddown_time, command_port,
48 	min_label, max_label, no_default_route, loop_detection;
49 int confh;
50 struct in_addr conf_ldp_id;
51 
52 static int conf_dispatch(char*);
53 static int conf_readline(char*, size_t);
54 static int checkeol(char*);
55 static int Fhellotime(char*);
56 static int Fport(char*);
57 static int Fholddown(char*);
58 static int Fkeepalive(char*);
59 static int Fmaxlabel(char*);
60 static int Fminlabel(char*);
61 static int Fldpid(char*);
62 static int Fneighbour(char*);
63 static int Gneighbour(struct conf_neighbour *, char *);
64 static int Fnodefault(char*);
65 static int Floopdetection(char*);
66 static int Fpassiveif(char*);
67 
68 struct conf_func {
69 	char com[64];
70 	int (* func)(char *);
71 };
72 
73 struct conf_func main_commands[] = {
74 	{ "hello-time", Fhellotime },
75 	{ "keepalive-time", Fkeepalive },
76 	{ "holddown-time", Fholddown },
77 	{ "command-port", Fport },
78 	{ "min-label", Fminlabel },
79 	{ "max-label", Fmaxlabel },
80 	{ "LDP-ID", Fldpid },
81 	{ "neighbor", Fneighbour },
82 	{ "neighbour", Fneighbour },
83 	{ "no-default-route", Fnodefault },
84 	{ "loop-detection", Floopdetection },
85 	{ "passive-if", Fpassiveif },
86 	{ "", NULL },
87 };
88 
89 /*
90  * Parses config file
91  */
92 int
93 conf_parsefile(char *fname)
94 {
95 	int i;
96 	char buf[LINEMAXSIZE + 1];
97 
98 	SLIST_INIT(&conei_head);
99 	SLIST_INIT(&passifs_head);
100 	conf_ldp_id.s_addr = 0;
101 
102 	confh = open(fname, O_RDONLY, 0);
103 
104 	if (confh == -1)
105 		return E_CONF_IO;
106 
107 	for (i = 1; conf_readline(buf, sizeof(buf)) >= 0; i++)
108 		if (conf_dispatch(buf) != 0) {
109 			close(confh);
110 			return i;
111 		}
112 
113 	close(confh);
114 	return 0;
115 }
116 
117 /*
118  * Reads a line from config file
119  */
120 int
121 conf_readline(char *buf, size_t bufsize)
122 {
123 	size_t i;
124 
125 	for (i = 0; i < bufsize; i++) {
126 		if (read(confh, &buf[i], 1) != 1) {
127 			if (i == 0)
128 				return E_CONF_IO;
129 			break;
130 		}
131 		if (buf[i] == '\n')
132 			break;
133 		if (i == 0 && isspace((unsigned char)buf[i]) != 0) {
134 			i--;
135 			continue;
136 		}
137 	}
138 	if (i == bufsize)
139 		return E_CONF_MEM;
140 	buf[i] = '\0';
141 	return i;
142 }
143 
144 /*
145  * Looks for a matching command on a line
146  */
147 int
148 conf_dispatch(char *line)
149 {
150 	int i, last_match = -1, matched = 0;
151 	char *command, *nline = line;
152 
153 	if (strlen(line) == 0 || line[0] == '#')
154 		return E_CONF_OK;
155 	command = NextCommand(nline);
156 	for (i = 0; main_commands[i].func != NULL; i++)
157 		if (strncasecmp(main_commands[i].com, command,
158 		    strlen(command)) == 0) {
159 			matched++;
160 			last_match = i;
161 		}
162 	if (matched == 0)
163 		return E_CONF_NOMATCH;
164 	else if (matched > 1)
165 		return E_CONF_AMBIGUOUS;
166 
167 	if (checkeol(nline) != 0)
168 		return E_CONF_PARAM;
169 	return main_commands[last_match].func(nline);
170 }
171 
172 /*
173  * Checks if a line is terminated or else if it contains
174  * a start block bracket. If it's semicolon terminated
175  * then trim it.
176  */
177 int
178 checkeol(char *line)
179 {
180 	size_t len = strlen(line);
181 	if (len > 0 && line[len - 1] == ';') {
182 		line[len - 1] = '\0';
183 		return 0;
184 	}
185 	for (size_t i = 0; i < len; i++)
186 		if (line[i] == '{')
187 			return 0;
188 	return -1;
189 }
190 
191 /*
192  * Sets hello time
193  */
194 int
195 Fhellotime(char *line)
196 {
197 	int ht = atoi(line);
198 	if (ht <= 0)
199 		return E_CONF_PARAM;
200 	ldp_hello_time = ht;
201 	return 0;
202 }
203 
204 /*
205  * Sets command port
206  */
207 int
208 Fport(char *line)
209 {
210 	int cp = atoi(line);
211 	if (cp <= 0 || cp > 65535)
212 		return E_CONF_PARAM;
213 	command_port = cp;
214 	return 0;
215 }
216 
217 /*
218  * Sets neighbour keepalive
219  */
220 int
221 Fkeepalive(char *line)
222 {
223 	int kt = atoi(line);
224 	if (kt <= 0)
225 		return E_CONF_PARAM;
226 	ldp_keepalive_time = kt;
227 	return 0;
228 }
229 
230 /*
231  * Sets neighbour holddown timer
232  */
233 int
234 Fholddown(char *line)
235 {
236 	int hdt = atoi(line);
237 	if (hdt <= 0)
238 		return E_CONF_PARAM;
239 	ldp_holddown_time = hdt;
240 	return 0;
241 }
242 
243 int
244 Fminlabel(char *line)
245 {
246 	int ml = atoi(line);
247 	if (ml <= 0)
248 		return E_CONF_PARAM;
249 	min_label = ml;
250 	return 0;
251 }
252 
253 int
254 Fmaxlabel(char *line)
255 {
256 	int ml = atoi(line);
257 	if (ml <= 0)
258 		return E_CONF_PARAM;
259 	max_label = ml;
260 	return 0;
261 }
262 
263 int
264 Fldpid(char *line)
265 {
266 	if (inet_pton(AF_INET, line, &conf_ldp_id) != 1)
267 		return E_CONF_PARAM;
268 	return 0;
269 }
270 
271 int
272 Fneighbour(char *line)
273 {
274 	char *peer;
275 	struct conf_neighbour *nei;
276 	struct in_addr ad;
277 	char buf[1024];
278 
279 	peer = NextCommand(line);
280 	if (inet_pton(AF_INET, peer, &ad) != 1)
281 		return E_CONF_PARAM;
282 
283 	nei = calloc(1, sizeof(*nei));
284 	if (nei == NULL)
285 		return E_CONF_MEM;
286 	nei->address.s_addr = ad.s_addr;
287 	SLIST_INSERT_HEAD(&conei_head, nei, neilist);
288 
289 	while (conf_readline(buf, sizeof(buf)) >= 0) {
290 		if (buf[0] == '}')
291 			return 0;
292 		if (Gneighbour(nei, buf) == -1)
293 			return -1;
294 	}
295 	return -1;
296 }
297 
298 /*
299  * neighbour { } sub-commands
300  */
301 int
302 Gneighbour(struct conf_neighbour *nei, char *line)
303 {
304 	if (strncasecmp("authenticate", line, 12) == 0) {
305 		nei->authenticate = 1;
306 		return 0;
307 	}
308 	return -1;
309 }
310 
311 int
312 Fnodefault(char *line)
313 {
314 	int nd = atoi(line);
315 	if (nd < 0)
316 		return E_CONF_PARAM;
317 	no_default_route = nd;
318 	return 0;
319 }
320 
321 int
322 Floopdetection(char *line)
323 {
324 	int loopd = atoi(line);
325 	if (loopd < 0)
326 		return E_CONF_PARAM;
327 	loop_detection = loopd;
328 	return 0;
329 }
330 
331 int
332 Fpassiveif(char *line)
333 {
334 	struct passive_if *pif;
335 
336 	if (strlen(line) > IF_NAMESIZE - 1)
337 		return E_CONF_PARAM;
338 	pif = calloc(1, sizeof(*pif));
339 	strlcpy(pif->if_name, line, IF_NAMESIZE);
340 	SLIST_INSERT_HEAD(&passifs_head, pif, listentry);
341 	return 0;
342 }
343