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