]>
Commit | Line | Data |
---|---|---|
88840341 | 1 | /* |
88840341 RC |
2 | chronyd/chronyc - Programs for keeping computer clocks accurate. |
3 | ||
4 | ********************************************************************** | |
6672f045 | 5 | * Copyright (C) Richard P. Curnow 1997-2003 |
5dc86c23 | 6 | * Copyright (C) Miroslav Lichvar 2009, 2012-2018 |
88840341 RC |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of version 2 of the GNU General Public License as | |
10 | * published by the Free Software Foundation. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License along | |
18 | * with this program; if not, write to the Free Software Foundation, Inc., | |
8e23110a | 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
88840341 RC |
20 | * |
21 | ********************************************************************** | |
22 | ||
23 | ======================================================================= | |
24 | ||
25 | Various utility functions | |
26 | */ | |
27 | ||
da2c8d90 ML |
28 | #include "config.h" |
29 | ||
88840341 RC |
30 | #include "sysincl.h" |
31 | ||
236576c1 | 32 | #include "logging.h" |
92706b15 | 33 | #include "memory.h" |
88840341 | 34 | #include "util.h" |
777303f1 | 35 | #include "hash.h" |
88840341 | 36 | |
d0dfa1de ML |
37 | #define NSEC_PER_SEC 1000000000 |
38 | ||
39 | /* ================================================== */ | |
40 | ||
41 | void | |
42 | UTI_ZeroTimespec(struct timespec *ts) | |
43 | { | |
44 | ts->tv_sec = 0; | |
45 | ts->tv_nsec = 0; | |
46 | } | |
47 | ||
48 | /* ================================================== */ | |
49 | ||
c8373f16 ML |
50 | int |
51 | UTI_IsZeroTimespec(struct timespec *ts) | |
52 | { | |
53 | return !ts->tv_sec && !ts->tv_nsec; | |
54 | } | |
55 | ||
56 | /* ================================================== */ | |
57 | ||
d0dfa1de | 58 | void |
d3f42929 | 59 | UTI_TimevalToTimespec(const struct timeval *tv, struct timespec *ts) |
d0dfa1de ML |
60 | { |
61 | ts->tv_sec = tv->tv_sec; | |
62 | ts->tv_nsec = 1000 * tv->tv_usec; | |
63 | } | |
64 | ||
65 | /* ================================================== */ | |
66 | ||
67 | void | |
d3f42929 | 68 | UTI_TimespecToTimeval(const struct timespec *ts, struct timeval *tv) |
d0dfa1de ML |
69 | { |
70 | tv->tv_sec = ts->tv_sec; | |
71 | tv->tv_usec = ts->tv_nsec / 1000; | |
72 | } | |
73 | ||
74 | /* ================================================== */ | |
75 | ||
cfe706f0 | 76 | double |
d3f42929 | 77 | UTI_TimespecToDouble(const struct timespec *ts) |
d0dfa1de | 78 | { |
cfe706f0 | 79 | return ts->tv_sec + 1.0e-9 * ts->tv_nsec; |
d0dfa1de ML |
80 | } |
81 | ||
82 | /* ================================================== */ | |
83 | ||
84 | void | |
85 | UTI_DoubleToTimespec(double d, struct timespec *ts) | |
86 | { | |
87 | ts->tv_sec = d; | |
88 | ts->tv_nsec = 1.0e9 * (d - ts->tv_sec); | |
89 | UTI_NormaliseTimespec(ts); | |
90 | } | |
91 | ||
92 | /* ================================================== */ | |
93 | ||
94 | void | |
95 | UTI_NormaliseTimespec(struct timespec *ts) | |
96 | { | |
97 | if (ts->tv_nsec >= NSEC_PER_SEC || ts->tv_nsec < 0) { | |
98 | ts->tv_sec += ts->tv_nsec / NSEC_PER_SEC; | |
99 | ts->tv_nsec = ts->tv_nsec % NSEC_PER_SEC; | |
100 | ||
101 | /* If seconds are negative nanoseconds would end up negative too */ | |
102 | if (ts->tv_nsec < 0) { | |
103 | ts->tv_sec--; | |
104 | ts->tv_nsec += NSEC_PER_SEC; | |
105 | } | |
106 | } | |
107 | } | |
108 | ||
88840341 RC |
109 | /* ================================================== */ |
110 | ||
cfe706f0 | 111 | double |
d3f42929 | 112 | UTI_TimevalToDouble(const struct timeval *tv) |
88840341 | 113 | { |
cfe706f0 | 114 | return tv->tv_sec + 1.0e-6 * tv->tv_usec; |
88840341 RC |
115 | } |
116 | ||
117 | /* ================================================== */ | |
118 | ||
82f7fa38 | 119 | void |
88840341 RC |
120 | UTI_DoubleToTimeval(double a, struct timeval *b) |
121 | { | |
0fc0f906 | 122 | double frac_part; |
4bbc7686 ML |
123 | |
124 | b->tv_sec = a; | |
125 | frac_part = 1.0e6 * (a - b->tv_sec); | |
126 | b->tv_usec = frac_part > 0 ? frac_part + 0.5 : frac_part - 0.5; | |
88840341 RC |
127 | UTI_NormaliseTimeval(b); |
128 | } | |
129 | ||
130 | /* ================================================== */ | |
131 | ||
82f7fa38 | 132 | void |
88840341 RC |
133 | UTI_NormaliseTimeval(struct timeval *x) |
134 | { | |
bc0aaa92 JH |
135 | /* Reduce tv_usec to within +-1000000 of zero. JGH */ |
136 | if ((x->tv_usec >= 1000000) || (x->tv_usec <= -1000000)) { | |
137 | x->tv_sec += x->tv_usec/1000000; | |
138 | x->tv_usec = x->tv_usec%1000000; | |
88840341 RC |
139 | } |
140 | ||
bc0aaa92 JH |
141 | /* Make tv_usec positive. JGH */ |
142 | if (x->tv_usec < 0) { | |
88840341 RC |
143 | --x->tv_sec; |
144 | x->tv_usec += 1000000; | |
bc0aaa92 | 145 | } |
88840341 RC |
146 | |
147 | } | |
148 | ||
149 | /* ================================================== */ | |
150 | ||
d0dfa1de | 151 | int |
d3f42929 | 152 | UTI_CompareTimespecs(const struct timespec *a, const struct timespec *b) |
88840341 | 153 | { |
d0dfa1de ML |
154 | if (a->tv_sec < b->tv_sec) |
155 | return -1; | |
156 | if (a->tv_sec > b->tv_sec) | |
157 | return 1; | |
158 | if (a->tv_nsec < b->tv_nsec) | |
159 | return -1; | |
160 | if (a->tv_nsec > b->tv_nsec) | |
161 | return 1; | |
162 | return 0; | |
163 | } | |
88840341 | 164 | |
d0dfa1de | 165 | /* ================================================== */ |
88840341 | 166 | |
d0dfa1de | 167 | void |
d3f42929 | 168 | UTI_DiffTimespecs(struct timespec *result, const struct timespec *a, const struct timespec *b) |
d0dfa1de ML |
169 | { |
170 | result->tv_sec = a->tv_sec - b->tv_sec; | |
171 | result->tv_nsec = a->tv_nsec - b->tv_nsec; | |
172 | UTI_NormaliseTimespec(result); | |
88840341 RC |
173 | } |
174 | ||
175 | /* ================================================== */ | |
176 | ||
177 | /* Calculate result = a - b and return as a double */ | |
cfe706f0 | 178 | double |
d3f42929 | 179 | UTI_DiffTimespecsToDouble(const struct timespec *a, const struct timespec *b) |
88840341 | 180 | { |
0c54cf31 | 181 | return ((double)a->tv_sec - (double)b->tv_sec) + 1.0e-9 * (a->tv_nsec - b->tv_nsec); |
88840341 RC |
182 | } |
183 | ||
184 | /* ================================================== */ | |
185 | ||
82f7fa38 | 186 | void |
d3f42929 | 187 | UTI_AddDoubleToTimespec(const struct timespec *start, double increment, struct timespec *end) |
88840341 | 188 | { |
d0dfa1de | 189 | time_t int_part; |
88840341 | 190 | |
d0dfa1de ML |
191 | int_part = increment; |
192 | end->tv_sec = start->tv_sec + int_part; | |
193 | end->tv_nsec = start->tv_nsec + 1.0e9 * (increment - int_part); | |
194 | UTI_NormaliseTimespec(end); | |
88840341 RC |
195 | } |
196 | ||
197 | /* ================================================== */ | |
198 | ||
d0dfa1de | 199 | /* Calculate the average and difference (as a double) of two timespecs */ |
82f7fa38 | 200 | void |
d3f42929 | 201 | UTI_AverageDiffTimespecs(const struct timespec *earlier, const struct timespec *later, |
d0dfa1de | 202 | struct timespec *average, double *diff) |
88840341 | 203 | { |
cfe706f0 | 204 | *diff = UTI_DiffTimespecsToDouble(later, earlier); |
d0dfa1de ML |
205 | UTI_AddDoubleToTimespec(earlier, *diff / 2.0, average); |
206 | } | |
88840341 RC |
207 | |
208 | /* ================================================== */ | |
209 | ||
8aa9eb19 | 210 | void |
d3f42929 ML |
211 | UTI_AddDiffToTimespec(const struct timespec *a, const struct timespec *b, |
212 | const struct timespec *c, struct timespec *result) | |
8aa9eb19 ML |
213 | { |
214 | double diff; | |
215 | ||
cfe706f0 | 216 | diff = UTI_DiffTimespecsToDouble(a, b); |
d0dfa1de | 217 | UTI_AddDoubleToTimespec(c, diff, result); |
8aa9eb19 ML |
218 | } |
219 | ||
220 | /* ================================================== */ | |
221 | ||
88840341 RC |
222 | #define POOL_ENTRIES 16 |
223 | #define BUFFER_LENGTH 64 | |
224 | static char buffer_pool[POOL_ENTRIES][BUFFER_LENGTH]; | |
225 | static int pool_ptr = 0; | |
226 | ||
227 | #define NEXT_BUFFER (buffer_pool[pool_ptr = ((pool_ptr + 1) % POOL_ENTRIES)]) | |
228 | ||
229 | /* ================================================== */ | |
d0dfa1de | 230 | /* Convert a timespec into a temporary string, largely for diagnostic display */ |
88840341 RC |
231 | |
232 | char * | |
d3f42929 | 233 | UTI_TimespecToString(const struct timespec *ts) |
88840341 | 234 | { |
77a71623 ML |
235 | char *result; |
236 | ||
88840341 | 237 | result = NEXT_BUFFER; |
fc2892fb | 238 | #ifdef HAVE_LONG_TIME_T |
d0dfa1de ML |
239 | snprintf(result, BUFFER_LENGTH, "%"PRId64".%09lu", |
240 | (int64_t)ts->tv_sec, (unsigned long)ts->tv_nsec); | |
fc2892fb | 241 | #else |
d0dfa1de ML |
242 | snprintf(result, BUFFER_LENGTH, "%ld.%09lu", |
243 | (long)ts->tv_sec, (unsigned long)ts->tv_nsec); | |
fc2892fb | 244 | #endif |
88840341 RC |
245 | return result; |
246 | } | |
247 | ||
88840341 RC |
248 | /* ================================================== */ |
249 | /* Convert an NTP timestamp into a temporary string, largely | |
250 | for diagnostic display */ | |
251 | ||
252 | char * | |
d3f42929 | 253 | UTI_Ntp64ToString(const NTP_int64 *ntp_ts) |
88840341 | 254 | { |
d0dfa1de | 255 | struct timespec ts; |
99cc9452 | 256 | UTI_Ntp64ToTimespec(ntp_ts, &ts); |
d0dfa1de | 257 | return UTI_TimespecToString(&ts); |
88840341 RC |
258 | } |
259 | ||
260 | /* ================================================== */ | |
261 | ||
ac30bb06 | 262 | char * |
91279a0f | 263 | UTI_RefidToString(uint32_t ref_id) |
ac30bb06 | 264 | { |
a3288d42 | 265 | unsigned int i, j, c; |
078f0f51 ML |
266 | char *result; |
267 | ||
268 | result = NEXT_BUFFER; | |
a3288d42 | 269 | |
078f0f51 | 270 | for (i = j = 0; i < 4 && i < BUFFER_LENGTH - 1; i++) { |
a3288d42 ML |
271 | c = (ref_id >> (24 - i * 8)) & 0xff; |
272 | if (isprint(c)) | |
078f0f51 | 273 | result[j++] = c; |
a3288d42 ML |
274 | } |
275 | ||
078f0f51 | 276 | result[j] = '\0'; |
a3288d42 | 277 | |
ac30bb06 ML |
278 | return result; |
279 | } | |
280 | ||
281 | /* ================================================== */ | |
282 | ||
8265ff28 | 283 | char * |
d3f42929 | 284 | UTI_IPToString(const IPAddr *addr) |
8265ff28 ML |
285 | { |
286 | unsigned long a, b, c, d, ip; | |
d3f42929 | 287 | const uint8_t *ip6; |
8265ff28 ML |
288 | char *result; |
289 | ||
290 | result = NEXT_BUFFER; | |
291 | switch (addr->family) { | |
292 | case IPADDR_UNSPEC: | |
293 | snprintf(result, BUFFER_LENGTH, "[UNSPEC]"); | |
294 | break; | |
295 | case IPADDR_INET4: | |
296 | ip = addr->addr.in4; | |
297 | a = (ip>>24) & 0xff; | |
298 | b = (ip>>16) & 0xff; | |
299 | c = (ip>> 8) & 0xff; | |
300 | d = (ip>> 0) & 0xff; | |
9bc774d6 | 301 | snprintf(result, BUFFER_LENGTH, "%lu.%lu.%lu.%lu", a, b, c, d); |
8265ff28 ML |
302 | break; |
303 | case IPADDR_INET6: | |
304 | ip6 = addr->addr.in6; | |
285fae85 | 305 | #ifdef FEAT_IPV6 |
8265ff28 ML |
306 | inet_ntop(AF_INET6, ip6, result, BUFFER_LENGTH); |
307 | #else | |
9bc774d6 ML |
308 | assert(BUFFER_LENGTH >= 40); |
309 | for (a = 0; a < 8; a++) | |
310 | snprintf(result + a * 5, 40 - a * 5, "%04x:", | |
311 | (unsigned int)(ip6[2 * a] << 8 | ip6[2 * a + 1])); | |
8265ff28 ML |
312 | #endif |
313 | break; | |
84902d0e ML |
314 | case IPADDR_ID: |
315 | snprintf(result, BUFFER_LENGTH, "ID#%010"PRIu32, addr->addr.id); | |
316 | break; | |
8265ff28 ML |
317 | default: |
318 | snprintf(result, BUFFER_LENGTH, "[UNKNOWN]"); | |
319 | } | |
320 | return result; | |
321 | } | |
322 | ||
323 | /* ================================================== */ | |
324 | ||
325 | int | |
326 | UTI_StringToIP(const char *addr, IPAddr *ip) | |
327 | { | |
285fae85 | 328 | #ifdef FEAT_IPV6 |
8265ff28 ML |
329 | struct in_addr in4; |
330 | struct in6_addr in6; | |
331 | ||
332 | if (inet_pton(AF_INET, addr, &in4) > 0) { | |
333 | ip->family = IPADDR_INET4; | |
510b22e9 | 334 | ip->_pad = 0; |
8265ff28 ML |
335 | ip->addr.in4 = ntohl(in4.s_addr); |
336 | return 1; | |
337 | } | |
338 | ||
339 | if (inet_pton(AF_INET6, addr, &in6) > 0) { | |
340 | ip->family = IPADDR_INET6; | |
510b22e9 | 341 | ip->_pad = 0; |
8265ff28 ML |
342 | memcpy(ip->addr.in6, in6.s6_addr, sizeof (ip->addr.in6)); |
343 | return 1; | |
344 | } | |
345 | #else | |
346 | unsigned long a, b, c, d, n; | |
347 | ||
348 | n = sscanf(addr, "%lu.%lu.%lu.%lu", &a, &b, &c, &d); | |
349 | if (n == 4) { | |
350 | ip->family = IPADDR_INET4; | |
510b22e9 | 351 | ip->_pad = 0; |
8265ff28 ML |
352 | ip->addr.in4 = ((a & 0xff) << 24) | ((b & 0xff) << 16) | |
353 | ((c & 0xff) << 8) | (d & 0xff); | |
354 | return 1; | |
355 | } | |
356 | #endif | |
357 | ||
358 | return 0; | |
359 | } | |
360 | ||
361 | /* ================================================== */ | |
362 | ||
84902d0e ML |
363 | int |
364 | UTI_StringToIdIP(const char *addr, IPAddr *ip) | |
365 | { | |
366 | if (sscanf(addr, "ID#%"SCNu32, &ip->addr.id) == 1) { | |
367 | ip->family = IPADDR_ID; | |
368 | ip->_pad = 0; | |
369 | return 1; | |
370 | } | |
371 | ||
372 | return 0; | |
373 | } | |
374 | ||
375 | /* ================================================== */ | |
376 | ||
377 | int | |
d3f42929 | 378 | UTI_IsIPReal(const IPAddr *ip) |
84902d0e ML |
379 | { |
380 | switch (ip->family) { | |
381 | case IPADDR_INET4: | |
382 | case IPADDR_INET6: | |
383 | return 1; | |
384 | default: | |
385 | return 0; | |
386 | } | |
387 | } | |
388 | ||
389 | /* ================================================== */ | |
390 | ||
91279a0f | 391 | uint32_t |
d3f42929 | 392 | UTI_IPToRefid(const IPAddr *ip) |
8265ff28 | 393 | { |
777303f1 ML |
394 | static int MD5_hash = -1; |
395 | unsigned char buf[16]; | |
8265ff28 ML |
396 | |
397 | switch (ip->family) { | |
398 | case IPADDR_INET4: | |
399 | return ip->addr.in4; | |
400 | case IPADDR_INET6: | |
4da9f74d | 401 | if (MD5_hash < 0) |
777303f1 | 402 | MD5_hash = HSH_GetHashId("MD5"); |
4da9f74d ML |
403 | |
404 | if (MD5_hash < 0 || | |
405 | HSH_Hash(MD5_hash, (const unsigned char *)ip->addr.in6, sizeof (ip->addr.in6), | |
406 | NULL, 0, buf, sizeof (buf)) != sizeof (buf)) | |
407 | LOG_FATAL("Could not get MD5"); | |
408 | ||
8e71a461 | 409 | return (uint32_t)buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; |
8265ff28 ML |
410 | } |
411 | return 0; | |
412 | } | |
413 | ||
414 | /* ================================================== */ | |
415 | ||
8b235297 | 416 | uint32_t |
d3f42929 | 417 | UTI_IPToHash(const IPAddr *ip) |
8b235297 | 418 | { |
b45f53dd | 419 | static uint32_t seed = 0; |
d3f42929 | 420 | const unsigned char *addr; |
8b235297 ML |
421 | unsigned int i, len; |
422 | uint32_t hash; | |
423 | ||
424 | switch (ip->family) { | |
425 | case IPADDR_INET4: | |
426 | addr = (unsigned char *)&ip->addr.in4; | |
427 | len = sizeof (ip->addr.in4); | |
428 | break; | |
429 | case IPADDR_INET6: | |
430 | addr = ip->addr.in6; | |
431 | len = sizeof (ip->addr.in6); | |
432 | break; | |
84902d0e ML |
433 | case IPADDR_ID: |
434 | addr = (unsigned char *)&ip->addr.id; | |
435 | len = sizeof (ip->addr.id); | |
436 | break; | |
8b235297 ML |
437 | default: |
438 | return 0; | |
439 | } | |
440 | ||
b45f53dd ML |
441 | /* Include a random seed in the hash to randomize collisions |
442 | and order of addresses in hash tables */ | |
443 | while (!seed) | |
444 | UTI_GetRandomBytes(&seed, sizeof (seed)); | |
445 | ||
446 | for (i = 0, hash = seed; i < len; i++) | |
8b235297 ML |
447 | hash = 71 * hash + addr[i]; |
448 | ||
b45f53dd | 449 | return hash + seed; |
8b235297 ML |
450 | } |
451 | ||
452 | /* ================================================== */ | |
453 | ||
8265ff28 | 454 | void |
d3f42929 | 455 | UTI_IPHostToNetwork(const IPAddr *src, IPAddr *dest) |
8265ff28 ML |
456 | { |
457 | /* Don't send uninitialized bytes over network */ | |
458 | memset(dest, 0, sizeof (IPAddr)); | |
459 | ||
460 | dest->family = htons(src->family); | |
461 | ||
462 | switch (src->family) { | |
463 | case IPADDR_INET4: | |
464 | dest->addr.in4 = htonl(src->addr.in4); | |
465 | break; | |
466 | case IPADDR_INET6: | |
467 | memcpy(dest->addr.in6, src->addr.in6, sizeof (dest->addr.in6)); | |
468 | break; | |
84902d0e ML |
469 | case IPADDR_ID: |
470 | dest->addr.id = htonl(src->addr.id); | |
471 | break; | |
23cf74d5 ML |
472 | default: |
473 | dest->family = htons(IPADDR_UNSPEC); | |
8265ff28 ML |
474 | } |
475 | } | |
476 | ||
477 | /* ================================================== */ | |
478 | ||
479 | void | |
d3f42929 | 480 | UTI_IPNetworkToHost(const IPAddr *src, IPAddr *dest) |
8265ff28 ML |
481 | { |
482 | dest->family = ntohs(src->family); | |
510b22e9 | 483 | dest->_pad = 0; |
8265ff28 ML |
484 | |
485 | switch (dest->family) { | |
486 | case IPADDR_INET4: | |
487 | dest->addr.in4 = ntohl(src->addr.in4); | |
488 | break; | |
489 | case IPADDR_INET6: | |
490 | memcpy(dest->addr.in6, src->addr.in6, sizeof (dest->addr.in6)); | |
491 | break; | |
84902d0e ML |
492 | case IPADDR_ID: |
493 | dest->addr.id = ntohl(src->addr.id); | |
494 | break; | |
23cf74d5 ML |
495 | default: |
496 | dest->family = IPADDR_UNSPEC; | |
8265ff28 ML |
497 | } |
498 | } | |
499 | ||
500 | /* ================================================== */ | |
501 | ||
502 | int | |
d3f42929 | 503 | UTI_CompareIPs(const IPAddr *a, const IPAddr *b, const IPAddr *mask) |
8265ff28 ML |
504 | { |
505 | int i, d; | |
506 | ||
507 | if (a->family != b->family) | |
508 | return a->family - b->family; | |
509 | ||
510 | if (mask && mask->family != b->family) | |
511 | mask = NULL; | |
512 | ||
513 | switch (a->family) { | |
514 | case IPADDR_UNSPEC: | |
515 | return 0; | |
516 | case IPADDR_INET4: | |
517 | if (mask) | |
518 | return (a->addr.in4 & mask->addr.in4) - (b->addr.in4 & mask->addr.in4); | |
519 | else | |
520 | return a->addr.in4 - b->addr.in4; | |
521 | case IPADDR_INET6: | |
522 | for (i = 0, d = 0; !d && i < 16; i++) { | |
523 | if (mask) | |
524 | d = (a->addr.in6[i] & mask->addr.in6[i]) - | |
525 | (b->addr.in6[i] & mask->addr.in6[i]); | |
526 | else | |
527 | d = a->addr.in6[i] - b->addr.in6[i]; | |
528 | } | |
529 | return d; | |
84902d0e ML |
530 | case IPADDR_ID: |
531 | return a->addr.id - b->addr.id; | |
8265ff28 ML |
532 | } |
533 | return 0; | |
534 | } | |
535 | ||
536 | /* ================================================== */ | |
537 | ||
3f8c57c8 | 538 | char * |
d3f42929 | 539 | UTI_IPSockAddrToString(const IPSockAddr *sa) |
3f8c57c8 ML |
540 | { |
541 | char *result; | |
542 | ||
543 | result = NEXT_BUFFER; | |
544 | snprintf(result, BUFFER_LENGTH, | |
545 | sa->ip_addr.family != IPADDR_INET6 ? "%s:%hu" : "[%s]:%hu", | |
546 | UTI_IPToString(&sa->ip_addr), sa->port); | |
547 | ||
548 | return result; | |
549 | } | |
550 | ||
551 | /* ================================================== */ | |
552 | ||
88840341 RC |
553 | char * |
554 | UTI_TimeToLogForm(time_t t) | |
555 | { | |
f40b0024 | 556 | struct tm *stm; |
88840341 RC |
557 | char *result; |
558 | ||
559 | result = NEXT_BUFFER; | |
560 | ||
f40b0024 ML |
561 | stm = gmtime(&t); |
562 | ||
563 | if (stm) | |
564 | strftime(result, BUFFER_LENGTH, "%Y-%m-%d %H:%M:%S", stm); | |
565 | else | |
566 | snprintf(result, BUFFER_LENGTH, "INVALID INVALID "); | |
88840341 RC |
567 | |
568 | return result; | |
569 | } | |
570 | ||
571 | /* ================================================== */ | |
572 | ||
573 | void | |
d3f42929 ML |
574 | UTI_AdjustTimespec(const struct timespec *old_ts, const struct timespec *when, |
575 | struct timespec *new_ts, double *delta_time, double dfreq, double doffset) | |
88840341 | 576 | { |
40d82675 | 577 | double elapsed; |
88840341 | 578 | |
cfe706f0 | 579 | elapsed = UTI_DiffTimespecsToDouble(when, old_ts); |
40d82675 | 580 | *delta_time = elapsed * dfreq - doffset; |
d0dfa1de | 581 | UTI_AddDoubleToTimespec(old_ts, *delta_time, new_ts); |
88840341 RC |
582 | } |
583 | ||
584 | /* ================================================== */ | |
585 | ||
116c6972 | 586 | void |
99cc9452 | 587 | UTI_GetNtp64Fuzz(NTP_int64 *ts, int precision) |
df6c2a43 | 588 | { |
116c6972 ML |
589 | int start, bits; |
590 | ||
591 | assert(precision >= -32 && precision <= 32); | |
702db726 | 592 | assert(sizeof (*ts) == 8); |
116c6972 ML |
593 | |
594 | start = sizeof (*ts) - (precision + 32 + 7) / 8; | |
595 | ts->hi = ts->lo = 0; | |
df6c2a43 | 596 | |
116c6972 ML |
597 | UTI_GetRandomBytes((unsigned char *)ts + start, sizeof (*ts) - start); |
598 | ||
599 | bits = (precision + 32) % 8; | |
600 | if (bits) | |
601 | ((unsigned char *)ts)[start] %= 1U << bits; | |
df6c2a43 ML |
602 | } |
603 | ||
604 | /* ================================================== */ | |
605 | ||
2ceb3c89 | 606 | double |
99cc9452 | 607 | UTI_Ntp32ToDouble(NTP_int32 x) |
2ceb3c89 ML |
608 | { |
609 | return (double) ntohl(x) / 65536.0; | |
610 | } | |
611 | ||
612 | /* ================================================== */ | |
613 | ||
8eb7ce85 ML |
614 | #define MAX_NTP_INT32 (4294967295.0 / 65536.0) |
615 | ||
2ceb3c89 | 616 | NTP_int32 |
99cc9452 | 617 | UTI_DoubleToNtp32(double x) |
2ceb3c89 | 618 | { |
7ffe59a7 ML |
619 | NTP_int32 r; |
620 | ||
621 | if (x >= MAX_NTP_INT32) { | |
622 | r = 0xffffffff; | |
623 | } else if (x <= 0.0) { | |
624 | r = 0; | |
625 | } else { | |
626 | x *= 65536.0; | |
627 | r = x; | |
628 | ||
629 | /* Round up */ | |
630 | if (r < x) | |
631 | r++; | |
632 | } | |
633 | ||
634 | return htonl(r); | |
2ceb3c89 ML |
635 | } |
636 | ||
637 | /* ================================================== */ | |
638 | ||
6e9c0489 ML |
639 | void |
640 | UTI_ZeroNtp64(NTP_int64 *ts) | |
641 | { | |
642 | ts->hi = ts->lo = htonl(0); | |
643 | } | |
644 | ||
645 | /* ================================================== */ | |
646 | ||
647 | int | |
d3f42929 | 648 | UTI_IsZeroNtp64(const NTP_int64 *ts) |
6e9c0489 ML |
649 | { |
650 | return !ts->hi && !ts->lo; | |
651 | } | |
652 | ||
653 | /* ================================================== */ | |
654 | ||
655 | int | |
d3f42929 | 656 | UTI_CompareNtp64(const NTP_int64 *a, const NTP_int64 *b) |
6e9c0489 ML |
657 | { |
658 | int32_t diff; | |
659 | ||
660 | if (a->hi == b->hi && a->lo == b->lo) | |
661 | return 0; | |
662 | ||
663 | diff = ntohl(a->hi) - ntohl(b->hi); | |
664 | ||
665 | if (diff < 0) | |
666 | return -1; | |
667 | if (diff > 0) | |
668 | return 1; | |
669 | ||
670 | return ntohl(a->lo) < ntohl(b->lo) ? -1 : 1; | |
671 | } | |
672 | ||
673 | /* ================================================== */ | |
674 | ||
2c7ab983 | 675 | int |
d3f42929 ML |
676 | UTI_IsEqualAnyNtp64(const NTP_int64 *a, const NTP_int64 *b1, const NTP_int64 *b2, |
677 | const NTP_int64 *b3) | |
2c7ab983 ML |
678 | { |
679 | if (b1 && a->lo == b1->lo && a->hi == b1->hi) | |
680 | return 1; | |
681 | ||
682 | if (b2 && a->lo == b2->lo && a->hi == b2->hi) | |
683 | return 1; | |
684 | ||
685 | if (b3 && a->lo == b3->lo && a->hi == b3->hi) | |
686 | return 1; | |
687 | ||
688 | return 0; | |
689 | } | |
690 | ||
691 | /* ================================================== */ | |
692 | ||
d0dfa1de | 693 | /* Seconds part of NTP timestamp correponding to the origin of the time_t format */ |
88840341 RC |
694 | #define JAN_1970 0x83aa7e80UL |
695 | ||
d0dfa1de ML |
696 | #define NSEC_PER_NTP64 4.294967296 |
697 | ||
88840341 | 698 | void |
d3f42929 | 699 | UTI_TimespecToNtp64(const struct timespec *src, NTP_int64 *dest, const NTP_int64 *fuzz) |
88840341 | 700 | { |
d0dfa1de | 701 | uint32_t hi, lo, sec, nsec; |
474b2af1 ML |
702 | |
703 | sec = (uint32_t)src->tv_sec; | |
d0dfa1de | 704 | nsec = (uint32_t)src->tv_nsec; |
88840341 RC |
705 | |
706 | /* Recognize zero as a special case - it always signifies | |
707 | an 'unknown' value */ | |
d0dfa1de | 708 | if (!nsec && !sec) { |
116c6972 | 709 | hi = lo = 0; |
88840341 | 710 | } else { |
116c6972 | 711 | hi = htonl(sec + JAN_1970); |
d0dfa1de | 712 | lo = htonl(NSEC_PER_NTP64 * nsec); |
df6c2a43 ML |
713 | |
714 | /* Add the fuzz */ | |
116c6972 ML |
715 | if (fuzz) { |
716 | hi ^= fuzz->hi; | |
717 | lo ^= fuzz->lo; | |
718 | } | |
88840341 | 719 | } |
116c6972 ML |
720 | |
721 | dest->hi = hi; | |
722 | dest->lo = lo; | |
88840341 RC |
723 | } |
724 | ||
725 | /* ================================================== */ | |
726 | ||
727 | void | |
d3f42929 | 728 | UTI_Ntp64ToTimespec(const NTP_int64 *src, struct timespec *dest) |
88840341 | 729 | { |
474b2af1 ML |
730 | uint32_t ntp_sec, ntp_frac; |
731 | ||
b0f7efd5 ML |
732 | /* Zero is a special value */ |
733 | if (UTI_IsZeroNtp64(src)) { | |
734 | UTI_ZeroTimespec(dest); | |
735 | return; | |
736 | } | |
88840341 | 737 | |
474b2af1 ML |
738 | ntp_sec = ntohl(src->hi); |
739 | ntp_frac = ntohl(src->lo); | |
740 | ||
741 | #ifdef HAVE_LONG_TIME_T | |
742 | dest->tv_sec = ntp_sec - (uint32_t)(NTP_ERA_SPLIT + JAN_1970) + | |
743 | (time_t)NTP_ERA_SPLIT; | |
744 | #else | |
745 | dest->tv_sec = ntp_sec - JAN_1970; | |
746 | #endif | |
0899ab52 | 747 | |
0c54cf31 | 748 | dest->tv_nsec = ntp_frac / NSEC_PER_NTP64; |
88840341 RC |
749 | } |
750 | ||
a7892a1a ML |
751 | /* ================================================== */ |
752 | ||
aec97397 ML |
753 | /* Maximum offset between two sane times */ |
754 | #define MAX_OFFSET 4294967296.0 | |
755 | ||
39c2bcd4 ML |
756 | /* Minimum allowed distance from maximum 32-bit time_t */ |
757 | #define MIN_ENDOFTIME_DISTANCE (365 * 24 * 3600) | |
758 | ||
aec97397 | 759 | int |
d3f42929 | 760 | UTI_IsTimeOffsetSane(const struct timespec *ts, double offset) |
aec97397 ML |
761 | { |
762 | double t; | |
763 | ||
764 | /* Handle nan correctly here */ | |
765 | if (!(offset > -MAX_OFFSET && offset < MAX_OFFSET)) | |
766 | return 0; | |
767 | ||
cfe706f0 | 768 | t = UTI_TimespecToDouble(ts) + offset; |
aec97397 ML |
769 | |
770 | /* Time before 1970 is not considered valid */ | |
771 | if (t < 0.0) | |
772 | return 0; | |
773 | ||
774 | #ifdef HAVE_LONG_TIME_T | |
775 | /* Check if it's in the interval to which NTP time is mapped */ | |
776 | if (t < (double)NTP_ERA_SPLIT || t > (double)(NTP_ERA_SPLIT + (1LL << 32))) | |
777 | return 0; | |
39c2bcd4 ML |
778 | #else |
779 | /* Don't get too close to 32-bit time_t overflow */ | |
780 | if (t > (double)(0x7fffffff - MIN_ENDOFTIME_DISTANCE)) | |
781 | return 0; | |
aec97397 ML |
782 | #endif |
783 | ||
784 | return 1; | |
785 | } | |
786 | ||
787 | /* ================================================== */ | |
788 | ||
3c217a9e ML |
789 | double |
790 | UTI_Log2ToDouble(int l) | |
791 | { | |
792 | if (l >= 0) { | |
793 | if (l > 31) | |
794 | l = 31; | |
7f58852e | 795 | return (uint32_t)1 << l; |
3c217a9e ML |
796 | } else { |
797 | if (l < -31) | |
798 | l = -31; | |
7f58852e | 799 | return 1.0 / ((uint32_t)1 << -l); |
3c217a9e ML |
800 | } |
801 | } | |
802 | ||
803 | /* ================================================== */ | |
804 | ||
a7892a1a | 805 | void |
d3f42929 | 806 | UTI_TimespecNetworkToHost(const Timespec *src, struct timespec *dest) |
a7892a1a | 807 | { |
0c54cf31 | 808 | uint32_t sec_low, nsec; |
1a795b04 ML |
809 | #ifdef HAVE_LONG_TIME_T |
810 | uint32_t sec_high; | |
811 | #endif | |
a7892a1a | 812 | |
a7892a1a | 813 | sec_low = ntohl(src->tv_sec_low); |
713153b6 | 814 | #ifdef HAVE_LONG_TIME_T |
1a795b04 | 815 | sec_high = ntohl(src->tv_sec_high); |
713153b6 ML |
816 | if (sec_high == TV_NOHIGHSEC) |
817 | sec_high = 0; | |
a7892a1a | 818 | |
713153b6 ML |
819 | dest->tv_sec = (uint64_t)sec_high << 32 | sec_low; |
820 | #else | |
821 | dest->tv_sec = sec_low; | |
822 | #endif | |
0899ab52 | 823 | |
0c54cf31 | 824 | nsec = ntohl(src->tv_nsec); |
a83f0d3c | 825 | dest->tv_nsec = MIN(nsec, 999999999U); |
a7892a1a ML |
826 | } |
827 | ||
828 | /* ================================================== */ | |
829 | ||
830 | void | |
d3f42929 | 831 | UTI_TimespecHostToNetwork(const struct timespec *src, Timespec *dest) |
a7892a1a | 832 | { |
d0dfa1de | 833 | dest->tv_nsec = htonl(src->tv_nsec); |
713153b6 ML |
834 | #ifdef HAVE_LONG_TIME_T |
835 | dest->tv_sec_high = htonl((uint64_t)src->tv_sec >> 32); | |
836 | #else | |
837 | dest->tv_sec_high = htonl(TV_NOHIGHSEC); | |
838 | #endif | |
a7892a1a ML |
839 | dest->tv_sec_low = htonl(src->tv_sec); |
840 | } | |
841 | ||
b4947011 ML |
842 | /* ================================================== */ |
843 | ||
844 | #define FLOAT_EXP_BITS 7 | |
845 | #define FLOAT_EXP_MIN (-(1 << (FLOAT_EXP_BITS - 1))) | |
846 | #define FLOAT_EXP_MAX (-FLOAT_EXP_MIN - 1) | |
847 | #define FLOAT_COEF_BITS ((int)sizeof (int32_t) * 8 - FLOAT_EXP_BITS) | |
848 | #define FLOAT_COEF_MIN (-(1 << (FLOAT_COEF_BITS - 1))) | |
849 | #define FLOAT_COEF_MAX (-FLOAT_COEF_MIN - 1) | |
850 | ||
851 | double | |
852 | UTI_FloatNetworkToHost(Float f) | |
853 | { | |
8e71a461 ML |
854 | int32_t exp, coef; |
855 | uint32_t x; | |
b4947011 ML |
856 | |
857 | x = ntohl(f.f); | |
8e71a461 | 858 | |
5833be6c | 859 | exp = x >> FLOAT_COEF_BITS; |
8e71a461 ML |
860 | if (exp >= 1 << (FLOAT_EXP_BITS - 1)) |
861 | exp -= 1 << FLOAT_EXP_BITS; | |
5833be6c | 862 | exp -= FLOAT_COEF_BITS; |
8e71a461 ML |
863 | |
864 | coef = x % (1U << FLOAT_COEF_BITS); | |
865 | if (coef >= 1 << (FLOAT_COEF_BITS - 1)) | |
866 | coef -= 1 << FLOAT_COEF_BITS; | |
867 | ||
b4947011 ML |
868 | return coef * pow(2.0, exp); |
869 | } | |
870 | ||
871 | Float | |
872 | UTI_FloatHostToNetwork(double x) | |
873 | { | |
874 | int32_t exp, coef, neg; | |
875 | Float f; | |
876 | ||
877 | if (x < 0.0) { | |
878 | x = -x; | |
879 | neg = 1; | |
cde3a003 ML |
880 | } else if (x >= 0.0) { |
881 | neg = 0; | |
b4947011 | 882 | } else { |
cde3a003 ML |
883 | /* Save NaN as zero */ |
884 | x = 0.0; | |
b4947011 ML |
885 | neg = 0; |
886 | } | |
887 | ||
888 | if (x < 1.0e-100) { | |
889 | exp = coef = 0; | |
890 | } else if (x > 1.0e100) { | |
891 | exp = FLOAT_EXP_MAX; | |
892 | coef = FLOAT_COEF_MAX + neg; | |
893 | } else { | |
894 | exp = log(x) / log(2) + 1; | |
895 | coef = x * pow(2.0, -exp + FLOAT_COEF_BITS) + 0.5; | |
896 | ||
897 | assert(coef > 0); | |
898 | ||
899 | /* we may need to shift up to two bits down */ | |
900 | while (coef > FLOAT_COEF_MAX + neg) { | |
901 | coef >>= 1; | |
902 | exp++; | |
903 | } | |
904 | ||
905 | if (exp > FLOAT_EXP_MAX) { | |
906 | /* overflow */ | |
907 | exp = FLOAT_EXP_MAX; | |
908 | coef = FLOAT_COEF_MAX + neg; | |
909 | } else if (exp < FLOAT_EXP_MIN) { | |
910 | /* underflow */ | |
911 | if (exp + FLOAT_COEF_BITS >= FLOAT_EXP_MIN) { | |
912 | coef >>= FLOAT_EXP_MIN - exp; | |
913 | exp = FLOAT_EXP_MIN; | |
914 | } else { | |
915 | exp = coef = 0; | |
916 | } | |
917 | } | |
918 | } | |
919 | ||
920 | /* negate back */ | |
921 | if (neg) | |
922 | coef = (uint32_t)-coef << FLOAT_EXP_BITS >> FLOAT_EXP_BITS; | |
923 | ||
8e71a461 | 924 | f.f = htonl((uint32_t)exp << FLOAT_COEF_BITS | coef); |
b4947011 ML |
925 | return f; |
926 | } | |
a7892a1a | 927 | |
88840341 | 928 | /* ================================================== */ |
9d35b5de | 929 | |
a8693a21 | 930 | int |
9d35b5de ML |
931 | UTI_FdSetCloexec(int fd) |
932 | { | |
933 | int flags; | |
934 | ||
935 | flags = fcntl(fd, F_GETFD); | |
622769cd ML |
936 | if (flags == -1) { |
937 | DEBUG_LOG("fcntl() failed : %s", strerror(errno)); | |
938 | return 0; | |
9d35b5de | 939 | } |
a8693a21 | 940 | |
622769cd ML |
941 | flags |= FD_CLOEXEC; |
942 | ||
943 | if (fcntl(fd, F_SETFD, flags) < 0) { | |
944 | DEBUG_LOG("fcntl() failed : %s", strerror(errno)); | |
945 | return 0; | |
946 | } | |
947 | ||
948 | return 1; | |
9d35b5de ML |
949 | } |
950 | ||
951 | /* ================================================== */ | |
777303f1 | 952 | |
5bb2bf93 | 953 | void |
879d9362 | 954 | UTI_SetQuitSignalsHandler(void (*handler)(int), int ignore_sigpipe) |
ceef8ad2 | 955 | { |
206e597b ML |
956 | struct sigaction sa; |
957 | ||
958 | sa.sa_handler = handler; | |
959 | sa.sa_flags = SA_RESTART; | |
960 | if (sigemptyset(&sa.sa_mask) < 0) | |
5bb2bf93 | 961 | LOG_FATAL("sigemptyset() failed"); |
206e597b ML |
962 | |
963 | #ifdef SIGINT | |
964 | if (sigaction(SIGINT, &sa, NULL) < 0) | |
5bb2bf93 | 965 | LOG_FATAL("sigaction(%d) failed", SIGINT); |
206e597b ML |
966 | #endif |
967 | #ifdef SIGTERM | |
968 | if (sigaction(SIGTERM, &sa, NULL) < 0) | |
5bb2bf93 | 969 | LOG_FATAL("sigaction(%d) failed", SIGTERM); |
206e597b ML |
970 | #endif |
971 | #ifdef SIGQUIT | |
972 | if (sigaction(SIGQUIT, &sa, NULL) < 0) | |
5bb2bf93 | 973 | LOG_FATAL("sigaction(%d) failed", SIGQUIT); |
206e597b ML |
974 | #endif |
975 | #ifdef SIGHUP | |
976 | if (sigaction(SIGHUP, &sa, NULL) < 0) | |
5bb2bf93 | 977 | LOG_FATAL("sigaction(%d) failed", SIGHUP); |
206e597b | 978 | #endif |
879d9362 ML |
979 | |
980 | if (ignore_sigpipe) | |
981 | sa.sa_handler = SIG_IGN; | |
982 | ||
983 | if (sigaction(SIGPIPE, &sa, NULL) < 0) | |
984 | LOG_FATAL("sigaction(%d) failed", SIGPIPE); | |
ceef8ad2 | 985 | } |
92706b15 ML |
986 | |
987 | /* ================================================== */ | |
988 | ||
f1ed08ab ML |
989 | char * |
990 | UTI_PathToDir(const char *path) | |
991 | { | |
992 | char *dir, *slash; | |
993 | ||
994 | slash = strrchr(path, '/'); | |
995 | ||
996 | if (!slash) | |
997 | return Strdup("."); | |
998 | ||
999 | if (slash == path) | |
1000 | return Strdup("/"); | |
1001 | ||
1002 | dir = Malloc(slash - path + 1); | |
1003 | snprintf(dir, slash - path + 1, "%s", path); | |
1004 | ||
1005 | return dir; | |
1006 | } | |
1007 | ||
1008 | /* ================================================== */ | |
1009 | ||
92706b15 | 1010 | static int |
236576c1 | 1011 | create_dir(char *p, mode_t mode, uid_t uid, gid_t gid) |
92706b15 ML |
1012 | { |
1013 | int status; | |
1014 | struct stat buf; | |
1015 | ||
1016 | /* See if directory exists */ | |
1017 | status = stat(p, &buf); | |
1018 | ||
1019 | if (status < 0) { | |
236576c1 | 1020 | if (errno != ENOENT) { |
f282856c | 1021 | LOG(LOGS_ERR, "Could not access %s : %s", p, strerror(errno)); |
236576c1 | 1022 | return 0; |
92706b15 | 1023 | } |
236576c1 ML |
1024 | } else { |
1025 | if (S_ISDIR(buf.st_mode)) | |
1026 | return 1; | |
f282856c | 1027 | LOG(LOGS_ERR, "%s is not directory", p); |
236576c1 | 1028 | return 0; |
92706b15 ML |
1029 | } |
1030 | ||
236576c1 ML |
1031 | /* Create the directory */ |
1032 | if (mkdir(p, mode) < 0) { | |
f282856c | 1033 | LOG(LOGS_ERR, "Could not create directory %s : %s", p, strerror(errno)); |
236576c1 | 1034 | return 0; |
92706b15 ML |
1035 | } |
1036 | ||
30b62139 ML |
1037 | /* Set its owner */ |
1038 | if (chown(p, uid, gid) < 0) { | |
f282856c | 1039 | LOG(LOGS_ERR, "Could not change ownership of %s : %s", p, strerror(errno)); |
236576c1 ML |
1040 | /* Don't leave it there with incorrect ownership */ |
1041 | rmdir(p); | |
1042 | return 0; | |
1043 | } | |
1044 | ||
1045 | return 1; | |
92706b15 ML |
1046 | } |
1047 | ||
1048 | /* ================================================== */ | |
1049 | /* Return 0 if the directory couldn't be created, 1 if it could (or | |
1050 | already existed) */ | |
1051 | int | |
236576c1 | 1052 | UTI_CreateDirAndParents(const char *path, mode_t mode, uid_t uid, gid_t gid) |
92706b15 ML |
1053 | { |
1054 | char *p; | |
1055 | int i, j, k, last; | |
1056 | ||
9a83cab2 ML |
1057 | /* Don't try to create current directory */ |
1058 | if (!strcmp(path, ".")) | |
1059 | return 1; | |
1060 | ||
92706b15 ML |
1061 | p = (char *)Malloc(1 + strlen(path)); |
1062 | ||
1063 | i = k = 0; | |
1064 | while (1) { | |
1065 | p[i++] = path[k++]; | |
1066 | ||
1067 | if (path[k] == '/' || !path[k]) { | |
236576c1 | 1068 | /* Check whether its end of string, a trailing / or group of / */ |
92706b15 | 1069 | last = 1; |
236576c1 | 1070 | j = k; |
92706b15 ML |
1071 | while (path[j]) { |
1072 | if (path[j] != '/') { | |
236576c1 ML |
1073 | /* Pick up a / into p[] thru the assignment at the top of the loop */ |
1074 | k = j - 1; | |
92706b15 ML |
1075 | last = 0; |
1076 | break; | |
1077 | } | |
1078 | j++; | |
1079 | } | |
1080 | ||
236576c1 ML |
1081 | p[i] = 0; |
1082 | ||
1083 | if (!create_dir(p, last ? mode : 0755, last ? uid : 0, last ? gid : 0)) { | |
1084 | Free(p); | |
1085 | return 0; | |
1086 | } | |
1087 | ||
92706b15 ML |
1088 | if (last) |
1089 | break; | |
1090 | } | |
1091 | ||
1092 | if (!path[k]) | |
1093 | break; | |
1094 | } | |
1095 | ||
1096 | Free(p); | |
1097 | return 1; | |
1098 | } | |
f1ed08ab ML |
1099 | |
1100 | /* ================================================== */ | |
1101 | ||
1102 | int | |
1103 | UTI_CheckDirPermissions(const char *path, mode_t perm, uid_t uid, gid_t gid) | |
1104 | { | |
1105 | struct stat buf; | |
1106 | ||
1107 | if (stat(path, &buf)) { | |
f282856c | 1108 | LOG(LOGS_ERR, "Could not access %s : %s", path, strerror(errno)); |
f1ed08ab ML |
1109 | return 0; |
1110 | } | |
1111 | ||
1112 | if (!S_ISDIR(buf.st_mode)) { | |
f282856c | 1113 | LOG(LOGS_ERR, "%s is not directory", path); |
f1ed08ab ML |
1114 | return 0; |
1115 | } | |
1116 | ||
1117 | if ((buf.st_mode & 0777) & ~perm) { | |
f282856c | 1118 | LOG(LOGS_ERR, "Wrong permissions on %s", path); |
f1ed08ab ML |
1119 | return 0; |
1120 | } | |
1121 | ||
06486f31 | 1122 | if (buf.st_uid != uid) { |
9bc774d6 | 1123 | LOG(LOGS_ERR, "Wrong owner of %s (%s != %u)", path, "UID", uid); |
06486f31 ML |
1124 | return 0; |
1125 | } | |
1126 | ||
1127 | if (buf.st_gid != gid) { | |
9bc774d6 | 1128 | LOG(LOGS_ERR, "Wrong owner of %s (%s != %u)", path, "GID", gid); |
f1ed08ab ML |
1129 | return 0; |
1130 | } | |
1131 | ||
1132 | return 1; | |
1133 | } | |
6199a891 ML |
1134 | |
1135 | /* ================================================== */ | |
1136 | ||
7a4c396b ML |
1137 | static int |
1138 | join_path(const char *basedir, const char *name, const char *suffix, | |
1139 | char *buffer, size_t length, LOG_Severity severity) | |
1140 | { | |
1141 | const char *sep; | |
1142 | ||
1143 | if (!basedir) { | |
1144 | basedir = ""; | |
1145 | sep = ""; | |
1146 | } else { | |
1147 | sep = "/"; | |
1148 | } | |
1149 | ||
1150 | if (!suffix) | |
1151 | suffix = ""; | |
1152 | ||
1153 | if (snprintf(buffer, length, "%s%s%s%s", basedir, sep, name, suffix) >= length) { | |
1154 | LOG(severity, "File path %s%s%s%s too long", basedir, sep, name, suffix); | |
1155 | return 0; | |
1156 | } | |
1157 | ||
1158 | return 1; | |
1159 | } | |
1160 | ||
1161 | /* ================================================== */ | |
1162 | ||
1163 | FILE * | |
1164 | UTI_OpenFile(const char *basedir, const char *name, const char *suffix, | |
1165 | char mode, mode_t perm) | |
1166 | { | |
1167 | const char *file_mode; | |
1168 | char path[PATH_MAX]; | |
1169 | LOG_Severity severity; | |
1170 | int fd, flags; | |
1171 | FILE *file; | |
1172 | ||
1173 | severity = mode >= 'A' && mode <= 'Z' ? LOGS_FATAL : LOGS_ERR; | |
1174 | ||
1175 | if (!join_path(basedir, name, suffix, path, sizeof (path), severity)) | |
1176 | return NULL; | |
1177 | ||
1178 | switch (mode) { | |
1179 | case 'r': | |
1180 | case 'R': | |
1181 | flags = O_RDONLY; | |
1182 | file_mode = "r"; | |
1183 | if (severity != LOGS_FATAL) | |
1184 | severity = LOGS_DEBUG; | |
1185 | break; | |
1186 | case 'w': | |
1187 | case 'W': | |
1188 | flags = O_WRONLY | O_CREAT | O_EXCL; | |
1189 | file_mode = "w"; | |
1190 | break; | |
1191 | case 'a': | |
1192 | case 'A': | |
1193 | flags = O_WRONLY | O_CREAT | O_APPEND; | |
1194 | file_mode = "a"; | |
1195 | break; | |
1196 | default: | |
1197 | assert(0); | |
1198 | return NULL; | |
1199 | } | |
1200 | ||
1201 | try_again: | |
1202 | fd = open(path, flags, perm); | |
1203 | if (fd < 0) { | |
1204 | if (errno == EEXIST) { | |
1205 | if (unlink(path) < 0) { | |
1206 | LOG(severity, "Could not remove %s : %s", path, strerror(errno)); | |
1207 | return NULL; | |
1208 | } | |
1209 | DEBUG_LOG("Removed %s", path); | |
1210 | goto try_again; | |
1211 | } | |
1212 | LOG(severity, "Could not open %s : %s", path, strerror(errno)); | |
1213 | return NULL; | |
1214 | } | |
1215 | ||
1216 | UTI_FdSetCloexec(fd); | |
1217 | ||
1218 | file = fdopen(fd, file_mode); | |
1219 | if (!file) { | |
1220 | LOG(severity, "Could not open %s : %s", path, strerror(errno)); | |
1221 | close(fd); | |
1222 | return NULL; | |
1223 | } | |
1224 | ||
1225 | DEBUG_LOG("Opened %s fd=%d mode=%c", path, fd, mode); | |
1226 | ||
1227 | return file; | |
1228 | } | |
1229 | ||
1230 | /* ================================================== */ | |
1231 | ||
1232 | int | |
1233 | UTI_RenameTempFile(const char *basedir, const char *name, | |
1234 | const char *old_suffix, const char *new_suffix) | |
1235 | { | |
1236 | char old_path[PATH_MAX], new_path[PATH_MAX]; | |
1237 | ||
1238 | if (!join_path(basedir, name, old_suffix, old_path, sizeof (old_path), LOGS_ERR)) | |
1239 | return 0; | |
1240 | ||
1241 | if (!join_path(basedir, name, new_suffix, new_path, sizeof (new_path), LOGS_ERR)) | |
1242 | goto error; | |
1243 | ||
1244 | if (rename(old_path, new_path) < 0) { | |
1245 | LOG(LOGS_ERR, "Could not replace %s with %s : %s", new_path, old_path, strerror(errno)); | |
1246 | goto error; | |
1247 | } | |
1248 | ||
1249 | DEBUG_LOG("Renamed %s to %s", old_path, new_path); | |
1250 | ||
1251 | return 1; | |
1252 | ||
1253 | error: | |
1254 | if (unlink(old_path) < 0) | |
1255 | LOG(LOGS_ERR, "Could not remove %s : %s", old_path, strerror(errno)); | |
1256 | ||
1257 | return 0; | |
1258 | } | |
1259 | ||
1260 | /* ================================================== */ | |
1261 | ||
1262 | int | |
1263 | UTI_RemoveFile(const char *basedir, const char *name, const char *suffix) | |
1264 | { | |
1265 | char path[PATH_MAX]; | |
1858104b | 1266 | struct stat buf; |
7a4c396b ML |
1267 | |
1268 | if (!join_path(basedir, name, suffix, path, sizeof (path), LOGS_ERR)) | |
1269 | return 0; | |
1270 | ||
1858104b ML |
1271 | /* Avoid logging an error message if the file is not accessible */ |
1272 | if (stat(path, &buf) < 0) { | |
1273 | DEBUG_LOG("Could not remove %s : %s", path, strerror(errno)); | |
1274 | return 0; | |
1275 | } | |
1276 | ||
7a4c396b | 1277 | if (unlink(path) < 0) { |
1858104b | 1278 | LOG(LOGS_ERR, "Could not remove %s : %s", path, strerror(errno)); |
7a4c396b ML |
1279 | return 0; |
1280 | } | |
1281 | ||
1282 | DEBUG_LOG("Removed %s", path); | |
1283 | ||
1284 | return 1; | |
1285 | } | |
1286 | ||
1287 | /* ================================================== */ | |
1288 | ||
3cf6acdf ML |
1289 | void |
1290 | UTI_DropRoot(uid_t uid, gid_t gid) | |
1291 | { | |
1292 | /* Drop supplementary groups */ | |
1293 | if (setgroups(0, NULL)) | |
f282856c | 1294 | LOG_FATAL("setgroups() failed : %s", strerror(errno)); |
3cf6acdf ML |
1295 | |
1296 | /* Set effective, saved and real group ID */ | |
1297 | if (setgid(gid)) | |
9bc774d6 | 1298 | LOG_FATAL("setgid(%u) failed : %s", gid, strerror(errno)); |
3cf6acdf ML |
1299 | |
1300 | /* Set effective, saved and real user ID */ | |
1301 | if (setuid(uid)) | |
9bc774d6 | 1302 | LOG_FATAL("setuid(%u) failed : %s", uid, strerror(errno)); |
3cf6acdf | 1303 | |
9bc774d6 | 1304 | DEBUG_LOG("Dropped root privileges: UID %u GID %u", uid, gid); |
3cf6acdf ML |
1305 | } |
1306 | ||
1307 | /* ================================================== */ | |
1308 | ||
6199a891 ML |
1309 | #define DEV_URANDOM "/dev/urandom" |
1310 | ||
1311 | void | |
32ac6ffa | 1312 | UTI_GetRandomBytesUrandom(void *buf, unsigned int len) |
6199a891 | 1313 | { |
6199a891 | 1314 | static FILE *f = NULL; |
32ac6ffa | 1315 | |
6199a891 | 1316 | if (!f) |
e18903a6 | 1317 | f = UTI_OpenFile(NULL, DEV_URANDOM, NULL, 'R', 0); |
6199a891 | 1318 | if (fread(buf, 1, len, f) != len) |
f282856c | 1319 | LOG_FATAL("Can't read from %s", DEV_URANDOM); |
32ac6ffa ML |
1320 | } |
1321 | ||
1322 | /* ================================================== */ | |
1323 | ||
c5735ebf ML |
1324 | #ifdef HAVE_GETRANDOM |
1325 | static void | |
1326 | get_random_bytes_getrandom(char *buf, unsigned int len) | |
1327 | { | |
1328 | static char rand_buf[256]; | |
1329 | static unsigned int available = 0, disabled = 0; | |
1330 | unsigned int i; | |
1331 | ||
1332 | for (i = 0; i < len; i++) { | |
1333 | if (!available) { | |
1334 | if (disabled) | |
1335 | break; | |
1336 | ||
7c5bd948 | 1337 | if (getrandom(rand_buf, sizeof (rand_buf), GRND_NONBLOCK) != sizeof (rand_buf)) { |
c5735ebf ML |
1338 | disabled = 1; |
1339 | break; | |
1340 | } | |
1341 | ||
1342 | available = sizeof (rand_buf); | |
1343 | } | |
1344 | ||
1345 | buf[i] = rand_buf[--available]; | |
1346 | } | |
1347 | ||
1348 | if (i < len) | |
1349 | UTI_GetRandomBytesUrandom(buf, len); | |
1350 | } | |
1351 | #endif | |
1352 | ||
1353 | /* ================================================== */ | |
1354 | ||
32ac6ffa ML |
1355 | void |
1356 | UTI_GetRandomBytes(void *buf, unsigned int len) | |
1357 | { | |
1358 | #ifdef HAVE_ARC4RANDOM | |
1359 | arc4random_buf(buf, len); | |
c5735ebf ML |
1360 | #elif defined(HAVE_GETRANDOM) |
1361 | get_random_bytes_getrandom(buf, len); | |
32ac6ffa ML |
1362 | #else |
1363 | UTI_GetRandomBytesUrandom(buf, len); | |
6199a891 ML |
1364 | #endif |
1365 | } | |
e43d6999 ML |
1366 | |
1367 | /* ================================================== */ | |
1368 | ||
1369 | int | |
1370 | UTI_BytesToHex(const void *buf, unsigned int buf_len, char *hex, unsigned int hex_len) | |
1371 | { | |
1372 | unsigned int i, l; | |
1373 | ||
1374 | for (i = l = 0; i < buf_len; i++, l += 2) { | |
1375 | if (l + 2 >= hex_len || | |
1376 | snprintf(hex + l, hex_len - l, "%02hhX", ((const char *)buf)[i]) != 2) | |
1377 | return 0; | |
1378 | } | |
1379 | ||
1380 | return 1; | |
1381 | } | |
1382 | ||
1383 | /* ================================================== */ | |
1384 | ||
1385 | unsigned int | |
1386 | UTI_HexToBytes(const char *hex, void *buf, unsigned int len) | |
1387 | { | |
1388 | char *p, byte[3]; | |
1389 | unsigned int i; | |
1390 | ||
1391 | for (i = 0; i < len && *hex != '\0'; i++) { | |
1392 | byte[0] = *hex++; | |
1393 | if (*hex == '\0') | |
1394 | return 0; | |
1395 | byte[1] = *hex++; | |
1396 | byte[2] = '\0'; | |
1397 | ((char *)buf)[i] = strtol(byte, &p, 16); | |
1398 | ||
1399 | if (p != byte + 2) | |
1400 | return 0; | |
1401 | } | |
1402 | ||
1403 | return *hex == '\0' ? i : 0; | |
1404 | } | |
d6034263 ML |
1405 | |
1406 | /* ================================================== */ | |
1407 | ||
1408 | int | |
1409 | UTI_SplitString(char *string, char **words, int max_saved_words) | |
1410 | { | |
1411 | char *s = string; | |
1412 | int i; | |
1413 | ||
1414 | for (i = 0; i < max_saved_words; i++) | |
1415 | words[i] = NULL; | |
1416 | ||
1417 | for (i = 0; ; i++) { | |
1418 | /* Zero white-space characters before the word */ | |
1419 | while (*s != '\0' && isspace((unsigned char)*s)) | |
1420 | *s++ = '\0'; | |
1421 | ||
1422 | if (*s == '\0') | |
1423 | break; | |
1424 | ||
1425 | if (i < max_saved_words) | |
1426 | words[i] = s; | |
1427 | ||
1428 | /* Find the next word */ | |
1429 | while (*s != '\0' && !isspace((unsigned char)*s)) | |
1430 | s++; | |
1431 | } | |
1432 | ||
1433 | return i; | |
1434 | } |