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