update to 9.7.2rc1
[tridge/bind9.git] / contrib / zkt / ncparse.c
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 */
67 static 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
90 static  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
102 static  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
114 static  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 *****************************************************************/
196 int     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
298 int     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
311 char    *progname;
312
313 main (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