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