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