The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: b058182245a8cd0add623d4fda058eafca54f86c $")
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/*
531 * So we don't have ifdef's in the rest of the code
532 */
533#ifndef HAVE_CLOSEFROM
534 #include <stdlib.h>
535#ifdef HAVE_DIRENT_H
536# include <dirent.h>
537/*
538 * Some versions of Linux don't have closefrom(), but they will
539 * have /proc.
540 *
541 * BSD systems will generally have closefrom(), but not proc.
542 *
543 * OSX doesn't have closefrom() or /proc/self/fd, but it does
544 * have /dev/fd
545 */
546# ifdef __linux__
547# define CLOSEFROM_DIR "/proc/self/fd"
548# elif defined(__APPLE__)
549# define CLOSEFROM_DIR "/dev/fd"
550# else
551# undef HAVE_DIRENT_H
552# endif
553#endif
554
555void closefrom(int fd)
556{
557 int i;
558 int maxfd = 256;
559# ifdef HAVE_DIRENT_H
560 DIR *dir;
561# endif
562
563#ifdef F_CLOSEM
564 if (fcntl(fd, F_CLOSEM) == 0) return;
565# endif
566
567# ifdef F_MAXFD
568 maxfd = fcntl(fd, F_F_MAXFD);
569 if (maxfd >= 0) goto do_close;
570# endif
571
572# ifdef _SC_OPEN_MAX
573 maxfd = sysconf(_SC_OPEN_MAX);
574 if (maxfd < 0) {
575 maxfd = 256;
576 }
577# endif
578
579# ifdef HAVE_DIRENT_H
580 /*
581 * Use /proc/self/fd directory if it exists.
582 */
583 dir = opendir(CLOSEFROM_DIR);
584 if (dir != NULL) {
585 long my_fd;
586 char *endp;
587 struct dirent *dp;
588
589 while ((dp = readdir(dir)) != NULL) {
590 my_fd = strtol(dp->d_name, &endp, 10);
591 if (my_fd <= 0) continue;
592
593 if (*endp) continue;
594
595 if (my_fd == dirfd(dir)) continue;
596
597 if ((my_fd >= fd) && (my_fd <= maxfd)) {
598 (void) close((int) my_fd);
599 }
600 }
601 (void) closedir(dir);
602 return;
603 }
604# endif
605
606# ifdef F_MAXFD
607do_close:
608# endif
609
610 if (fd > maxfd) return;
611
612 /*
613 * FIXME: return EINTR?
614 */
615 for (i = fd; i < maxfd; i++) {
616 close(i);
617 }
618
619 return;
620}
621#endif
622
623#ifndef HAVE_MEMSET_EXPLICIT
624void *memset_explicit(void *ptr,
625#ifdef HAVE_EXPLICIT_BZERO
626 UNUSED
627#endif
628 int ch,
629 size_t len)
630{
631 if (!len) return ptr;
632
633#ifdef HAVE_EXPLICIT_BZERO
634 explicit_bzero(ptr, len);
635#else
636 {
637 volatile unsigned char *volatile p = (volatile unsigned char *volatile) ptr;
638 size_t i = len;
639
640 while (i--) {
641 *(p++) = ch;
642 }
643 }
644#endif
645
646 return ptr;
647}
648#endif
int n
Definition acutest.h:577
strcpy(log_entry->msg, buffer)
va_list args
Definition acutest.h:770
#define RCSID(id)
Definition build.h:488
#define UNUSED
Definition build.h:318
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:624
int inet_pton(int af, char const *src, void *dst)
Definition missing.c:431
void closefrom(int fd)
Definition missing.c:555
char const * inet_ntop(int af, void const *src, char *dst, size_t cnt)
Definition missing.c:447
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
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
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
int format(printf, 5, 0))