OpenDNSSEC-signer  1.4.7
util.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009 NLNet Labs. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
32 #include "config.h"
33 #include "shared/file.h"
34 #include "shared/log.h"
35 #include "shared/util.h"
36 
37 #include <fcntl.h>
38 #include <ldns/ldns.h>
39 #include <signal.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <time.h>
43 #include <unistd.h>
44 
45 static const char* util_str = "util";
46 
47 
52 int
53 util_is_dnssec_rr(ldns_rr* rr)
54 {
55  ldns_rr_type type = 0;
56  if (!rr) {
57  return 0;
58  }
59  type = ldns_rr_get_type(rr);
60  return (type == LDNS_RR_TYPE_RRSIG ||
61  type == LDNS_RR_TYPE_NSEC ||
62  type == LDNS_RR_TYPE_NSEC3 ||
63  type == LDNS_RR_TYPE_NSEC3PARAMS);
64 }
65 
66 
71 int
72 util_serial_gt(uint32_t serial_new, uint32_t serial_old)
73 {
74  return DNS_SERIAL_GT(serial_new, serial_old);
75 }
76 
77 
82 int
83 util_soa_compare_rdata(ldns_rr* rr1, ldns_rr* rr2)
84 {
85  size_t i = 0;
86  size_t rdata_count = SE_SOA_RDATA_MINIMUM;
87  for (i = 0; i <= rdata_count; i++) {
88  if (i != SE_SOA_RDATA_SERIAL &&
89  ldns_rdf_compare(ldns_rr_rdf(rr1, i), ldns_rr_rdf(rr2, i)) != 0) {
90  return 1;
91  }
92  }
93  return 0;
94 }
95 
96 
101 int
102 util_soa_compare(ldns_rr* rr1, ldns_rr* rr2)
103 {
104  size_t rr1_len = 0;
105  size_t rr2_len = 0;
106  size_t offset = 0;
107  if (!rr1 || !rr2) {
108  return 1;
109  }
110  rr1_len = ldns_rr_uncompressed_size(rr1);
111  rr2_len = ldns_rr_uncompressed_size(rr2);
112  if (ldns_dname_compare(ldns_rr_owner(rr1), ldns_rr_owner(rr2)) != 0) {
113  return 1;
114  }
115  if (ldns_rr_get_class(rr1) != ldns_rr_get_class(rr2)) {
116  return 1;
117  }
118  if (ldns_rr_get_type(rr1) != LDNS_RR_TYPE_SOA) {
119  return 1;
120  }
121  if (ldns_rr_get_type(rr1) != ldns_rr_get_type(rr2)) {
122  return 1;
123  }
124  if (offset > rr1_len || offset > rr2_len) {
125  if (rr1_len == rr2_len) {
126  return util_soa_compare_rdata(rr1, rr2);
127  }
128  return 1;
129  }
130  return util_soa_compare_rdata(rr1, rr2);
131 }
132 
133 
134 
139 ldns_status
140 util_dnssec_rrs_compare(ldns_rr* rr1, ldns_rr* rr2, int* cmp)
141 {
142  ldns_status status = LDNS_STATUS_OK;
143  size_t rr1_len;
144  size_t rr2_len;
145  ldns_buffer* rr1_buf;
146  ldns_buffer* rr2_buf;
147 
148  if (!rr1 || !rr2) {
149  return LDNS_STATUS_ERR;
150  }
151  rr1_len = ldns_rr_uncompressed_size(rr1);
152  rr2_len = ldns_rr_uncompressed_size(rr2);
153  rr1_buf = ldns_buffer_new(rr1_len);
154  rr2_buf = ldns_buffer_new(rr2_len);
155  /* name, class and type should already be equal */
156  status = ldns_rr2buffer_wire_canonical(rr1_buf, rr1, LDNS_SECTION_ANY);
157  if (status != LDNS_STATUS_OK) {
158  ldns_buffer_free(rr1_buf);
159  ldns_buffer_free(rr2_buf);
160  /* critical */
161  return status;
162  }
163  status = ldns_rr2buffer_wire_canonical(rr2_buf, rr2, LDNS_SECTION_ANY);
164  if (status != LDNS_STATUS_OK) {
165  ldns_buffer_free(rr1_buf);
166  ldns_buffer_free(rr2_buf);
167  /* critical */
168  return status;
169  }
170  *cmp = ldns_rr_compare_wire(rr1_buf, rr2_buf);
171  ldns_buffer_free(rr1_buf);
172  ldns_buffer_free(rr2_buf);
173  return LDNS_STATUS_OK;
174 }
175 
176 
181 ldns_status
182 util_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr)
183 {
184  int cmp = 0;
185  ldns_dnssec_rrs *new_rrs = NULL;
186  ldns_status status = LDNS_STATUS_OK;
187  uint32_t rr_ttl = 0;
188  uint32_t default_ttl = 0;
189 
190  if (!rrs || !rrs->rr || !rr) {
191  return LDNS_STATUS_ERR;
192  }
193 
194  rr_ttl = ldns_rr_ttl(rr);
195  status = util_dnssec_rrs_compare(rrs->rr, rr, &cmp);
196  if (status != LDNS_STATUS_OK) {
197  /* critical */
198  return status;
199  }
200 
201  if (cmp < 0) {
202  if (rrs->next) {
203  return util_dnssec_rrs_add_rr(rrs->next, rr);
204  } else {
205  new_rrs = ldns_dnssec_rrs_new();
206  new_rrs->rr = rr;
207  rrs->next = new_rrs;
208  default_ttl = ldns_rr_ttl(rrs->rr);
209  if (rr_ttl < default_ttl) {
210  ldns_rr_set_ttl(rrs->rr, rr_ttl);
211  } else {
212  ldns_rr_set_ttl(new_rrs->rr, default_ttl);
213  }
214  return LDNS_STATUS_OK;
215  }
216  } else if (cmp > 0) {
217  /* put the current old rr in the new next, put the new
218  rr in the current container */
219  new_rrs = ldns_dnssec_rrs_new();
220  new_rrs->rr = rrs->rr;
221  new_rrs->next = rrs->next;
222 
223  rrs->rr = rr;
224  rrs->next = new_rrs;
225 
226  default_ttl = ldns_rr_ttl(new_rrs->rr);
227  if (rr_ttl < default_ttl) {
228  ldns_rr_set_ttl(new_rrs->rr, rr_ttl);
229  } else {
230  ldns_rr_set_ttl(rrs->rr, default_ttl);
231  }
232 
233  return LDNS_STATUS_OK;
234  } else {
235  /* should we error on equal? or free memory of rr */
236  ods_log_warning("[%s] adding duplicate RR?", util_str);
237  return LDNS_STATUS_NO_DATA;
238  }
239  return LDNS_STATUS_OK;
240 }
241 
242 
247 static pid_t
248 util_read_pidfile(const char* file)
249 {
250  int fd;
251  pid_t pid;
252  char pidbuf[32];
253  char *t;
254  int l;
255 
256  if ((fd = open(file, O_RDONLY)) == -1) {
257  return -1;
258  }
259  if (((l = read(fd, pidbuf, sizeof(pidbuf)))) == -1) {
260  close(fd);
261  return -1;
262  }
263  close(fd);
264  /* Empty pidfile means no pidfile... */
265  if (l == 0) {
266  errno = ENOENT;
267  return -1;
268  }
269  pid = (pid_t) strtol(pidbuf, &t, 10);
270 
271  if (*t && *t != '\n') {
272  return -1;
273  }
274  return pid;
275 }
276 
277 
282 int
283 util_check_pidfile(const char* pidfile)
284 {
285  pid_t oldpid;
286  struct stat stat_ret;
291  if (stat(pidfile, &stat_ret) != 0) {
292  if (errno != ENOENT) {
293  ods_log_error("[%s] cannot stat pidfile %s: %s", util_str, pidfile,
294  strerror(errno));
295  } /* else: file does not exist: carry on */
296  } else {
297  if (S_ISREG(stat_ret.st_mode)) {
299  if ((oldpid = util_read_pidfile(pidfile)) == -1) {
301  if (errno != ENOENT) {
302  ods_log_error("[%s] cannot read pidfile %s: %s", util_str,
303  pidfile, strerror(errno));
304  }
305  } else {
306  if (kill(oldpid, 0) == 0 || errno == EPERM) {
307  ods_log_crit("[%s] pidfile %s already exists, "
308  "a process with pid %u is already running. "
309  "If no ods-signerd process is running, a previous "
310  "instance didn't shutdown cleanly, please remove this "
311  "file and try again.", util_str, pidfile, oldpid);
312  return 0;
313  } else {
315  ods_log_warning("[%s] pidfile %s already exists, "
316  "but no process with pid %u is running. "
317  "A previous instance didn't shutdown cleanly, this "
318  "pidfile is stale.", util_str, pidfile, oldpid);
319  }
320  }
321  }
322  }
324  return 1;
325 }
326 
327 
332 int
333 util_write_pidfile(const char* pidfile, pid_t pid)
334 {
335  FILE* fd;
336  char pidbuf[32];
337  size_t result = 0, size = 0;
338 
339  ods_log_assert(pidfile);
340  ods_log_assert(pid);
341 
342  ods_log_debug("[%s] writing pid %lu to pidfile %s", util_str,
343  (unsigned long) pid, pidfile);
344  snprintf(pidbuf, sizeof(pidbuf), "%lu\n", (unsigned long) pid);
345  fd = ods_fopen(pidfile, NULL, "w");
346  if (!fd) {
347  return -1;
348  }
349  size = strlen(pidbuf);
350  if (size == 0) {
351  result = 1;
352  } else {
353  result = fwrite((const void*) pidbuf, 1, size, fd);
354  }
355  if (result == 0) {
356  ods_log_error("[%s] write to pidfile %s failed: %s", util_str,
357  pidfile, strerror(errno));
358  } else if (result < size) {
359  ods_log_error("[%s] short write to pidfile %s: disk full?", util_str,
360  pidfile);
361  result = 0;
362  } else {
363  result = 1;
364  }
365  ods_fclose(fd);
366  if (!result) {
367  return -1;
368  }
369  return 0;
370 }
371 
372 
378 util_rr_print(FILE* fd, const ldns_rr* rr)
379 {
380  char* result = NULL;
381  ldns_buffer* tmp_buffer = NULL;
382  ods_status status = ODS_STATUS_OK;
383 
384  if (!fd || !rr) {
385  return ODS_STATUS_ASSERT_ERR;
386  }
387 
388  tmp_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
389  if (!tmp_buffer) {
390  return ODS_STATUS_MALLOC_ERR;
391  }
392  if (ldns_rr2buffer_str_fmt(tmp_buffer, NULL, rr)
393  == LDNS_STATUS_OK) {
394  /* export and return string, destroy rest */
395  result = ldns_buffer2str(tmp_buffer);
396  if (result) {
397  fprintf(fd, "%s", result);
398  status = ODS_STATUS_OK;
399  LDNS_FREE(result);
400  } else {
401  fprintf(fd, "; Unable to convert rr to string\n");
402  status = ODS_STATUS_FWRITE_ERR;
403  }
404  } else {
405  status = ODS_STATUS_FWRITE_ERR;
406  }
407  ldns_buffer_free(tmp_buffer);
408  return status;
409 }
410 
415 size_t
417 {
418  return (((((srcsize + 3) / 4) * 3)) + 1);
419 }
420 
#define DNS_SERIAL_GT(a, b)
Definition: util.h:52
void ods_log_debug(const char *format,...)
Definition: log.c:270
ldns_status util_dnssec_rrs_compare(ldns_rr *rr1, ldns_rr *rr2, int *cmp)
Definition: util.c:140
size_t util_b64_pton_calculate_size(size_t srcsize)
Definition: util.c:416
enum ods_enum_status ods_status
Definition: status.h:90
int util_soa_compare_rdata(ldns_rr *rr1, ldns_rr *rr2)
Definition: util.c:83
void ods_log_error(const char *format,...)
Definition: log.c:334
#define SE_SOA_RDATA_SERIAL
Definition: util.h:47
ods_status util_rr_print(FILE *fd, const ldns_rr *rr)
Definition: util.c:378
FILE * ods_fopen(const char *file, const char *dir, const char *mode)
Definition: file.c:190
int util_serial_gt(uint32_t serial_new, uint32_t serial_old)
Definition: util.c:72
void ods_log_crit(const char *format,...)
Definition: log.c:350
int util_write_pidfile(const char *pidfile, pid_t pid)
Definition: util.c:333
#define SE_SOA_RDATA_MINIMUM
Definition: util.h:49
ldns_status util_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr)
Definition: util.c:182
int util_check_pidfile(const char *pidfile)
Definition: util.c:283
int util_soa_compare(ldns_rr *rr1, ldns_rr *rr2)
Definition: util.c:102
void ods_fclose(FILE *fd)
Definition: file.c:250
#define ods_log_assert(x)
Definition: log.h:154
int util_is_dnssec_rr(ldns_rr *rr)
Definition: util.c:53
void ods_log_warning(const char *format,...)
Definition: log.c:318