1/*****************************************************************
2**
3**	@(#) zone.c  (c) Mar 2005  Holger Zuleger  hznet.de
4**
5**	Copyright (c) Mar 2005, 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 <stdlib.h>
40# include <sys/types.h>
41# include <sys/stat.h>
42# include <dirent.h>
43# include <assert.h>
44#ifdef HAVE_CONFIG_H
45# include <config.h>
46#endif
47# include "config_zkt.h"
48# include "debug.h"
49# include "domaincmp.h"
50# include "misc.h"
51# include "zconf.h"
52# include "dki.h"
53#define	extern
54# include "zone.h"
55#undef	extern
56
57/*****************************************************************
58**	private (static) function declaration and definition
59*****************************************************************/
60static	char	zone_estr[255+1];
61
62/*****************************************************************
63**	zone_alloc ()
64*****************************************************************/
65static	zone_t	*zone_alloc ()
66{
67	zone_t	*zp;
68
69	if ( (zp = malloc (sizeof (zone_t))) )
70	{
71		memset (zp, 0, sizeof (zone_t));
72		return zp;
73	}
74
75	snprintf (zone_estr, sizeof (zone_estr),
76			"zone_alloc: Out of memory");
77	return NULL;
78}
79
80/*****************************************************************
81**	zone_cmp () 	return <0 | 0 | >0
82*****************************************************************/
83static	int	zone_cmp (const zone_t *a, const zone_t *b)
84{
85	if ( a == NULL ) return -1;
86	if ( b == NULL ) return 1;
87
88	return domaincmp (a->zone, b->zone);
89}
90
91
92/*****************************************************************
93**	public function definition
94*****************************************************************/
95
96/*****************************************************************
97**	zone_free ()
98*****************************************************************/
99void	zone_free (zone_t *zp)
100{
101	assert (zp != NULL);
102
103	if ( zp->zone ) free ((char *)zp->zone);
104	if ( zp->dir ) free ((char *)zp->dir);
105	if ( zp->file ) free ((char *)zp->file);
106	if ( zp->sfile ) free ((char *)zp->sfile);
107#if 0
108	/* TODO: actually there are some problems freeing the config :-( */
109	if ( zp->conf ) free ((zconf_t *)zp->conf);
110#endif
111	if ( zp->keys ) dki_freelist (&zp->keys);
112	free (zp);
113}
114
115/*****************************************************************
116**	zone_freelist ()
117*****************************************************************/
118void	zone_freelist (zone_t **listp)
119{
120	zone_t	*curr;
121	zone_t	*next;
122
123	assert (listp != NULL);
124
125	curr = *listp;
126	while ( curr )
127	{
128		next = curr->next;
129		zone_free (curr);
130		curr = next;
131	}
132	if ( *listp )
133		*listp = NULL;
134}
135
136/*****************************************************************
137**	zone_new ()
138**	allocate memory for new zone structure and initialize it
139*****************************************************************/
140zone_t	*zone_new (zone_t **zp, const char *zone, const char *dir, const char *file, const char *signed_ext, const zconf_t *cp)
141{
142	char	path[MAX_PATHSIZE+1];
143	zone_t	*new;
144
145	assert (zp != NULL);
146	assert (zone != NULL && *zone != '\0');
147
148	dbg_val3 ("zone_new: (zp, zone: %s, dir: %s, file: %s, cp)\n", zone, dir, file);
149	if ( dir == NULL || *dir == '\0' )
150		dir = ".";
151
152	if ( file == NULL || *file == '\0' )
153		file = cp->zonefile;
154	else
155	{	/* check if file contains a path */
156		const	char	*p;
157		if ( (p = strrchr (file, '/')) != NULL )
158		{
159			snprintf (path, sizeof (path), "%s/%.*s", dir, p-file, file);
160			dir = path;
161			file = p+1;
162		}
163	}
164
165	if ( (new = zone_alloc ()) != NULL )
166	{
167		char	*p;
168
169		new->zone = domain_canonicdup (zone);
170		new->dir = strdup (dir);
171		new->file = strdup (file);
172		/* check if file ends with ".signed" ? */
173		if ( (p = strrchr (new->file, '.')) != NULL && strcmp (p, signed_ext) == 0 )
174		{
175			new->sfile = strdup (new->file);
176			*p = '\0';
177		}
178		else
179		{
180			snprintf (path, sizeof (path), "%s%s", file, signed_ext);
181			new->sfile = strdup (path);
182		}
183		new->conf = cp;
184		new->keys = NULL;
185		dki_readdir (new->dir, &new->keys, 0);
186		new->next = NULL;
187	}
188
189	return zone_add (zp, new);
190}
191
192/*****************************************************************
193**	zone_readdir ()
194*****************************************************************/
195int	zone_readdir (const char *dir, const char *zone, const char *zfile, zone_t **listp, const zconf_t *conf, int dyn_zone)
196{
197	char	*p;
198	char	path[MAX_PATHSIZE+1];
199	char	*signed_ext = ".signed";
200	zconf_t	*localconf = NULL;
201
202	assert (dir != NULL && *dir != '\0');
203	assert (conf != NULL);
204
205	if ( zone == NULL )	/* zone not given ? */
206	{
207		if ( (zone = strrchr (dir, '/')) )	/* try to extract zone name out of directory */
208			zone++;
209		else
210			zone = dir;
211	}
212	if ( zone == NULL )	/* zone name still null ? */
213		return 0;
214
215	dbg_val4 ("zone_readdir: (dir: \"%s\", zone: \"%s\", zfile: \"%s\", zp, cp, dyn_zone = %d)\n",
216					dir, zone, zfile ? zfile: "NULL", dyn_zone);
217
218	if ( dyn_zone )
219		signed_ext = ".dsigned";
220
221	if ( zfile && (p = strrchr (zfile, '/')) )	/* check if zfile contains a directory */
222	{
223		char	subdir[MAX_PATHSIZE+1];
224
225		snprintf (subdir, sizeof (subdir), "%s/%.*s", dir, p - zfile, zfile);
226		pathname (path, sizeof (path), subdir, LOCALCONF_FILE, NULL);
227	}
228	else
229		pathname (path, sizeof (path), dir, LOCALCONF_FILE, NULL);
230	dbg_val1 ("zone_readdir: check local config file %s\n", path);
231	if ( fileexist (path) )			/* load local config file */
232	{
233		localconf = dupconfig (conf);
234		conf = loadconfig (path, localconf);
235		/* do not free localconf, because a ptr to it will be added to the zone by zone_new() */
236	}
237
238	if ( zfile == NULL )
239	{
240		zfile = conf->zonefile;
241		pathname (path, sizeof (path), dir, zfile, signed_ext);
242	}
243	else
244	{
245		dbg_val2("zone_readdir: add %s to zonefile if not already there ? (%s)\n", signed_ext, zfile);
246		if ( (p = strrchr (zfile, '.')) == NULL || strcmp (p, signed_ext) != 0 )
247			pathname (path, sizeof (path), dir, zfile, signed_ext);
248		else
249			pathname (path, sizeof (path), dir, zfile, NULL);
250	}
251
252	dbg_val1("zone_readdir: fileexist (%s): ", path);
253	if ( !fileexist (path) )	/* no .signed file found ? ... */
254	{
255		dbg_val0("no!\n");
256		return 0;		/* ... not a secure zone ! */
257	}
258	dbg_val0("yes!\n");
259
260	dbg_val("zone_readdir: add zone (%s)\n", zone);
261	zone_new (listp, zone, dir, zfile, signed_ext, conf);
262
263	return 1;
264}
265
266
267/*****************************************************************
268**	zone_geterrstr ()
269**	return error string
270*****************************************************************/
271const	char	*zone_geterrstr ()
272{
273	return zone_estr;
274}
275
276/*****************************************************************
277**	zone_add ()
278*****************************************************************/
279zone_t	*zone_add (zone_t **list, zone_t *new)
280{
281	zone_t	*curr;
282	zone_t	*last;
283
284	if ( list == NULL )
285		return NULL;
286	if ( new == NULL )
287		return *list;
288
289	last = curr = *list;
290	while ( curr && zone_cmp (curr, new) < 0 )
291	{
292		last = curr;
293		curr = curr->next;
294	}
295
296	if ( curr == *list )	/* add node at the begining of the list */
297		*list = new;
298	else			/* add node at end or between two nodes */
299		last->next = new;
300	new->next = curr;
301
302	return new;
303}
304
305/*****************************************************************
306**	zone_search ()
307*****************************************************************/
308const zone_t	*zone_search (const zone_t *list, const char *zone)
309{
310	if ( zone == NULL || *zone == '\0' )
311		return NULL;
312
313	while ( list && strcmp (zone, list->zone) != 0 )
314		list = list->next;
315
316	return list;
317}
318
319/*****************************************************************
320**	zone_print ()
321*****************************************************************/
322int	zone_print (const char *mesg, const zone_t *z)
323{
324	dki_t	*dkp;
325
326	if ( !z )
327		return 0;
328	fprintf (stderr, "%s: zone\t %s\n", mesg, z->zone);
329	fprintf (stderr, "%s: dir\t %s\n", mesg, z->dir);
330	fprintf (stderr, "%s: file\t %s\n", mesg, z->file);
331	fprintf (stderr, "%s: sfile\t %s\n", mesg, z->sfile);
332
333	for ( dkp = z->keys; dkp; dkp = dkp->next )
334        {
335                dki_prt_comment (dkp, stderr);
336        }
337
338	return 1;
339}
340