1/***************************************************************** 2** 3** @(#) ncparse.c -- A very simple named.conf parser 4** 5** Copyright (c) Apr 2005 - Nov 2007, Holger Zuleger HZnet. All rights reserved. 6** 7** This software is open source. 8** 9** Redistribution and use in source and binary forms, with or without 10** modification, are permitted provided that the following conditions 11** are met: 12** 13** Redistributions of source code must retain the above copyright notice, 14** this list of conditions and the following disclaimer. 15** 16** Redistributions in binary form must reproduce the above copyright notice, 17** this list of conditions and the following disclaimer in the documentation 18** and/or other materials provided with the distribution. 19** 20** Neither the name of Holger Zuleger HZnet nor the names of its contributors may 21** be used to endorse or promote products derived from this software without 22** specific prior written permission. 23** 24** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 28** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34** POSSIBILITY OF SUCH DAMAGE. 35** 36*****************************************************************/ 37# include <stdio.h> 38# include <string.h> 39# include <ctype.h> 40# include <assert.h> 41# include "debug.h" 42# include "misc.h" 43# include "log.h" 44#define extern 45# include "ncparse.h" 46#undef extern 47 48# define TOK_STRING 257 49# define TOK_DIR 258 50# define TOK_INCLUDE 259 51 52# define TOK_ZONE 260 53# define TOK_TYPE 261 54# define TOK_MASTER 262 55# define TOK_SLAVE 263 56# define TOK_STUB 264 57# define TOK_HINT 265 58# define TOK_FORWARD 266 59# define TOK_DELEGATION 267 60# define TOK_VIEW 268 61 62# define TOK_FILE 270 63 64# define TOK_UNKNOWN 511 65 66/* list of "named.conf" keywords we are interested in */ 67static struct KeyWords { 68 char *name; 69 int tok; 70} kw[] = { 71 { "STRING", TOK_STRING }, 72 { "include", TOK_INCLUDE }, 73 { "directory", TOK_DIR }, 74 { "file", TOK_FILE }, 75 { "zone", TOK_ZONE }, 76#if 0 /* we don't need the type keyword; master, slave etc. is sufficient */ 77 { "type", TOK_TYPE }, 78#endif 79 { "master", TOK_MASTER }, 80 { "slave", TOK_SLAVE }, 81 { "stub", TOK_STUB }, 82 { "hint", TOK_HINT }, 83 { "forward", TOK_FORWARD }, 84 { "delegation-only", TOK_DELEGATION }, 85 { "view", TOK_VIEW }, 86 { NULL, TOK_UNKNOWN }, 87}; 88 89#ifdef DBG 90static const char *tok2str (int tok) 91{ 92 int i; 93 94 i = 0; 95 while ( kw[i].name && kw[i].tok != tok ) 96 i++; 97 98 return kw[i].name; 99} 100#endif 101 102static int searchkw (const char *keyword) 103{ 104 int i; 105 106 dbg_val ("ncparse: searchkw (%s)\n", keyword); 107 i = 0; 108 while ( kw[i].name && strcmp (kw[i].name, keyword) != 0 ) 109 i++; 110 111 return kw[i].tok; 112} 113 114static int gettok (FILE *fp, char *val, size_t valsize) 115{ 116 int lastc; 117 int c; 118 char buf[255+1]; 119 char *p; 120 char *bufend; 121 122 *val = '\0'; 123 do { 124 while ( (c = getc (fp)) != EOF && isspace (c) ) 125 ; 126 127 if ( c == '#' ) /* single line comment ? */ 128 { 129 while ( (c = getc (fp)) != EOF && c != '\n' ) 130 ; 131 continue; 132 } 133 134 if ( c == EOF ) 135 return EOF; 136 137 if ( c == '{' || c == '}' || c == ';' ) 138 continue; 139 140 if ( c == '/' ) /* begin of C comment ? */ 141 { 142 if ( (c = getc (fp)) == '*' ) /* yes! */ 143 { 144 lastc = EOF; /* read until end of c comment */ 145 while ( (c = getc (fp)) != EOF && !(lastc == '*' && c == '/') ) 146 lastc = c; 147 } 148 else if ( c == '/' ) /* is it a C single line comment ? */ 149 { 150 while ( (c = getc (fp)) != EOF && c != '\n' ) 151 ; 152 } 153 else /* no ! */ 154 ungetc (c, fp); 155 continue; 156 } 157 158 if ( c == '\"' ) 159 { 160 p = val; 161 bufend = val + valsize - 1; 162 while ( (c = getc (fp)) != EOF && p < bufend && c != '\"' ) 163 *p++ = c; 164 *p = '\0'; 165 /* if string buffer is too small, eat up rest of string */ 166 while ( c != EOF && c != '\"' ) 167 c = getc (fp); 168 169 return TOK_STRING; 170 } 171 172 p = buf; 173 bufend = buf + sizeof (buf) - 1; 174 do 175 *p++ = tolower (c); 176 while ( (c = getc (fp)) != EOF && p < bufend && (isalpha (c) || c == '-') ); 177 *p = '\0'; 178 ungetc (c, fp); 179 180 if ( (c = searchkw (buf)) != TOK_UNKNOWN ) 181 return c; 182 } while ( c != EOF ); 183 184 return EOF; 185} 186 187/***************************************************************** 188** 189** parse_namedconf (const char *filename, chroot_dir, dir, dirsize, int (*func) ()) 190** 191** Very dumb named.conf parser. 192** - In a zone declaration the _first_ keyword MUST be "type" 193** - For every master zone "func (directory, zone, filename)" will be called 194** 195*****************************************************************/ 196int parse_namedconf (const char *filename, const char *chroot_dir, char *dir, size_t dirsize, int (*func) ()) 197{ 198 FILE *fp; 199 int tok; 200 char path[511+1]; 201#if 1 /* this is potentialy too small for key data, but we don't need the keys... */ 202 char strval[255+1]; 203#else 204 char strval[4095+1]; 205#endif 206 char view[255+1]; 207 char zone[255+1]; 208 char zonefile[255+1]; 209 210 dbg_val ("parse_namedconf: parsing file \"%s\" \n", filename); 211 212 assert (filename != NULL); 213 assert (dir != NULL && dirsize != 0); 214 assert (func != NULL); 215 216 view[0] = '\0'; 217 if ( (fp = fopen (filename, "r")) == NULL ) 218 return 0; 219 220 while ( (tok = gettok (fp, strval, sizeof strval)) != EOF ) 221 { 222 if ( tok > 0 && tok < 256 ) 223 { 224 error ("parse_namedconf: token found with value %-10d: %c\n", tok, tok); 225 lg_mesg (LG_ERROR, "parse_namedconf: token found with value %-10d: %c", tok, tok); 226 } 227 else if ( tok == TOK_DIR ) 228 { 229 if ( gettok (fp, strval, sizeof (strval)) == TOK_STRING ) 230 { 231 dbg_val2 ("parse_namedconf: directory found \"%s\" (dir is %s)\n", 232 strval, dir); 233 if ( *strval != '/' && *dir ) 234 snprintf (path, sizeof (path), "%s/%s", dir, strval); 235 else 236 snprintf (path, sizeof (path), "%s", strval); 237 238 /* prepend chroot directory (do it only once) */ 239 if ( chroot_dir && *chroot_dir ) 240 { 241 snprintf (dir, dirsize, "%s%s%s", chroot_dir, *path == '/' ? "": "/", path); 242 chroot_dir = NULL; 243 } 244 else 245 snprintf (dir, dirsize, "%s", path); 246 dbg_val ("parse_namedconf: new dir \"%s\" \n", dir); 247 } 248 } 249 else if ( tok == TOK_INCLUDE ) 250 { 251 if ( gettok (fp, strval, sizeof (strval)) == TOK_STRING ) 252 { 253 if ( *strval != '/' && *dir ) 254 snprintf (path, sizeof (path), "%s/%s", dir, strval); 255 else 256 snprintf (path, sizeof (path), "%s", strval); 257 if ( !parse_namedconf (path, chroot_dir, dir, dirsize, func) ) 258 return 0; 259 } 260 else 261 { 262 error ("parse_namedconf: need a filename after \"include\"!\n"); 263 lg_mesg (LG_ERROR, "parse_namedconf: need a filename after \"include\"!"); 264 } 265 } 266 else if ( tok == TOK_VIEW ) 267 { 268 if ( gettok (fp, strval, sizeof (strval)) != TOK_STRING ) 269 continue; 270 snprintf (view, sizeof view, "%s", strval); /* store the name of the view */ 271 } 272 else if ( tok == TOK_ZONE ) 273 { 274 if ( gettok (fp, strval, sizeof (strval)) != TOK_STRING ) 275 continue; 276 snprintf (zone, sizeof zone, "%s", strval); /* store the name of the zone */ 277 278 if ( gettok (fp, strval, sizeof (strval)) != TOK_MASTER ) 279 continue; 280 if ( gettok (fp, strval, sizeof (strval)) != TOK_FILE ) 281 continue; 282 if ( gettok (fp, strval, sizeof (strval)) != TOK_STRING ) 283 continue; 284 snprintf (zonefile, sizeof zonefile, "%s", strval); /* this is the filename */ 285 286 dbg_val4 ("dir %s view %s zone %s file %s\n", dir, view, zone, zonefile); 287 (*func) (dir, view, zone, zonefile); 288 } 289 else 290 dbg_val3 ("%-10s(%d): %s\n", tok2str(tok), tok, strval); 291 } 292 fclose (fp); 293 294 return 1; 295} 296 297#ifdef TEST_NCPARSE 298int printzone (const char *dir, const char *view, const char *zone, const char *file) 299{ 300 printf ("printzone "); 301 printf ("view \"%s\" " , view); 302 printf ("zone \"%s\" " , zone); 303 printf ("file "); 304 if ( dir && *dir ) 305 printf ("%s/", dir, file); 306 printf ("%s", file); 307 putchar ('\n'); 308 return 1; 309} 310 311char *progname; 312 313main (int argc, char *argv[]) 314{ 315 char directory[255+1]; 316 317 progname = argv[0]; 318 319 directory[0] = '\0'; 320 if ( --argc == 0 ) 321 parse_namedconf ("/var/named/named.conf", NULL, directory, sizeof (directory), printzone); 322 else 323 parse_namedconf (argv[1], NULL, directory, sizeof (directory), printzone); 324} 325#endif 326