1 /*------------------------------------------------------------------------------
2  *
3  * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4  * The YADIFA TM software product is provided under the BSD 3-clause license:
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  *        * Redistributions of source code must retain the above copyright
11  *          notice, this list of conditions and the following disclaimer.
12  *        * Redistributions in binary form must reproduce the above copyright
13  *          notice, this list of conditions and the following disclaimer in the
14  *          documentation and/or other materials provided with the distribution.
15  *        * Neither the name of EURid nor the names of its contributors may be
16  *          used to endorse or promote products derived from this software
17  *          without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  *------------------------------------------------------------------------------
32  *
33  */
34 
35 /** @defgroup
36  *  @ingroup
37  *  @brief
38  *
39  *
40  *
41  * @{
42  *
43  *----------------------------------------------------------------------------*/
44 #include "dnsdb/dnsdb-config.h"
45 #include <ctype.h>
46 #include <dnscore/format.h>
47 #include <dnscore/fdtools.h>
48 #include <dnscore/serial.h>
49 #include <dnscore/timems.h>
50 #include "dnsdb/zdb-zone-path-provider.h"
51 
52 static ya_result
53 zdb_zone_path_provider_default(const u8* domain_fqdn, char *path_buffer, u32 path_buffer_size, u32 flags);
54 
55 static zdb_zone_path_provider_callback *zdb_zone_path_provider = zdb_zone_path_provider_default;
56 static char *xfr_path = LOCALSTATEDIR "/zones/xfr";
57 static bool xfr_path_free = FALSE;
58 
59 /**
60  * The hash function that gives a number from an ASCIIZ string
61  *
62  * @param p ASCIIZ string
63  *
64  * @return the hash
65  */
66 
67 static u32
zdb_zone_path_provider_copy_hash(const u8 * p)68 zdb_zone_path_provider_copy_hash(const u8 *p)
69 {
70     u32 h = 0;
71     u32 c;
72     u8 s = 0;
73     do
74     {
75         c = toupper(*p++);
76         c &= 0x3f;
77         h += c << (s & 15);
78         h += 97;
79         s += 13;
80     }
81     while(c != 0);
82 
83     return h;
84 }
85 
86 /**
87  *
88  * Returns the hashed folder path for a zone.
89  *
90  * @param data_path             the target buffer for the data path
91  * @param data_path_size        the target buffer size
92  * @param base_data_path        the base folder
93  * @param origin                the origin of the zone
94  *
95  * @return
96  */
97 
98 static ya_result
zdb_zone_path_provider_get_data_path(char * data_path,u32 data_path_size,const char * base_data_path,const u8 * origin)99 zdb_zone_path_provider_get_data_path(char *data_path, u32 data_path_size, const char *base_data_path, const u8 *origin)
100 {
101     u32 h = zdb_zone_path_provider_copy_hash(origin);
102 
103     return snformat(data_path, data_path_size, "%s/%02x/%02x", base_data_path, h & 0xff, (h >> 8) & 0xff);
104 }
105 
106 /**
107  * For backward compatibility
108  *
109  * @param path
110  */
111 
112 void
journal_set_xfr_path(const char * path)113 journal_set_xfr_path(const char *path)
114 {
115     if(xfr_path_free)
116     {
117         free((char*)xfr_path);
118     }
119 
120     if(path == NULL)
121     {
122         xfr_path = LOCALSTATEDIR "/xfr";
123         xfr_path_free = FALSE;
124     }
125     else
126     {
127         xfr_path = strdup(path);
128         xfr_path_free = TRUE;
129     }
130 }
131 
132 /**
133  * For backward compatibility
134  */
135 
136 const char*
journal_get_xfr_path()137 journal_get_xfr_path()
138 {
139     return xfr_path;
140 }
141 
142 static ya_result
zdb_zone_path_provider_default(const u8 * domain_fqdn,char * path_buffer,u32 path_buffer_size,u32 flags)143 zdb_zone_path_provider_default(const u8* domain_fqdn, char *path_buffer, u32 path_buffer_size, u32 flags)
144 {
145     ya_result ret;
146     char *suffix = "";
147     char dir_path[PATH_MAX];
148 
149     if((flags & ZDB_ZONE_PATH_PROVIDER_RNDSUFFIX) != 0)
150     {
151         flags &= ~ZDB_ZONE_PATH_PROVIDER_RNDSUFFIX;
152         suffix = ".part";
153     }
154 
155     if(FAIL(ret = zdb_zone_path_provider_get_data_path(dir_path, sizeof(dir_path), xfr_path, domain_fqdn))) // default path provider
156     {
157         return ret;
158     }
159 
160     if((flags & ZDB_ZONE_PATH_PROVIDER_MKDIR) != 0)
161     {
162         flags &= ~ZDB_ZONE_PATH_PROVIDER_MKDIR;
163 
164         if(FAIL(ret = mkdir_ex(dir_path, 0755, 0)))
165         {
166             return ret;
167         }
168     }
169 
170     switch(flags)
171     {
172         case ZDB_ZONE_PATH_PROVIDER_ZONE_FILE:
173         {
174             ret = snformat(path_buffer, path_buffer_size, "%s/%{dnsname}%s", dir_path, domain_fqdn, suffix);
175             break;
176         }
177         case ZDB_ZONE_PATH_PROVIDER_ZONE_PATH:
178         {
179             ret = snformat(path_buffer, path_buffer_size, "%s", dir_path);
180             break;
181         }
182         case ZDB_ZONE_PATH_PROVIDER_DNSKEY_PATH:
183         {
184             ret = snformat(path_buffer, path_buffer_size, "%s/keys", dir_path);
185             break;
186         }
187         default:
188         {
189             ret = INVALID_ARGUMENT_ERROR;    // no handled flags have been used
190         }
191     }
192 
193     return ret;
194 }
195 
196 /**
197  * Sets the provider.
198  * Note that the provider should return the length of the strings it returns.
199  *
200  * @param provider the provider or NULL to reset to the default one.
201  */
202 
203 void
zdb_zone_path_set_provider(zdb_zone_path_provider_callback * provider)204 zdb_zone_path_set_provider(zdb_zone_path_provider_callback *provider)
205 {
206     if(provider == NULL)
207     {
208         provider = zdb_zone_path_provider_default;
209     }
210 
211     zdb_zone_path_provider = provider;
212 }
213 
214 /**
215  *
216  * @return
217  */
218 
219 static ya_result zdb_zone_info_provider_data_default(const u8 *origin, zdb_zone_info_provider_data *data, u32 flags);
220 
221 static zdb_zone_info_provider_callback *zdb_zone_info_provider = zdb_zone_info_provider_data_default;
222 
zdb_zone_info_provider_data_default(const u8 * origin,zdb_zone_info_provider_data * data,u32 flags)223 static ya_result zdb_zone_info_provider_data_default(const u8 *origin, zdb_zone_info_provider_data *data, u32 flags)
224 {
225     (void)origin;
226     (void)data;
227     (void)flags;
228 
229     return FEATURE_NOT_IMPLEMENTED_ERROR;
230 }
231 
232 zdb_zone_path_provider_callback *
zdb_zone_path_get_provider()233 zdb_zone_path_get_provider()
234 {
235     return zdb_zone_path_provider;
236 }
237 
238 void
zdb_zone_info_set_provider(zdb_zone_info_provider_callback * data)239 zdb_zone_info_set_provider(zdb_zone_info_provider_callback *data)
240 {
241     if(data == NULL)
242     {
243         data = zdb_zone_info_provider_data_default;
244     }
245 
246     zdb_zone_info_provider = data;
247 }
248 
249 zdb_zone_info_provider_callback *
zdb_zone_info_get_provider()250 zdb_zone_info_get_provider()
251 {
252     return zdb_zone_info_provider;
253 }
254 
255 ya_result
zdb_zone_info_get_stored_serial(const u8 * origin,u32 * serial)256 zdb_zone_info_get_stored_serial(const u8 *origin, u32 *serial)
257 {
258     yassert(origin != NULL);
259     yassert(serial != NULL);
260     zdb_zone_info_provider_data data;
261     ya_result ret;
262     if(ISOK(ret = zdb_zone_info_get_provider()(origin, &data, ZDB_ZONE_INFO_PROVIDER_STORED_SERIAL)))
263     {
264         *serial = data._u32; // VS false positive: reaching this point, data is initialized (by contract)
265     }
266     return ret;
267 }
268 
269 ya_result
zdb_zone_info_get_zone_max_journal_size(const u8 * origin,u32 * size)270 zdb_zone_info_get_zone_max_journal_size(const u8 *origin, u32 *size)
271 {
272     yassert(origin != NULL);
273     yassert(size != NULL);
274     zdb_zone_info_provider_data data;
275     data._u64 = *size;      // known wire size / 2
276     ya_result ret;
277     if(ISOK(ret = zdb_zone_info_get_provider()(origin, &data, ZDB_ZONE_INFO_PROVIDER_MAX_JOURNAL_SIZE)))
278     {
279         if(data._u64 > MAX_U32)
280         {
281             data._u64 = MAX_U32;
282         }
283 
284         /// @note THX: here, if data._u64 is < 256*1024, then set to 256*1024 .
285 
286         *size = data._u64;
287     }
288     return ret;
289 }
290 
291 ya_result
zdb_zone_info_get_zone_type(const u8 * origin,u8 * zt)292 zdb_zone_info_get_zone_type(const u8 *origin, u8 *zt)
293 {
294     yassert(origin != NULL);
295     yassert(zt != NULL);
296     zdb_zone_info_provider_data data;
297     ya_result ret;
298     if(ISOK(ret = zdb_zone_info_get_provider()(origin, &data, ZDB_ZONE_INFO_PROVIDER_ZONE_TYPE)))
299     {
300         *zt = data._u8; // VS false positive: reaching this point, data is initialized (by contract)
301     }
302     return ret;
303 }
304 
305 ya_result
zdb_zone_info_background_store_zone(const u8 * origin)306 zdb_zone_info_background_store_zone(const u8 *origin)
307 {
308     yassert(origin != NULL);
309     ya_result ret;
310 
311     ret = zdb_zone_info_get_provider()(origin, NULL, ZDB_ZONE_INFO_PROVIDER_STORE_TRIGGER);
312 
313     return ret;
314 }
315 
316 ya_result
zdb_zone_info_store_locked_zone(const u8 * origin)317 zdb_zone_info_store_locked_zone(const u8 *origin)
318 {
319     yassert(origin != NULL);
320     ya_result ret;
321 
322     zdb_zone_info_provider_data already_locked_by;
323     already_locked_by._u8 = 0;
324     ret = zdb_zone_info_get_provider()(origin, &already_locked_by, ZDB_ZONE_INFO_PROVIDER_STORE_NOW);
325 
326     return ret;
327 }
328 
329 /**
330  *
331  * Should not be used anymore.
332  *
333  * @param origin
334  * @param minimum_serial
335  * @return
336  */
337 
338 ya_result
zdb_zone_info_background_store_zone_and_wait_for_serial(const u8 * origin,u32 minimum_serial)339 zdb_zone_info_background_store_zone_and_wait_for_serial(const u8 *origin, u32 minimum_serial)
340 {
341     // This mechanism should be improved : the zone should be unlocked, frozen, saved, unfrozen, re-locked
342 
343     yassert(origin != NULL);
344     ya_result ret;
345 
346     ret = zdb_zone_info_get_provider()(origin, NULL, ZDB_ZONE_INFO_PROVIDER_STORE_TRIGGER);
347 
348     if(ISOK(ret))
349     {
350         u64 start = timeus();
351 
352         for(;;)
353         {
354             u32 serial;
355             if(FAIL(ret = zdb_zone_info_get_stored_serial(origin, &serial)))
356             {
357                 return ret;
358             }
359             if(serial_ge(serial, minimum_serial))
360             {
361                 return SUCCESS;
362             }
363 
364             u64 now = timeus();
365 
366             if(now < start)
367             {
368                 start = now; //clock modified
369             }
370 
371             if(now - start > ONE_SECOND_US)
372             {
373                 zdb_zone_info_provider_data already_locked_by;
374 
375                 already_locked_by._u8 = 0;
376 
377                 if(FAIL(ret = zdb_zone_info_get_provider()(origin, &already_locked_by, ZDB_ZONE_INFO_PROVIDER_STORE_TRIGGER)))
378                 {
379                     return ret;
380                 }
381             }
382 
383             usleep(500000);
384         }
385     }
386 
387     return ret;
388 }
389 
390 ya_result
zdb_zone_info_background_store_in_progress(const u8 * origin)391 zdb_zone_info_background_store_in_progress(const u8 *origin)
392 {
393     // This mechanism should be improved : the zone should be unlocked, frozen, saved, unfrozen, re-locked
394 
395     yassert(origin != NULL);
396     ya_result ret;
397 
398     ret = zdb_zone_info_get_provider()(origin, NULL, ZDB_ZONE_INFO_PROVIDER_STORE_IN_PROGRESS);
399 
400     return ret;
401 }
402 
403 /** @} */
404