OpenDNSSEC-signer  1.3.16
util.c
Go to the documentation of this file.
1 /*
2  * $Id: util.c 6956 2013-01-17 10:57:36Z 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 
59  if (!rr) {
60  return 0;
61  }
62 
63  type = ldns_rr_get_type(rr);
64  return (type == LDNS_RR_TYPE_RRSIG ||
65  type == LDNS_RR_TYPE_NSEC ||
66  type == LDNS_RR_TYPE_NSEC3 ||
67  type == LDNS_RR_TYPE_NSEC3PARAMS);
68 }
69 
70 
75 int
76 util_soa_compare_rdata(ldns_rr* rr1, ldns_rr* rr2)
77 {
78  size_t i = 0;
79  size_t rdata_count = SE_SOA_RDATA_MINIMUM;
80 
81  for (i = 0; i <= rdata_count; i++) {
82  if (i != SE_SOA_RDATA_SERIAL &&
83  ldns_rdf_compare(ldns_rr_rdf(rr1, i), ldns_rr_rdf(rr2, i)) != 0) {
84  return 1;
85  }
86  }
87  return 0;
88 }
89 
90 
95 int
96 util_soa_compare(ldns_rr* rr1, ldns_rr* rr2)
97 {
98  size_t rr1_len = 0;
99  size_t rr2_len = 0;
100  size_t offset = 0;
101 
102  if (!rr1 || !rr2) {
103  return 1;
104  }
105 
106  rr1_len = ldns_rr_uncompressed_size(rr1);
107  rr2_len = ldns_rr_uncompressed_size(rr2);
108  if (ldns_dname_compare(ldns_rr_owner(rr1), ldns_rr_owner(rr2)) != 0) {
109  return 1;
110  }
111  if (ldns_rr_get_class(rr1) != ldns_rr_get_class(rr2)) {
112  return 1;
113  }
114  if (ldns_rr_get_type(rr1) != LDNS_RR_TYPE_SOA) {
115  return 1;
116  }
117  if (ldns_rr_get_type(rr1) != ldns_rr_get_type(rr2)) {
118  return 1;
119  }
120  if (offset > rr1_len || offset > rr2_len) {
121  if (rr1_len == rr2_len) {
122  return util_soa_compare_rdata(rr1, rr2);
123  }
124  return 1;
125  }
126 
127  return util_soa_compare_rdata(rr1, rr2);
128 }
129 
130 
131 
136 ldns_status
137 util_dnssec_rrs_compare(ldns_rr* rr1, ldns_rr* rr2, int* cmp)
138 {
139  ldns_status status = LDNS_STATUS_OK;
140  size_t rr1_len;
141  size_t rr2_len;
142  ldns_buffer* rr1_buf;
143  ldns_buffer* rr2_buf;
144 
145  if (!rr1 || !rr2) {
146  return LDNS_STATUS_ERR;
147  }
148 
149  rr1_len = ldns_rr_uncompressed_size(rr1);
150  rr2_len = ldns_rr_uncompressed_size(rr2);
151  rr1_buf = ldns_buffer_new(rr1_len);
152  rr2_buf = ldns_buffer_new(rr2_len);
153 
154  /* name, class and type should already be equal */
155  status = ldns_rr2buffer_wire_canonical(rr1_buf, rr1, LDNS_SECTION_ANY);
156  if (status != LDNS_STATUS_OK) {
157  ldns_buffer_free(rr1_buf);
158  ldns_buffer_free(rr2_buf);
159  /* critical */
160  return status;
161  }
162  status = ldns_rr2buffer_wire_canonical(rr2_buf, rr2, LDNS_SECTION_ANY);
163  if (status != LDNS_STATUS_OK) {
164  ldns_buffer_free(rr1_buf);
165  ldns_buffer_free(rr2_buf);
166  /* critical */
167  return status;
168  }
169  *cmp = ldns_rr_compare_wire(rr1_buf, rr2_buf);
170  ldns_buffer_free(rr1_buf);
171  ldns_buffer_free(rr2_buf);
172  return LDNS_STATUS_OK;
173 }
174 
175 
180 ldns_status
181 util_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr)
182 {
183  int cmp = 0;
184  ldns_dnssec_rrs *new_rrs = NULL;
185  ldns_status status = LDNS_STATUS_OK;
186  uint32_t rr_ttl = 0;
187  uint32_t default_ttl = 0;
188 
189  if (!rrs || !rrs->rr || !rr) {
190  return LDNS_STATUS_ERR;
191  }
192 
193  rr_ttl = ldns_rr_ttl(rr);
194  status = util_dnssec_rrs_compare(rrs->rr, rr, &cmp);
195  if (status != LDNS_STATUS_OK) {
196  /* critical */
197  return status;
198  }
199 
200  if (cmp < 0) {
201  if (rrs->next) {
202  return util_dnssec_rrs_add_rr(rrs->next, rr);
203  } else {
204  new_rrs = ldns_dnssec_rrs_new();
205  new_rrs->rr = rr;
206  rrs->next = new_rrs;
207  default_ttl = ldns_rr_ttl(rrs->rr);
208  if (rr_ttl < default_ttl) {
209  ldns_rr_set_ttl(rrs->rr, rr_ttl);
210  } else {
211  ldns_rr_set_ttl(new_rrs->rr, default_ttl);
212  }
213  return LDNS_STATUS_OK;
214  }
215  } else if (cmp > 0) {
216  /* put the current old rr in the new next, put the new
217  rr in the current container */
218  new_rrs = ldns_dnssec_rrs_new();
219  new_rrs->rr = rrs->rr;
220  new_rrs->next = rrs->next;
221 
222  rrs->rr = rr;
223  rrs->next = new_rrs;
224 
225  default_ttl = ldns_rr_ttl(new_rrs->rr);
226  if (rr_ttl < default_ttl) {
227  ldns_rr_set_ttl(new_rrs->rr, rr_ttl);
228  } else {
229  ldns_rr_set_ttl(rrs->rr, default_ttl);
230  }
231 
232  return LDNS_STATUS_OK;
233  } else {
234  /* should we error on equal? or free memory of rr */
235  ods_log_warning("[%s] adding duplicate RR?", util_str);
236  return LDNS_STATUS_NO_DATA;
237  }
238  return LDNS_STATUS_OK;
239 }
240 
241 
246 static pid_t
247 util_read_pidfile(const char* file)
248 {
249  int fd;
250  pid_t pid;
251  char pidbuf[32];
252  char *t;
253  int l;
254 
255  if ((fd = open(file, O_RDONLY)) == -1) {
256  return -1;
257  }
258  if (((l = read(fd, pidbuf, sizeof(pidbuf)))) == -1) {
259  close(fd);
260  return -1;
261  }
262  close(fd);
263  /* Empty pidfile means no pidfile... */
264  if (l == 0) {
265  errno = ENOENT;
266  return -1;
267  }
268  pid = (pid_t) strtol(pidbuf, &t, 10);
269 
270  if (*t && *t != '\n') {
271  return -1;
272  }
273  return pid;
274 }
275 
276 
281 int
282 util_check_pidfile(const char* pidfile)
283 {
284  pid_t oldpid;
285  struct stat stat_ret;
286 
287  if (!pidfile) {
288  return 1;
289  }
294  if (stat(pidfile, &stat_ret) != 0) {
295  if (errno != ENOENT) {
296  ods_log_error("[%s] cannot stat pidfile %s: %s", util_str, pidfile,
297  strerror(errno));
298  } /* else: file does not exist: carry on */
299  } else {
300  if (S_ISREG(stat_ret.st_mode)) {
302  if ((oldpid = util_read_pidfile(pidfile)) == -1) {
304  if (errno != ENOENT) {
305  ods_log_error("[%s] cannot read pidfile %s: %s", util_str,
306  pidfile, strerror(errno));
307  }
308  } else {
309  if (kill(oldpid, 0) == 0 || errno == EPERM) {
310  ods_log_crit("[%s] pidfile %s already exists, "
311  "a process with pid %u is already running. "
312  "If no ods-signerd process is running, a previous "
313  "instance didn't shutdown cleanly, please remove this "
314  "file and try again.", util_str, pidfile, oldpid);
315  return 0;
316  } else {
318  ods_log_warning("[%s] pidfile %s already exists, "
319  "but no process with pid %u is running. "
320  "A previous instance didn't shutdown cleanly, this "
321  "pidfile is stale.", util_str, pidfile, oldpid);
322  }
323  }
324  }
325  }
327  return 1;
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  if (!pidfile || !pid) {
342  return -1;
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 }
void ods_log_debug(const char *format,...)
Definition: log.c:285
ldns_status util_dnssec_rrs_compare(ldns_rr *rr1, ldns_rr *rr2, int *cmp)
Definition: util.c:137
int util_soa_compare_rdata(ldns_rr *rr1, ldns_rr *rr2)
Definition: util.c:76
void ods_log_error(const char *format,...)
Definition: log.c:349
#define SE_SOA_RDATA_SERIAL
Definition: util.h:48
FILE * ods_fopen(const char *file, const char *dir, const char *mode)
Definition: file.c:188
void ods_log_crit(const char *format,...)
Definition: log.c:365
int util_write_pidfile(const char *pidfile, pid_t pid)
Definition: util.c:335
#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:181
int util_check_pidfile(const char *pidfile)
Definition: util.c:282
int util_soa_compare(ldns_rr *rr1, ldns_rr *rr2)
Definition: util.c:96
void ods_fclose(FILE *fd)
Definition: file.c:245
int util_is_dnssec_rr(ldns_rr *rr)
Definition: util.c:55
void ods_log_warning(const char *format,...)
Definition: log.c:333