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