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