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