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