/src/freeradius-server/src/lib/util/misc.c
Line | Count | Source |
1 | | /* |
2 | | * This library is free software; you can redistribute it and/or |
3 | | * modify it under the terms of the GNU Lesser General Public |
4 | | * License as published by the Free Software Foundation; either |
5 | | * version 2.1 of the License, or (at your option) any later version. |
6 | | * |
7 | | * This library is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
10 | | * Lesser General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU Lesser General Public |
13 | | * License along with this library; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
15 | | */ |
16 | | |
17 | | /** Various miscellaneous utility functions |
18 | | * |
19 | | * @file src/lib/util/misc.c |
20 | | * |
21 | | * @copyright 2000,2006 The FreeRADIUS server project |
22 | | */ |
23 | | RCSID("$Id: bf4c82aa58893f3fbc7cf3d98fbf52299fe213e6 $") |
24 | | |
25 | | #include <freeradius-devel/util/dbuff.h> |
26 | | #include <freeradius-devel/util/sbuff.h> |
27 | | #include <freeradius-devel/util/syserror.h> |
28 | | |
29 | | #include <string.h> |
30 | | #include <fcntl.h> |
31 | | #include <grp.h> |
32 | | #include <pwd.h> |
33 | | #include <sys/file.h> |
34 | | #include <sys/stat.h> |
35 | | #include <sys/uio.h> |
36 | | |
37 | | #define FR_PUT_LE16(a, val)\ |
38 | 0 | do {\ |
39 | 0 | a[1] = ((uint16_t) (val)) >> 8;\ |
40 | 0 | a[0] = ((uint16_t) (val)) & 0xff;\ |
41 | 0 | } while (0) |
42 | | |
43 | | /** Sets a signal handler using sigaction if available, else signal |
44 | | * |
45 | | * @param sig to set handler for. |
46 | | * @param func handler to set. |
47 | | */ |
48 | | int fr_set_signal(int sig, sig_t func) |
49 | 0 | { |
50 | 0 | #ifdef HAVE_SIGACTION |
51 | 0 | struct sigaction act; |
52 | |
|
53 | 0 | memset(&act, 0, sizeof(act)); |
54 | 0 | act.sa_flags = 0; |
55 | 0 | sigemptyset(&act.sa_mask); |
56 | 0 | act.sa_handler = func; |
57 | |
|
58 | 0 | if (sigaction(sig, &act, NULL) < 0) { |
59 | 0 | fr_strerror_printf("Failed setting signal %i handler via sigaction(): %s", sig, fr_syserror(errno)); |
60 | 0 | return -1; |
61 | 0 | } |
62 | | #else |
63 | | if (signal(sig, func) < 0) { |
64 | | fr_strerror_printf("Failed setting signal %i handler via signal(): %s", sig, fr_syserror(errno)); |
65 | | return -1; |
66 | | } |
67 | | #endif |
68 | 0 | return 0; |
69 | 0 | } |
70 | | |
71 | | /** Uninstall a signal for a specific handler |
72 | | * |
73 | | * man sigaction says these are fine to call from a signal handler. |
74 | | * |
75 | | * @param sig SIGNAL |
76 | | */ |
77 | | int fr_unset_signal(int sig) |
78 | 0 | { |
79 | 0 | #ifdef HAVE_SIGACTION |
80 | 0 | struct sigaction act; |
81 | |
|
82 | 0 | memset(&act, 0, sizeof(act)); |
83 | 0 | act.sa_flags = 0; |
84 | 0 | sigemptyset(&act.sa_mask); |
85 | 0 | act.sa_handler = SIG_DFL; |
86 | |
|
87 | 0 | return sigaction(sig, &act, NULL); |
88 | | #else |
89 | | return signal(sig, SIG_DFL); |
90 | | #endif |
91 | 0 | } |
92 | | |
93 | | #ifndef F_WRLCK |
94 | | #error "missing definition for F_WRLCK, all file locks will fail" |
95 | | #endif |
96 | | |
97 | | /* |
98 | | * cppcheck apparently can't pick this up from the system headers. |
99 | | */ |
100 | | #ifdef CPPCHECK |
101 | | #define F_WRLCK |
102 | | #endif |
103 | | |
104 | | static int rad_lock(int fd, int lock_len, int cmd, int type) |
105 | 0 | { |
106 | 0 | struct flock fl; |
107 | |
|
108 | 0 | fl.l_start = 0; |
109 | 0 | fl.l_len = lock_len; |
110 | 0 | fl.l_pid = getpid(); |
111 | 0 | fl.l_type = type; |
112 | 0 | fl.l_whence = SEEK_CUR; |
113 | |
|
114 | 0 | return fcntl(fd, cmd, (void *)&fl); |
115 | 0 | } |
116 | | |
117 | | /* |
118 | | * Internal wrapper for locking, to minimize the number of ifdef's |
119 | | */ |
120 | | int rad_lockfd(int fd, int lock_len) |
121 | 0 | { |
122 | 0 | return rad_lock(fd, lock_len, F_SETLKW, F_WRLCK); |
123 | 0 | } |
124 | | |
125 | | /* |
126 | | * Internal wrapper for locking, to minimize the number of ifdef's |
127 | | * |
128 | | * Nonblocking version. |
129 | | */ |
130 | | int rad_lockfd_nonblock(int fd, int lock_len) |
131 | 0 | { |
132 | | /* |
133 | | * Note that there's no "W" on SETLK |
134 | | */ |
135 | 0 | return rad_lock(fd, lock_len, F_SETLK, F_WRLCK); |
136 | 0 | } |
137 | | |
138 | | /* |
139 | | * Internal wrapper for unlocking, to minimize the number of ifdef's |
140 | | * in the source. |
141 | | */ |
142 | | int rad_unlockfd(int fd, int lock_len) |
143 | 0 | { |
144 | | /* |
145 | | * Note UNLOCK. |
146 | | */ |
147 | 0 | return rad_lock(fd, lock_len, F_SETLK, F_UNLCK); |
148 | 0 | } |
149 | | |
150 | | /** Consume the integer (or hex) portion of a value string |
151 | | * |
152 | | * Allows integer or hex representations of integers (but not octal, |
153 | | * as octal is deemed to be confusing). |
154 | | * |
155 | | * @param[out] out Result of parsing string as unsigned 64bit integer. |
156 | | * @param[out] end pointer to the first non numeric char. |
157 | | * @param[in] value string to parse. |
158 | | * |
159 | | * @return integer value. |
160 | | */ |
161 | | int fr_strtoull(uint64_t *out, char **end, char const *value) |
162 | 0 | { |
163 | 0 | errno = 0; /* Explicitly clear errors, as glibc appears not to do this */ |
164 | |
|
165 | 0 | if ((value[0] == '0') && (value[1] == 'x')) { |
166 | 0 | *out = strtoull(value, end, 16); |
167 | 0 | if (errno == ERANGE) { |
168 | 0 | error: |
169 | 0 | fr_strerror_printf("Unsigned integer value \"%s\" too large, would overflow", value); |
170 | 0 | return -1; |
171 | 0 | } |
172 | 0 | return 0; |
173 | 0 | } |
174 | | |
175 | 0 | *out = strtoull(value, end, 10); |
176 | 0 | if (errno == ERANGE) goto error; |
177 | 0 | return 0; |
178 | 0 | } |
179 | | |
180 | | /** Consume the integer (or hex) portion of a value string |
181 | | * |
182 | | * Allows integer or hex representations of integers (but not octal, |
183 | | * as octal is deemed to be confusing). |
184 | | * |
185 | | * @note Check for overflow with errno == ERANGE. |
186 | | * |
187 | | * @param[out] out Result of parsing string as signed 64bit integer. |
188 | | * @param[out] end pointer to the first non numeric char. |
189 | | * @param[in] value string to parse. |
190 | | * @return integer value. |
191 | | */ |
192 | | int fr_strtoll(int64_t *out, char **end, char const *value) |
193 | 0 | { |
194 | 0 | errno = 0; /* Explicitly clear errors, as glibc appears not to do this */ |
195 | |
|
196 | 0 | if ((value[0] == '0') && (value[1] == 'x')) { |
197 | 0 | *out = strtoll(value, end, 16); |
198 | 0 | if (errno == ERANGE) { |
199 | 0 | error: |
200 | 0 | fr_strerror_printf("Signed integer value \"%s\" too large, would overflow", value); |
201 | 0 | return -1; |
202 | 0 | } |
203 | 0 | return 0; |
204 | 0 | } |
205 | | |
206 | 0 | *out = strtoll(value, end, 10); |
207 | 0 | if (errno == ERANGE) goto error; |
208 | 0 | return 0; |
209 | 0 | } |
210 | | |
211 | | /** Trim whitespace from the end of a string |
212 | | * |
213 | | */ |
214 | | char *fr_trim(char const *str, size_t size) |
215 | 0 | { |
216 | 0 | char *q; |
217 | |
|
218 | 0 | if (!str || !size) return NULL; |
219 | | |
220 | 0 | memcpy(&q, &str, sizeof(q)); |
221 | 0 | for (q = q + size; q > str && isspace((uint8_t) *q); q--); |
222 | |
|
223 | 0 | return q; |
224 | 0 | } |
225 | | |
226 | | char *fr_tolower(char *str) |
227 | 8 | { |
228 | 8 | char *p; |
229 | | |
230 | 56 | for (p = str; *p != '\0'; p++) *p = tolower(*p); |
231 | | |
232 | 8 | return str; |
233 | 8 | } |
234 | | |
235 | | #ifdef O_NONBLOCK |
236 | | /** Set O_NONBLOCK on a socket |
237 | | * |
238 | | * @note O_NONBLOCK is POSIX. |
239 | | * |
240 | | * @param fd to set nonblocking flag on. |
241 | | * @return |
242 | | * - Flags set on the socket. |
243 | | * - -1 on failure. |
244 | | */ |
245 | | int fr_nonblock(int fd) |
246 | 0 | { |
247 | 0 | int flags; |
248 | |
|
249 | 0 | flags = fcntl(fd, F_GETFL, NULL); |
250 | 0 | if (flags < 0) { |
251 | 0 | fr_strerror_printf("Failed getting socket flags: %s", fr_syserror(errno)); |
252 | 0 | return -1; |
253 | 0 | } |
254 | | |
255 | 0 | flags |= O_NONBLOCK; |
256 | 0 | if (fcntl(fd, F_SETFL, flags) < 0) { |
257 | 0 | fr_strerror_printf("Failed setting socket flags: %s", fr_syserror(errno)); |
258 | 0 | return -1; |
259 | 0 | } |
260 | | |
261 | 0 | return flags; |
262 | 0 | } |
263 | | |
264 | | /** Unset O_NONBLOCK on a socket |
265 | | * |
266 | | * @note O_NONBLOCK is POSIX. |
267 | | * |
268 | | * @param fd to set nonblocking flag on. |
269 | | * @return |
270 | | * - Flags set on the socket. |
271 | | * - -1 on failure. |
272 | | */ |
273 | | int fr_blocking(int fd) |
274 | 0 | { |
275 | 0 | int flags; |
276 | |
|
277 | 0 | flags = fcntl(fd, F_GETFL, NULL); |
278 | 0 | if (flags < 0) { |
279 | 0 | fr_strerror_printf("Failed getting socket flags: %s", fr_syserror(errno)); |
280 | 0 | return -1; |
281 | 0 | } |
282 | | |
283 | 0 | if (!(flags & O_NONBLOCK)) return flags; |
284 | | |
285 | 0 | flags ^= O_NONBLOCK; |
286 | 0 | if (fcntl(fd, F_SETFL, flags) < 0) { |
287 | 0 | fr_strerror_printf("Failed setting socket flags: %s", fr_syserror(errno)); |
288 | 0 | return -1; |
289 | 0 | } |
290 | | |
291 | 0 | return flags; |
292 | 0 | } |
293 | | #else |
294 | | int fr_nonblock(UNUSED int fd) |
295 | | { |
296 | | fr_strerror_const("Non blocking sockets are not supported"); |
297 | | return -1; |
298 | | } |
299 | | int fr_blocking(UNUSED int fd) |
300 | | { |
301 | | fr_strerror_const("Non blocking sockets are not supported"); |
302 | | return -1; |
303 | | } |
304 | | #endif |
305 | | |
306 | | /** Convert UTF8 string to UCS2 encoding |
307 | | * |
308 | | * @note Borrowed from src/crypto/ms_funcs.c of wpa_supplicant project (http://hostap.epitest.fi/wpa_supplicant/) |
309 | | * |
310 | | * @param[out] out Where to write the ucs2 string. |
311 | | * @param[in] outlen Size of output buffer. |
312 | | * @param[in] in UTF8 string to convert. |
313 | | * @param[in] inlen length of UTF8 string. |
314 | | * @return the size of the UCS2 string written to the output buffer (in bytes). |
315 | | */ |
316 | | ssize_t fr_utf8_to_ucs2(uint8_t *out, size_t outlen, char const *in, size_t inlen) |
317 | 0 | { |
318 | 0 | size_t i; |
319 | 0 | uint8_t *start = out; |
320 | |
|
321 | 0 | for (i = 0; i < inlen; i++) { |
322 | 0 | uint8_t c, c2, c3; |
323 | |
|
324 | 0 | c = in[i]; |
325 | 0 | if ((size_t)(out - start) >= outlen) { |
326 | | /* input too long */ |
327 | 0 | return -1; |
328 | 0 | } |
329 | | |
330 | | /* One-byte encoding */ |
331 | 0 | if (c <= 0x7f) { |
332 | 0 | out[0] = (uint8_t)c; |
333 | 0 | out[1] = 0; |
334 | 0 | out += 2; |
335 | 0 | continue; |
336 | 0 | } else if ((i == (inlen - 1)) || ((size_t)(out - start) >= (outlen - 1))) { |
337 | | /* Incomplete surrogate */ |
338 | 0 | return -1; |
339 | 0 | } |
340 | | |
341 | 0 | c2 = in[++i]; |
342 | | /* Two-byte encoding */ |
343 | 0 | if ((c & 0xe0) == 0xc0) { |
344 | 0 | FR_PUT_LE16(out, ((c & 0x1f) << 6) | (c2 & 0x3f)); |
345 | 0 | out += 2; |
346 | 0 | continue; |
347 | 0 | } |
348 | 0 | if ((i == inlen) || ((size_t)(out - start) >= (outlen - 1))) { |
349 | | /* Incomplete surrogate */ |
350 | 0 | return -1; |
351 | 0 | } |
352 | | |
353 | | /* Three-byte encoding */ |
354 | 0 | c3 = in[++i]; |
355 | 0 | FR_PUT_LE16(out, ((c & 0xf) << 12) | ((c2 & 0x3f) << 6) | (c3 & 0x3f)); |
356 | 0 | out += 2; |
357 | 0 | } |
358 | | |
359 | 0 | return out - start; |
360 | 0 | } |
361 | | |
362 | | /** Write 128bit unsigned integer to buffer |
363 | | * |
364 | | * @author Alexey Frunze |
365 | | * |
366 | | * @param out where to write result to. |
367 | | * @param outlen size of out. |
368 | | * @param num 128 bit integer. |
369 | | */ |
370 | | size_t fr_snprint_uint128(char *out, size_t outlen, uint128_t const num) |
371 | 0 | { |
372 | 0 | char buff[] = "00000000000000000000000000000000000000000000"; |
373 | 0 | uint64_t n[2]; |
374 | 0 | char *p = buff; |
375 | 0 | int i; |
376 | 0 | #ifndef WORDS_BIGENDIAN |
377 | 0 | size_t const l = 0; |
378 | 0 | size_t const h = 1; |
379 | | #else |
380 | | size_t const l = 1; |
381 | | size_t const h = 0; |
382 | | #endif |
383 | |
|
384 | 0 | memcpy(n, &num, sizeof(n)); |
385 | |
|
386 | 0 | for (i = 0; i < 128; i++) { |
387 | 0 | ssize_t j; |
388 | 0 | int carry; |
389 | |
|
390 | 0 | carry = (n[h] >= 0x8000000000000000); |
391 | | |
392 | | // Shift n[] left, doubling it |
393 | 0 | n[h] = ((n[h] << 1) & 0xffffffffffffffff) + (n[l] >= 0x8000000000000000); |
394 | 0 | n[l] = ((n[l] << 1) & 0xffffffffffffffff); |
395 | | |
396 | | // Add s[] to itself in float, doubling it |
397 | 0 | for (j = sizeof(buff) - 2; j >= 0; j--) { |
398 | 0 | buff[j] += buff[j] - '0' + carry; |
399 | 0 | carry = (buff[j] > '9'); |
400 | 0 | if (carry) buff[j] -= 10; |
401 | 0 | } |
402 | 0 | } |
403 | |
|
404 | 0 | while ((*p == '0') && (p < &buff[sizeof(buff) - 2])) p++; |
405 | |
|
406 | 0 | return strlcpy(out, p, outlen); |
407 | 0 | } |
408 | | |
409 | | /** Compares two pointers |
410 | | * |
411 | | * @param a first pointer to compare. |
412 | | * @param b second pointer to compare. |
413 | | * @return |
414 | | * - -1 if a < b. |
415 | | * - +1 if b > a. |
416 | | * - 0 if both equal. |
417 | | */ |
418 | | int8_t fr_pointer_cmp(void const *a, void const *b) |
419 | 0 | { |
420 | 0 | return CMP(a, b); |
421 | 0 | } |
422 | | |
423 | | /** Quick sort an array of pointers using a comparator |
424 | | * |
425 | | * @param to_sort array of pointers to sort. |
426 | | * @param start the lowest index (usually 0). |
427 | | * @param end the length of the array. |
428 | | * @param cmp the comparison function to use to sort the array elements. |
429 | | */ |
430 | | void fr_quick_sort(void const *to_sort[], int start, int end, fr_cmp_t cmp) |
431 | 0 | { |
432 | 0 | int i, pi; |
433 | 0 | void const *pivot; |
434 | |
|
435 | 0 | if (start >= end) return; |
436 | | |
437 | 0 | #define SWAP(_a, _b) \ |
438 | 0 | do { \ |
439 | 0 | void const *_tmp = to_sort[_a]; \ |
440 | 0 | to_sort[_a] = to_sort[_b]; \ |
441 | 0 | to_sort[_b] = _tmp; \ |
442 | 0 | } while (0) |
443 | | |
444 | 0 | pivot = to_sort[end]; |
445 | 0 | for (pi = start, i = start; i < end; i++) { |
446 | 0 | if (cmp(to_sort[i], pivot) < 0) { |
447 | 0 | SWAP(i , pi); |
448 | 0 | pi++; |
449 | 0 | } |
450 | 0 | } |
451 | 0 | SWAP(end, pi); |
452 | |
|
453 | 0 | fr_quick_sort(to_sort, start, pi - 1, cmp); |
454 | 0 | fr_quick_sort(to_sort, pi + 1, end, cmp); |
455 | 0 | } |
456 | | |
457 | | #ifdef TALLOC_DEBUG |
458 | | void fr_talloc_verify_cb(UNUSED const void *ptr, UNUSED int depth, |
459 | | UNUSED int max_depth, UNUSED int is_ref, |
460 | | UNUSED void *private_data) |
461 | | { |
462 | | /* do nothing */ |
463 | | } |
464 | | #endif |
465 | | |
466 | | |
467 | | /** Do a comparison of two authentication digests by comparing the FULL data. |
468 | | * |
469 | | * Otherwise, the server can be subject to timing attacks. |
470 | | * |
471 | | * http://www.cs.rice.edu/~dwallach/pub/crosby-timing2009.pdf |
472 | | */ |
473 | | int fr_digest_cmp(uint8_t const *a, uint8_t const *b, size_t length) |
474 | 0 | { |
475 | 0 | int result = 0; |
476 | 0 | size_t i; |
477 | |
|
478 | 0 | for (i = 0; i < length; i++) result |= a[i] ^ b[i]; |
479 | |
|
480 | 0 | return result; /* 0 is OK, !0 is !OK, just like memcmp */ |
481 | 0 | } |
482 | | |
483 | | /** Get the filename from a path |
484 | | * |
485 | | * @param path to get filename from. |
486 | | * @return |
487 | | * - pointer to the filename in the path. |
488 | | * - pointer to the path if no '/' is found. |
489 | | */ |
490 | | char const *fr_filename(char const *path) |
491 | 0 | { |
492 | 0 | char const *p = strrchr(path, '/'); |
493 | |
|
494 | 0 | if (p) return p + 1; |
495 | | |
496 | 0 | return path; |
497 | 0 | } |
498 | | |
499 | | /** Trim a common prefix from a filename |
500 | | * |
501 | | * @param path to get filename from. |
502 | | * @param common prefix to trim from the path. |
503 | | * @return |
504 | | * - pointer to the position on the path where the common prefix match ended. |
505 | | */ |
506 | | char const *fr_filename_common_trim(char const *path, char const *common) |
507 | 0 | { |
508 | 0 | char const *p_p, *p_c, *p_pn, *p_cn; |
509 | |
|
510 | 0 | if (!path) return NULL; |
511 | 0 | if (!common) return NULL; |
512 | | |
513 | 0 | p_p = path; |
514 | 0 | p_c = common; |
515 | |
|
516 | 0 | while ((p_pn = strchr(p_p, '/')) != NULL) { |
517 | 0 | p_cn = strchr(p_c, '/'); |
518 | 0 | if (!p_cn) p_cn = p_c + strlen(p_c); |
519 | |
|
520 | 0 | if ((p_pn - p_p) != (p_cn - p_c)) break; /* path component not the same len */ |
521 | 0 | if (strncmp(p_p, p_c, p_pn - p_p) != 0) break; /* path component not the same */ |
522 | | |
523 | 0 | p_p = p_pn + 1; |
524 | 0 | p_c = p_cn + 1; |
525 | 0 | } |
526 | |
|
527 | 0 | return p_p; |
528 | 0 | } |