/src/freeradius-server/src/lib/util/missing.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 | | /** Replacements for functions that are or can be missing on some platforms |
18 | | * |
19 | | * @file src/lib/util/missing.c |
20 | | * |
21 | | * @copyright 2000,2006 The FreeRADIUS server project |
22 | | */ |
23 | | RCSID("$Id: 65cd304c9cb8c036bd5195a8459ba4874c20ebde $") |
24 | | |
25 | | #include <freeradius-devel/missing.h> |
26 | | |
27 | | #include <ctype.h> |
28 | | #include <pthread.h> |
29 | | #include <stdbool.h> |
30 | | |
31 | | #if !defined(HAVE_CLOCK_GETTIME) && defined(__MACH__) |
32 | | # include <mach/mach_time.h> |
33 | | #endif |
34 | | |
35 | | #ifndef HAVE_STRNCASECMP |
36 | | int strncasecmp(char *s1, char *s2, int n) |
37 | | { |
38 | | int dif; |
39 | | unsigned char *p1, *p2; |
40 | | int c1, c2; |
41 | | |
42 | | p1 = (unsigned char *)s1; |
43 | | p2 = (unsigned char *)s2; |
44 | | dif = 0; |
45 | | |
46 | | while (n != 0) { |
47 | | if (*p1 == 0 && *p2 == 0) |
48 | | break; |
49 | | c1 = *p1; |
50 | | c2 = *p2; |
51 | | |
52 | | if (islower(c1)) c1 = toupper(c1); |
53 | | if (islower(c2)) c2 = toupper(c2); |
54 | | |
55 | | if ((dif = c1 - c2) != 0) |
56 | | break; |
57 | | p1++; |
58 | | p2++; |
59 | | n--; |
60 | | } |
61 | | return dif; |
62 | | } |
63 | | #endif |
64 | | |
65 | | #ifndef HAVE_STRCASECMP |
66 | | int strcasecmp(char *s1, char *s2) |
67 | | { |
68 | | int l1, l2; |
69 | | |
70 | | l1 = strlen(s1); |
71 | | l2 = strlen(s2); |
72 | | if (l2 > l1) l1 = l2; |
73 | | |
74 | | return strncasecmp(s1, s2, l1); |
75 | | } |
76 | | #endif |
77 | | |
78 | | |
79 | | #ifndef HAVE_MEMRCHR |
80 | | /** GNU libc extension on some platforms |
81 | | * |
82 | | */ |
83 | | void *memrchr(void const *s, int c, size_t n) |
84 | | { |
85 | | uint8_t *p; |
86 | | |
87 | | if (n == 0) return NULL; |
88 | | |
89 | | memcpy(&p, &s, sizeof(p)); /* defeat const */ |
90 | | for (p += (n - 1); p >= (uint8_t const *)s; p--) if (*p == (uint8_t)c) return (void *)p; |
91 | | |
92 | | return NULL; |
93 | | } |
94 | | #endif |
95 | | |
96 | | #ifndef HAVE_INET_ATON |
97 | | int inet_aton(char const *cp, struct in_addr *inp) |
98 | | { |
99 | | int a1, a2, a3, a4; |
100 | | |
101 | | if (sscanf(cp, "%d.%d.%d.%d", &a1, &a2, &a3, &a4) != 4) |
102 | | return 0; |
103 | | |
104 | | inp->s_addr = htonl((a1 << 24) + (a2 << 16) + (a3 << 8) + a4); |
105 | | return 1; |
106 | | } |
107 | | #endif |
108 | | |
109 | | #ifndef HAVE_STRSEP |
110 | | /* |
111 | | * Get next token from string *stringp, where tokens are |
112 | | * possibly-empty strings separated by characters from delim. |
113 | | * |
114 | | * Writes NULs into the string at *stringp to end tokens. |
115 | | * delim need not remain constant from call to call. On |
116 | | * return, *stringp points past the last NUL written (if there |
117 | | * might be further tokens), or is NULL (if there are |
118 | | * definitely no more tokens). |
119 | | * |
120 | | * If *stringp is NULL, strsep returns NULL. |
121 | | */ |
122 | | char * |
123 | | strsep(char **stringp, char const *delim) |
124 | | { |
125 | | char *s; |
126 | | char const *spanp; |
127 | | int c, sc; |
128 | | char *tok; |
129 | | |
130 | | if ((s = *stringp) == NULL) |
131 | | return (NULL); |
132 | | |
133 | | for (tok = s;;) { |
134 | | c = *s++; |
135 | | spanp = delim; |
136 | | do { |
137 | | if ((sc = *spanp++) == c) { |
138 | | if (c == 0) |
139 | | s = NULL; |
140 | | else |
141 | | s[-1] = 0; |
142 | | *stringp = s; |
143 | | return (tok); |
144 | | } |
145 | | } while (sc != 0); |
146 | | } |
147 | | |
148 | | return NULL; /* NOTREACHED, but the compiler complains */ |
149 | | } |
150 | | #endif |
151 | | |
152 | | #ifndef HAVE_LOCALTIME_R |
153 | | /* |
154 | | * We use localtime_r() by default in the server. |
155 | | * |
156 | | * For systems which do NOT have localtime_r(), we make the |
157 | | * assumption that localtime() is re-entrant, and returns a |
158 | | * per-thread data structure. |
159 | | * |
160 | | * Even if localtime is NOT re-entrant, this function will |
161 | | * lower the possibility of race conditions. |
162 | | */ |
163 | | struct tm *localtime_r(time_t const *l_clock, struct tm *result) |
164 | | { |
165 | | memcpy(result, localtime(l_clock), sizeof(*result)); |
166 | | |
167 | | return result; |
168 | | } |
169 | | #endif |
170 | | |
171 | | #ifndef HAVE_CTIME_R |
172 | | /* |
173 | | * We use ctime_r() by default in the server. |
174 | | * |
175 | | * For systems which do NOT have ctime_r(), we make the |
176 | | * assumption that ctime() is re-entrant, and returns a |
177 | | * per-thread data structure. |
178 | | * |
179 | | * Even if ctime is NOT re-entrant, this function will |
180 | | * lower the possibility of race conditions. |
181 | | */ |
182 | | char *ctime_r(time_t const *l_clock, char *l_buf) |
183 | | { |
184 | | strcpy(l_buf, ctime(l_clock)); |
185 | | |
186 | | return l_buf; |
187 | | } |
188 | | #endif |
189 | | |
190 | | #ifndef HAVE_GMTIME_R |
191 | | /* |
192 | | * We use gmtime_r() by default in the server. |
193 | | * |
194 | | * For systems which do NOT have gmtime_r(), we make the |
195 | | * assumption that gmtime() is re-entrant, and returns a |
196 | | * per-thread data structure. |
197 | | * |
198 | | * Even if gmtime is NOT re-entrant, this function will |
199 | | * lower the possibility of race conditions. |
200 | | */ |
201 | | struct tm *gmtime_r(time_t const *l_clock, struct tm *result) |
202 | | { |
203 | | memcpy(result, gmtime(l_clock), sizeof(*result)); |
204 | | |
205 | | return result; |
206 | | } |
207 | | #endif |
208 | | |
209 | | #ifndef HAVE_VDPRINTF |
210 | | int vdprintf (int fd, char const *format, va_list args) |
211 | | { |
212 | | int ret; |
213 | | FILE *fp; |
214 | | int dup_fd; |
215 | | |
216 | | dup_fd = dup(fd); |
217 | | if (dup_fd < 0) return -1; |
218 | | |
219 | | fp = fdopen(fd, "w"); |
220 | | if (!fp) { |
221 | | close(dup_fd); |
222 | | return -1; |
223 | | } |
224 | | |
225 | | ret = vfprintf(fp, format, args); |
226 | | fclose(fp); /* Also closes dup_fd */ |
227 | | |
228 | | return ret; |
229 | | } |
230 | | #endif |
231 | | |
232 | | |
233 | | #if !defined(HAVE_CLOCK_GETTIME) && defined(__MACH__) |
234 | | int clock_gettime(int clk_id, struct timespec *t) |
235 | | { |
236 | | static mach_timebase_info_data_t timebase; |
237 | | static bool done_init = false; |
238 | | |
239 | | static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; |
240 | | |
241 | | if (!done_init) { |
242 | | pthread_mutex_lock(&mutex); |
243 | | if (!done_init) { |
244 | | mach_timebase_info(&timebase); |
245 | | done_init = true; |
246 | | } |
247 | | pthread_mutex_unlock(&mutex); |
248 | | } |
249 | | |
250 | | switch (clk_id) { |
251 | | case CLOCK_REALTIME: |
252 | | return -1; |
253 | | |
254 | | case CLOCK_MONOTONIC: |
255 | | { |
256 | | uint64_t time; |
257 | | time = mach_absolute_time(); |
258 | | double nanoseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom); |
259 | | double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9); |
260 | | t->tv_sec = seconds; |
261 | | t->tv_nsec = nanoseconds; |
262 | | } |
263 | | return 0; |
264 | | |
265 | | default: |
266 | | errno = EINVAL; |
267 | | return -1; |
268 | | } |
269 | | } |
270 | | #endif |
271 | | |
272 | | /* |
273 | | * Replacements in case we don't have inet_pton |
274 | | */ |
275 | | #ifndef HAVE_INET_PTON |
276 | | static int inet_pton4(char const *src, struct in_addr *dst) |
277 | | { |
278 | | int octet; |
279 | | unsigned int num; |
280 | | char const *p, *off; |
281 | | uint8_t tmp[4]; |
282 | | static char const digits[] = "0123456789"; |
283 | | |
284 | | octet = 0; |
285 | | p = src; |
286 | | while (1) { |
287 | | num = 0; |
288 | | while (*p && ((off = strchr(digits, *p)) != NULL)) { |
289 | | num *= 10; |
290 | | num += (off - digits); |
291 | | |
292 | | if (num > 255) return 0; |
293 | | |
294 | | p++; |
295 | | } |
296 | | if (!*p) break; |
297 | | |
298 | | /* |
299 | | * Not a digit, MUST be a dot, else we |
300 | | * die. |
301 | | */ |
302 | | if (*p != '.') { |
303 | | return 0; |
304 | | } |
305 | | |
306 | | tmp[octet++] = num; |
307 | | p++; |
308 | | } |
309 | | |
310 | | /* |
311 | | * End of the string. At the fourth |
312 | | * octet is OK, anything else is an |
313 | | * error. |
314 | | */ |
315 | | if (octet != 3) { |
316 | | return 0; |
317 | | } |
318 | | tmp[3] = num; |
319 | | |
320 | | memcpy(dst, &tmp, sizeof(tmp)); |
321 | | return 1; |
322 | | } |
323 | | |
324 | | |
325 | | # ifdef HAVE_STRUCT_SOCKADDR_IN6 |
326 | | /** Convert presentation level address to network order binary form |
327 | | * |
328 | | * @note Does not touch dst unless it's returning 1. |
329 | | * @note :: in a full address is silently ignored. |
330 | | * @note Inspired by Mark Andrews. |
331 | | * @author Paul Vixie, 1996. |
332 | | * |
333 | | * @param src presentation level address. |
334 | | * @param dst where to write output address. |
335 | | * @return |
336 | | * - 1 if `src' is a valid [RFC1884 2.2] address. |
337 | | * - 0 if `src' in not a valid [RFC1884 2.2] address. |
338 | | */ |
339 | | static int inet_pton6(char const *src, unsigned char *dst) |
340 | | { |
341 | | static char const xdigits_l[] = "0123456789abcdef", |
342 | | xdigits_u[] = "0123456789ABCDEF"; |
343 | | uint8_t tmp[IN6ADDRSZ], *tp, *endp, *colonp; |
344 | | char const *xdigits, *curtok; |
345 | | int ch, saw_xdigit; |
346 | | u_int val; |
347 | | |
348 | | memset((tp = tmp), 0, IN6ADDRSZ); |
349 | | endp = tp + IN6ADDRSZ; |
350 | | colonp = NULL; |
351 | | /* Leading :: requires some special handling. */ |
352 | | if (*src == ':') |
353 | | if (*++src != ':') |
354 | | return (0); |
355 | | curtok = src; |
356 | | saw_xdigit = 0; |
357 | | val = 0; |
358 | | while ((ch = *src++) != '\0') { |
359 | | char const *pch; |
360 | | |
361 | | if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) |
362 | | pch = strchr((xdigits = xdigits_u), ch); |
363 | | if (pch != NULL) { |
364 | | val <<= 4; |
365 | | val |= (pch - xdigits); |
366 | | if (val > 0xffff) |
367 | | return (0); |
368 | | saw_xdigit = 1; |
369 | | continue; |
370 | | } |
371 | | if (ch == ':') { |
372 | | curtok = src; |
373 | | if (!saw_xdigit) { |
374 | | if (colonp) |
375 | | return (0); |
376 | | colonp = tp; |
377 | | continue; |
378 | | } |
379 | | if (tp + INT16SZ > endp) |
380 | | return (0); |
381 | | *tp++ = (uint8_t) (val >> 8) & 0xff; |
382 | | *tp++ = (uint8_t) val & 0xff; |
383 | | saw_xdigit = 0; |
384 | | val = 0; |
385 | | continue; |
386 | | } |
387 | | if (ch == '.' && ((tp + INADDRSZ) <= endp) && |
388 | | inet_pton4(curtok, (struct in_addr *) tp) > 0) { |
389 | | tp += INADDRSZ; |
390 | | saw_xdigit = 0; |
391 | | break; /* '\0' was seen by inet_pton4(). */ |
392 | | } |
393 | | return (0); |
394 | | } |
395 | | if (saw_xdigit) { |
396 | | if (tp + INT16SZ > endp) |
397 | | return (0); |
398 | | *tp++ = (uint8_t) (val >> 8) & 0xff; |
399 | | *tp++ = (uint8_t) val & 0xff; |
400 | | } |
401 | | if (colonp != NULL) { |
402 | | /* |
403 | | * Since some memmove()'s erroneously fail to handle |
404 | | * overlapping regions, we'll do the shift by hand. |
405 | | */ |
406 | | int const n = tp - colonp; |
407 | | int i; |
408 | | |
409 | | for (i = 1; i <= n; i++) { |
410 | | endp[- i] = colonp[n - i]; |
411 | | colonp[n - i] = 0; |
412 | | } |
413 | | tp = endp; |
414 | | } |
415 | | if (tp != endp) |
416 | | return (0); |
417 | | /* bcopy(tmp, dst, IN6ADDRSZ); */ |
418 | | memcpy(dst, tmp, IN6ADDRSZ); |
419 | | return (1); |
420 | | } |
421 | | # endif |
422 | | |
423 | | /* |
424 | | * Utility function, so that the rest of the server doesn't |
425 | | * have ifdef's around IPv6 support |
426 | | */ |
427 | | int inet_pton(int af, char const *src, void *dst) |
428 | | { |
429 | | if (af == AF_INET) return inet_pton4(src, dst); |
430 | | |
431 | | # ifdef HAVE_STRUCT_SOCKADDR_IN6 |
432 | | if (af == AF_INET6) return inet_pton6(src, dst); |
433 | | # endif |
434 | | return -1; |
435 | | } |
436 | | #endif /* HAVE_INET_PTON */ |
437 | | |
438 | | #ifndef HAVE_INET_NTOP |
439 | | /* |
440 | | * Utility function, so that the rest of the server doesn't |
441 | | * have ifdef's around IPv6 support |
442 | | */ |
443 | | char const *inet_ntop(int af, void const *src, char *dst, size_t cnt) |
444 | | { |
445 | | if (af == AF_INET) { |
446 | | uint8_t const *ipaddr = src; |
447 | | |
448 | | if (cnt <= INET_ADDRSTRLEN) return NULL; |
449 | | |
450 | | snprintf(dst, cnt, "%d.%d.%d.%d", |
451 | | ipaddr[0], ipaddr[1], |
452 | | ipaddr[2], ipaddr[3]); |
453 | | return dst; |
454 | | } |
455 | | |
456 | | /* |
457 | | * If the system doesn't define this, we define it |
458 | | * in missing.h |
459 | | */ |
460 | | if (af == AF_INET6) { |
461 | | struct in6_addr const *ipaddr = src; |
462 | | |
463 | | if (cnt <= INET6_ADDRSTRLEN) return NULL; |
464 | | |
465 | | snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x", |
466 | | fr_nbo_to_uint16(ipaddr->a6_addr), |
467 | | fr_nbo_to_uint16(ipaddr->a6_addr + 2), |
468 | | fr_nbo_to_uint16(ipaddr->a6_addr + 4), |
469 | | fr_nbo_to_uint16(ipaddr->a6_addr + 6), |
470 | | fr_nbo_to_uint16(ipaddr->a6_addr + 8), |
471 | | fr_nbo_to_uint16(ipaddr->a6_addr + 10), |
472 | | fr_nbo_to_uint16(ipaddr->a6_addr + 12), |
473 | | fr_nbo_to_uint16(ipaddr->a6_addr + 14)); |
474 | | return dst; |
475 | | } |
476 | | |
477 | | return NULL; /* don't support IPv6 */ |
478 | | } |
479 | | #endif |
480 | | |
481 | | #ifndef HAVE_SENDMMSG |
482 | | /** Emulates the real sendmmsg in userland |
483 | | * |
484 | | * The idea behind the proper sendmmsg in FreeBSD and Linux is that multiple |
485 | | * datagram messages can be sent using a single system call. |
486 | | * |
487 | | * This function doesn't achieve that, but it does reduce ifdefs elsewhere |
488 | | * and means we can batch encoding/sending operations. |
489 | | * |
490 | | * @param[in] sockfd to write packets to. |
491 | | * @param[in] msgvec a pointer to an array of mmsghdr structures. |
492 | | * The size of this array is specified in vlen. |
493 | | * @param[in] vlen Length of msgvec. |
494 | | * @param[in] flags same as for sendmsg(2). |
495 | | * @return |
496 | | * - >= 0 The number of messages sent. Check against vlen to determine |
497 | | * if overall operation was successful. |
498 | | * - < 0 on error. Only returned if first operation errors. |
499 | | */ |
500 | | int sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags) |
501 | | { |
502 | | unsigned int i; |
503 | | |
504 | | for (i = 0; i < vlen; i++) { |
505 | | ssize_t slen; |
506 | | |
507 | | slen = sendmsg(sockfd, &msgvec[i].msg_hdr, flags); |
508 | | if (slen < 0) { |
509 | | msgvec[i].msg_len = 0; |
510 | | |
511 | | /* |
512 | | * man sendmmsg - Errors are as for sendmsg(2). |
513 | | * An error is returned only if no datagrams could |
514 | | * be sent. See also BUGS. |
515 | | */ |
516 | | if (i == 0) return -1; |
517 | | return i; |
518 | | } |
519 | | msgvec[i].msg_len = (unsigned int)slen; /* Number of bytes sent */ |
520 | | } |
521 | | |
522 | | return i; |
523 | | } |
524 | | #endif |
525 | | |
526 | | /* |
527 | | * So we don't have ifdef's in the rest of the code |
528 | | */ |
529 | | #ifndef HAVE_CLOSEFROM |
530 | | #include <stdlib.h> |
531 | | #ifdef HAVE_DIRENT_H |
532 | | # include <dirent.h> |
533 | | /* |
534 | | * Some versions of Linux don't have closefrom(), but they will |
535 | | * have /proc. |
536 | | * |
537 | | * BSD systems will generally have closefrom(), but not proc. |
538 | | * |
539 | | * OSX doesn't have closefrom() or /proc/self/fd, but it does |
540 | | * have /dev/fd |
541 | | */ |
542 | | # ifdef __linux__ |
543 | | # define CLOSEFROM_DIR "/proc/self/fd" |
544 | | # elif defined(__APPLE__) |
545 | | # define CLOSEFROM_DIR "/dev/fd" |
546 | | # else |
547 | | # undef HAVE_DIRENT_H |
548 | | # endif |
549 | | #endif |
550 | | |
551 | | void closefrom(int fd) |
552 | | { |
553 | | int i; |
554 | | int maxfd = 256; |
555 | | # ifdef HAVE_DIRENT_H |
556 | | DIR *dir; |
557 | | # endif |
558 | | |
559 | | #ifdef F_CLOSEM |
560 | | if (fcntl(fd, F_CLOSEM) == 0) return; |
561 | | # endif |
562 | | |
563 | | # ifdef F_MAXFD |
564 | | maxfd = fcntl(fd, F_F_MAXFD); |
565 | | if (maxfd >= 0) goto do_close; |
566 | | # endif |
567 | | |
568 | | # ifdef _SC_OPEN_MAX |
569 | | maxfd = sysconf(_SC_OPEN_MAX); |
570 | | if (maxfd < 0) { |
571 | | maxfd = 256; |
572 | | } |
573 | | # endif |
574 | | |
575 | | # ifdef HAVE_DIRENT_H |
576 | | /* |
577 | | * Use /proc/self/fd directory if it exists. |
578 | | */ |
579 | | dir = opendir(CLOSEFROM_DIR); |
580 | | if (dir != NULL) { |
581 | | long my_fd; |
582 | | char *endp; |
583 | | struct dirent *dp; |
584 | | |
585 | | while ((dp = readdir(dir)) != NULL) { |
586 | | my_fd = strtol(dp->d_name, &endp, 10); |
587 | | if (my_fd <= 0) continue; |
588 | | |
589 | | if (*endp) continue; |
590 | | |
591 | | if (my_fd == dirfd(dir)) continue; |
592 | | |
593 | | if ((my_fd >= fd) && (my_fd <= maxfd)) { |
594 | | (void) close((int) my_fd); |
595 | | } |
596 | | } |
597 | | (void) closedir(dir); |
598 | | return; |
599 | | } |
600 | | # endif |
601 | | |
602 | | # ifdef F_MAXFD |
603 | | do_close: |
604 | | # endif |
605 | | |
606 | | if (fd > maxfd) return; |
607 | | |
608 | | /* |
609 | | * FIXME: return EINTR? |
610 | | */ |
611 | | for (i = fd; i < maxfd; i++) { |
612 | | close(i); |
613 | | } |
614 | | |
615 | | return; |
616 | | } |
617 | | #endif |
618 | | |
619 | | #ifndef HAVE_MEMSET_EXPLICIT |
620 | | void *memset_explicit(void *ptr, |
621 | | #ifdef HAVE_EXPLICIT_BZERO |
622 | | UNUSED |
623 | | #endif |
624 | | int ch, |
625 | | size_t len) |
626 | 5.20k | { |
627 | 5.20k | if (!len) return ptr; |
628 | | |
629 | 3.75k | #ifdef HAVE_EXPLICIT_BZERO |
630 | 3.75k | explicit_bzero(ptr, len); |
631 | | #else |
632 | | { |
633 | | volatile unsigned char *volatile p = (volatile unsigned char *volatile) ptr; |
634 | | size_t i = len; |
635 | | |
636 | | while (i--) { |
637 | | *(p++) = ch; |
638 | | } |
639 | | } |
640 | | #endif |
641 | | |
642 | 3.75k | return ptr; |
643 | 5.20k | } |
644 | | #endif |