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
27 /**
28 *
29 * Utility tools.
30 */
31
32 #include "config.h"
33
34 #include "file.h"
35 #include "log.h"
36 #include "util.h"
37
38 #include <fcntl.h>
39 #include <ldns/ldns.h>
40 #include <signal.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <time.h>
44 #include <unistd.h>
45
46 static const char* util_str = "util";
47
48
49 /**
50 * Check if a RR is a DNSSEC RR (RRSIG, NSEC, NSEC3 or NSEC3PARAMS).
51 *
52 */
53 int
util_is_dnssec_rr(ldns_rr * rr)54 util_is_dnssec_rr(ldns_rr* rr)
55 {
56 ldns_rr_type type = 0;
57 if (!rr) {
58 return 0;
59 }
60 type = ldns_rr_get_type(rr);
61 return (type == LDNS_RR_TYPE_RRSIG ||
62 type == LDNS_RR_TYPE_NSEC ||
63 type == LDNS_RR_TYPE_NSEC3 ||
64 type == LDNS_RR_TYPE_NSEC3PARAMS);
65 }
66
67
68 /**
69 * Compare SERIALs.
70 *
71 */
72 int
util_serial_gt(uint32_t serial_new,uint32_t serial_old)73 util_serial_gt(uint32_t serial_new, uint32_t serial_old)
74 {
75 return DNS_SERIAL_GT(serial_new, serial_old);
76 }
77
78
79 /**
80 * Compare RRs only on RDATA.
81 *
82 */
83 ldns_status
util_dnssec_rrs_compare(ldns_rr * rr1,ldns_rr * rr2,int * cmp)84 util_dnssec_rrs_compare(ldns_rr* rr1, ldns_rr* rr2, int* cmp)
85 {
86 ldns_status status = LDNS_STATUS_OK;
87 size_t rr1_len;
88 size_t rr2_len;
89 ldns_buffer* rr1_buf;
90 ldns_buffer* rr2_buf;
91
92 if (!rr1 || !rr2) {
93 return LDNS_STATUS_ERR;
94 }
95 rr1_len = ldns_rr_uncompressed_size(rr1);
96 rr2_len = ldns_rr_uncompressed_size(rr2);
97 rr1_buf = ldns_buffer_new(rr1_len);
98 rr2_buf = ldns_buffer_new(rr2_len);
99 /* name, class and type should already be equal */
100 status = ldns_rr2buffer_wire_canonical(rr1_buf, rr1, LDNS_SECTION_ANY);
101 if (status != LDNS_STATUS_OK) {
102 ldns_buffer_free(rr1_buf);
103 ldns_buffer_free(rr2_buf);
104 /* critical */
105 return status;
106 }
107 status = ldns_rr2buffer_wire_canonical(rr2_buf, rr2, LDNS_SECTION_ANY);
108 if (status != LDNS_STATUS_OK) {
109 ldns_buffer_free(rr1_buf);
110 ldns_buffer_free(rr2_buf);
111 /* critical */
112 return status;
113 }
114 *cmp = ldns_rr_compare_wire(rr1_buf, rr2_buf);
115 ldns_buffer_free(rr1_buf);
116 ldns_buffer_free(rr2_buf);
117 return LDNS_STATUS_OK;
118 }
119
120
121 /**
122 * Read process id from file.
123 *
124 */
125 static pid_t
util_read_pidfile(const char * file)126 util_read_pidfile(const char* file)
127 {
128 int fd;
129 pid_t pid;
130 char pidbuf[32];
131 char *t;
132 int l;
133
134 if ((fd = open(file, O_RDONLY)) == -1) {
135 return -1;
136 }
137 if (((l = read(fd, pidbuf, sizeof(pidbuf)))) == -1) {
138 close(fd);
139 return -1;
140 }
141 close(fd);
142 /* Empty pidfile means no pidfile... */
143 if (l == 0) {
144 errno = ENOENT;
145 return -1;
146 }
147 pid = (pid_t) strtol(pidbuf, &t, 10);
148
149 if (*t && *t != '\n') {
150 return -1;
151 }
152 return pid;
153 }
154
155
156 /**
157 * Check process id file.
158 *
159 */
160 int
util_check_pidfile(const char * pidfile)161 util_check_pidfile(const char* pidfile)
162 {
163 pid_t oldpid;
164 struct stat stat_ret;
165 /**
166 * If the file exists then either we didn't shutdown cleanly or
167 * a signer daemon is already running: in either case shutdown.
168 */
169 if (stat(pidfile, &stat_ret) != 0) {
170 if (errno != ENOENT) {
171 ods_log_error("[%s] cannot stat pidfile %s: %s", util_str, pidfile,
172 strerror(errno));
173 } /* else: file does not exist: carry on */
174 } else {
175 if (S_ISREG(stat_ret.st_mode)) {
176 /** The pidfile exists already */
177 if ((oldpid = util_read_pidfile(pidfile)) == -1) {
178 /** Consider stale pidfile */
179 if (errno != ENOENT) {
180 ods_log_error("[%s] cannot read pidfile %s: %s", util_str,
181 pidfile, strerror(errno));
182 }
183 } else {
184 if (kill(oldpid, 0) == 0 || errno == EPERM) {
185 ods_log_crit("[%s] pidfile %s already exists, "
186 "a process with pid %u is already running. "
187 "If no ods-signerd process is running, a previous "
188 "instance didn't shutdown cleanly, please remove this "
189 "file and try again.", util_str, pidfile, oldpid);
190 return 0;
191 } else {
192 /** Consider state pidfile */
193 ods_log_warning("[%s] pidfile %s already exists, "
194 "but no process with pid %u is running. "
195 "A previous instance didn't shutdown cleanly, this "
196 "pidfile is stale.", util_str, pidfile, oldpid);
197 }
198 }
199 }
200 }
201 /** All good, carry on */
202 return 1;
203 }
204
205
206 /**
207 * Write process id to file.
208 *
209 */
210 int
util_write_pidfile(const char * pidfile,pid_t pid)211 util_write_pidfile(const char* pidfile, pid_t pid)
212 {
213 FILE* fd;
214 char pidbuf[32];
215 size_t result = 0, size = 0;
216
217 ods_log_assert(pidfile);
218 ods_log_assert(pid);
219
220 ods_log_debug("[%s] writing pid %lu to pidfile %s", util_str,
221 (unsigned long) pid, pidfile);
222 snprintf(pidbuf, sizeof(pidbuf), "%lu\n", (unsigned long) pid);
223 fd = ods_fopen(pidfile, NULL, "w");
224 if (!fd) {
225 return -1;
226 }
227 size = strlen(pidbuf);
228 if (size == 0) {
229 result = 1;
230 } else {
231 result = fwrite((const void*) pidbuf, 1, size, fd);
232 }
233 if (result == 0) {
234 ods_log_error("[%s] write to pidfile %s failed: %s", util_str,
235 pidfile, strerror(errno));
236 } else if (result < size) {
237 ods_log_error("[%s] short write to pidfile %s: disk full?", util_str,
238 pidfile);
239 result = 0;
240 } else {
241 result = 1;
242 }
243 ods_fclose(fd);
244 if (!result) {
245 return -1;
246 }
247 return 0;
248 }
249
250 /**
251 * Calculates the size needed to store the result of b64_pton.
252 *
253 */
254 size_t
util_b64_pton_calculate_size(size_t srcsize)255 util_b64_pton_calculate_size(size_t srcsize)
256 {
257 return (((((srcsize + 3) / 4) * 3)) + 1);
258 }
259
260 /**
261 * Print an LDNS RR, check status.
262 *
263 */
264 ods_status
util_rr_print(FILE * fd,const ldns_rr * rr)265 util_rr_print(FILE* fd, const ldns_rr* rr)
266 {
267 char* result = NULL;
268 ldns_buffer* tmp_buffer = NULL;
269 ods_status status = ODS_STATUS_OK;
270
271 if (!fd || !rr) {
272 return ODS_STATUS_ASSERT_ERR;
273 }
274
275 tmp_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
276 if (!tmp_buffer) {
277 return ODS_STATUS_MALLOC_ERR;
278 }
279 if (ldns_rr2buffer_str_fmt(tmp_buffer, NULL, rr)
280 == LDNS_STATUS_OK) {
281 /* export and return string, destroy rest */
282 result = ldns_buffer2str(tmp_buffer);
283 if (result) {
284 fprintf(fd, "%s", result);
285 status = ODS_STATUS_OK;
286 LDNS_FREE(result);
287 } else {
288 fprintf(fd, "; Unable to convert rr to string\n");
289 status = ODS_STATUS_FWRITE_ERR;
290 }
291 } else {
292 status = ODS_STATUS_FWRITE_ERR;
293 }
294 ldns_buffer_free(tmp_buffer);
295 return status;
296 }
297
298
299 /**
300 * Check pidfile
301 *
302 */
303 int
util_pidfile_avail(const char * pidfile)304 util_pidfile_avail(const char* pidfile)
305 {
306 int fd, available, pid;
307 char pidbuf[32];
308 ssize_t n;
309
310 if (!pidfile) return 0;
311 if ((fd = open(pidfile, O_RDONLY)) == -1) {
312 return (errno == ENOENT); /* Does not exist*/
313 }
314 n = read(fd, pidbuf, 32);
315 if (n == -1) { /* error */
316 available = 0;
317 } else if (n == 0) { /* EOF */
318 available = 1;
319 } else { /* PID */
320 pidbuf[31] = 0;
321 /* atoi can not fail but we must not pass negative values to
322 * kill */
323 pid = atoi(pidbuf);
324 if (pid > 0)
325 available = (kill(pid, 0) != 0);
326 else
327 available = 1;
328 }
329 (void) close(fd);
330 return available;
331 }
332
333 int
clamp(int value,int lbnd,int ubnd)334 clamp(int value, int lbnd, int ubnd)
335 {
336 if(value < lbnd)
337 return lbnd;
338 else if(value > ubnd)
339 return ubnd;
340 else
341 return value;
342 }
343