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: 7a12416e129a840d433e7fa913ba6c5895bc9724 $")
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
36int 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
66int 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 */
83void *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
97int 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 */
122char *
123strsep(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 */
163struct 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 */
182char *ctime_r(time_t const *l_clock, char *l_buf)
183{
184 char *p;
185
186 p = ctime(l_clock);
187 if (!p) return NULL;
188
189 strcpy(l_buf, p);
190
191 return l_buf;
192}
193#endif
194
195#ifndef HAVE_GMTIME_R
196/*
197 * We use gmtime_r() by default in the server.
198 *
199 * For systems which do NOT have gmtime_r(), we make the
200 * assumption that gmtime() is re-entrant, and returns a
201 * per-thread data structure.
202 *
203 * Even if gmtime is NOT re-entrant, this function will
204 * lower the possibility of race conditions.
205 */
206struct tm *gmtime_r(time_t const *l_clock, struct tm *result)
207{
208 memcpy(result, gmtime(l_clock), sizeof(*result));
209
210 return result;
211}
212#endif
213
214#ifndef HAVE_VDPRINTF
215int vdprintf(int fd, char const *format, va_list args)
216{
217 int ret;
218 FILE *fp;
219 int dup_fd;
220
221 dup_fd = dup(fd);
222 if (dup_fd < 0) return -1;
223
224 fp = fdopen(dup_fd, "w");
225 if (!fp) {
226 close(dup_fd);
227 return -1;
228 }
229
230 ret = vfprintf(fp, format, args);
231 fclose(fp); /* Also closes dup_fd */
232
233 return ret;
234}
235#endif
236
237
238#if !defined(HAVE_CLOCK_GETTIME) && defined(__MACH__)
239int clock_gettime(int clk_id, struct timespec *t)
240{
241 static mach_timebase_info_data_t timebase;
242 static bool done_init = false;
243
244 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
245
246 if (!done_init) {
247 pthread_mutex_lock(&mutex);
248 if (!done_init) {
249 mach_timebase_info(&timebase);
250 done_init = true;
251 }
252 pthread_mutex_unlock(&mutex);
253 }
254
255 switch (clk_id) {
256 case CLOCK_REALTIME:
257 return -1;
258
259 case CLOCK_MONOTONIC:
260 {
261 uint64_t time;
262 time = mach_absolute_time();
263 double nanoseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom);
264 double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9);
265 t->tv_sec = seconds;
266 t->tv_nsec = nanoseconds;
267 }
268 return 0;
269
270 default:
271 errno = EINVAL;
272 return -1;
273 }
274}
275#endif
276
277/*
278 * Replacements in case we don't have inet_pton
279 */
280#ifndef HAVE_INET_PTON
281static int inet_pton4(char const *src, struct in_addr *dst)
282{
283 int octet;
284 unsigned int num;
285 char const *p, *off;
286 uint8_t tmp[4];
287 static char const digits[] = "0123456789";
288
289 octet = 0;
290 p = src;
291 while (1) {
292 num = 0;
293 while (*p && ((off = strchr(digits, *p)) != NULL)) {
294 num *= 10;
295 num += (off - digits);
296
297 if (num > 255) return 0;
298
299 p++;
300 }
301 if (!*p) break;
302
303 /*
304 * Not a digit, MUST be a dot, else we
305 * die.
306 */
307 if (*p != '.') {
308 return 0;
309 }
310
311 tmp[octet++] = num;
312 p++;
313 }
314
315 /*
316 * End of the string. At the fourth
317 * octet is OK, anything else is an
318 * error.
319 */
320 if (octet != 3) {
321 return 0;
322 }
323 tmp[3] = num;
324
325 memcpy(dst, &tmp, sizeof(tmp));
326 return 1;
327}
328
329
330# ifdef HAVE_STRUCT_SOCKADDR_IN6
331/** Convert presentation level address to network order binary form
332 *
333 * @note Does not touch dst unless it's returning 1.
334 * @note :: in a full address is silently ignored.
335 * @note Inspired by Mark Andrews.
336 * @author Paul Vixie, 1996.
337 *
338 * @param src presentation level address.
339 * @param dst where to write output address.
340 * @return
341 * - 1 if `src' is a valid [RFC1884 2.2] address.
342 * - 0 if `src' in not a valid [RFC1884 2.2] address.
343 */
344static int inet_pton6(char const *src, unsigned char *dst)
345{
346 static char const xdigits_l[] = "0123456789abcdef",
347 xdigits_u[] = "0123456789ABCDEF";
348 uint8_t tmp[IN6ADDRSZ], *tp, *endp, *colonp;
349 char const *xdigits, *curtok;
350 int ch, saw_xdigit;
351 u_int val;
352
353 memset((tp = tmp), 0, IN6ADDRSZ);
354 endp = tp + IN6ADDRSZ;
355 colonp = NULL;
356 /* Leading :: requires some special handling. */
357 if (*src == ':')
358 if (*++src != ':')
359 return (0);
360 curtok = src;
361 saw_xdigit = 0;
362 val = 0;
363 while ((ch = *src++) != '\0') {
364 char const *pch;
365
366 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
367 pch = strchr((xdigits = xdigits_u), ch);
368 if (pch != NULL) {
369 val <<= 4;
370 val |= (pch - xdigits);
371 if (val > 0xffff)
372 return (0);
373 saw_xdigit = 1;
374 continue;
375 }
376 if (ch == ':') {
377 curtok = src;
378 if (!saw_xdigit) {
379 if (colonp)
380 return (0);
381 colonp = tp;
382 continue;
383 }
384 if (tp + INT16SZ > endp)
385 return (0);
386 *tp++ = (uint8_t) (val >> 8) & 0xff;
387 *tp++ = (uint8_t) val & 0xff;
388 saw_xdigit = 0;
389 val = 0;
390 continue;
391 }
392 if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
393 inet_pton4(curtok, (struct in_addr *) tp) > 0) {
394 tp += INADDRSZ;
395 saw_xdigit = 0;
396 break; /* '\0' was seen by inet_pton4(). */
397 }
398 return (0);
399 }
400 if (saw_xdigit) {
401 if (tp + INT16SZ > endp)
402 return (0);
403 *tp++ = (uint8_t) (val >> 8) & 0xff;
404 *tp++ = (uint8_t) val & 0xff;
405 }
406 if (colonp != NULL) {
407 /*
408 * Since some memmove()'s erroneously fail to handle
409 * overlapping regions, we'll do the shift by hand.
410 */
411 int const n = tp - colonp;
412 int i;
413
414 for (i = 1; i <= n; i++) {
415 endp[- i] = colonp[n - i];
416 colonp[n - i] = 0;
417 }
418 tp = endp;
419 }
420 if (tp != endp)
421 return (0);
422 /* bcopy(tmp, dst, IN6ADDRSZ); */
423 memcpy(dst, tmp, IN6ADDRSZ);
424 return (1);
425}
426# endif
427
428/*
429 * Utility function, so that the rest of the server doesn't
430 * have ifdef's around IPv6 support
431 */
432int inet_pton(int af, char const *src, void *dst)
433{
434 if (af == AF_INET) return inet_pton4(src, dst);
435
436# ifdef HAVE_STRUCT_SOCKADDR_IN6
437 if (af == AF_INET6) return inet_pton6(src, dst);
438# endif
439 return -1;
440}
441#endif /* HAVE_INET_PTON */
442
443#ifndef HAVE_INET_NTOP
444/*
445 * Utility function, so that the rest of the server doesn't
446 * have ifdef's around IPv6 support
447 */
448char const *inet_ntop(int af, void const *src, char *dst, size_t cnt)
449{
450 if (af == AF_INET) {
451 uint8_t const *ipaddr = src;
452
453 if (cnt <= INET_ADDRSTRLEN) return NULL;
454
455 snprintf(dst, cnt, "%d.%d.%d.%d",
456 ipaddr[0], ipaddr[1],
457 ipaddr[2], ipaddr[3]);
458 return dst;
459 }
460
461 /*
462 * If the system doesn't define this, we define it
463 * in missing.h
464 */
465 if (af == AF_INET6) {
466 struct in6_addr const *ipaddr = src;
467
468 if (cnt <= INET6_ADDRSTRLEN) return NULL;
469
470 snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x",
471 fr_nbo_to_uint16(ipaddr->a6_addr),
472 fr_nbo_to_uint16(ipaddr->a6_addr + 2),
473 fr_nbo_to_uint16(ipaddr->a6_addr + 4),
474 fr_nbo_to_uint16(ipaddr->a6_addr + 6),
475 fr_nbo_to_uint16(ipaddr->a6_addr + 8),
476 fr_nbo_to_uint16(ipaddr->a6_addr + 10),
477 fr_nbo_to_uint16(ipaddr->a6_addr + 12),
478 fr_nbo_to_uint16(ipaddr->a6_addr + 14));
479 return dst;
480 }
481
482 return NULL; /* don't support IPv6 */
483}
484#endif
485
486#ifndef HAVE_SENDMMSG
487/** Emulates the real sendmmsg in userland
488 *
489 * The idea behind the proper sendmmsg in FreeBSD and Linux is that multiple
490 * datagram messages can be sent using a single system call.
491 *
492 * This function doesn't achieve that, but it does reduce ifdefs elsewhere
493 * and means we can batch encoding/sending operations.
494 *
495 * @param[in] sockfd to write packets to.
496 * @param[in] msgvec a pointer to an array of mmsghdr structures.
497 * The size of this array is specified in vlen.
498 * @param[in] vlen Length of msgvec.
499 * @param[in] flags same as for sendmsg(2).
500 * @return
501 * - >= 0 The number of messages sent. Check against vlen to determine
502 * if overall operation was successful.
503 * - < 0 on error. Only returned if first operation errors.
504 */
505int sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags)
506{
507 unsigned int i;
508
509 for (i = 0; i < vlen; i++) {
510 ssize_t slen;
511
512 slen = sendmsg(sockfd, &msgvec[i].msg_hdr, flags);
513 if (slen < 0) {
514 msgvec[i].msg_len = 0;
515
516 /*
517 * man sendmmsg - Errors are as for sendmsg(2).
518 * An error is returned only if no datagrams could
519 * be sent. See also BUGS.
520 */
521 if (i == 0) return -1;
522 return i;
523 }
524 msgvec[i].msg_len = (unsigned int)slen; /* Number of bytes sent */
525 }
526
527 return i;
528}
529#endif
530
531/*
532 * So we don't have ifdef's in the rest of the code
533 */
534#ifndef HAVE_CLOSEFROM
535 #include <stdlib.h>
536#ifdef HAVE_DIRENT_H
537# include <dirent.h>
538/*
539 * Some versions of Linux don't have closefrom(), but they will
540 * have /proc.
541 *
542 * BSD systems will generally have closefrom(), but not proc.
543 *
544 * OSX doesn't have closefrom() or /proc/self/fd, but it does
545 * have /dev/fd
546 */
547# ifdef __linux__
548# define CLOSEFROM_DIR "/proc/self/fd"
549# elif defined(__APPLE__)
550# define CLOSEFROM_DIR "/dev/fd"
551# else
552# undef HAVE_DIRENT_H
553# endif
554#endif
555
556void closefrom(int fd)
557{
558 int i;
559 int maxfd = 256;
560# ifdef HAVE_DIRENT_H
561 DIR *dir;
562# endif
563
564#ifdef F_CLOSEM
565 if (fcntl(fd, F_CLOSEM) == 0) return;
566# endif
567
568# ifdef F_MAXFD
569 maxfd = fcntl(fd, F_F_MAXFD);
570 if (maxfd >= 0) goto do_close;
571# endif
572
573# ifdef _SC_OPEN_MAX
574 maxfd = sysconf(_SC_OPEN_MAX);
575 if (maxfd < 0) {
576 maxfd = 256;
577 }
578# endif
579
580# ifdef HAVE_DIRENT_H
581 /*
582 * Use /proc/self/fd directory if it exists.
583 */
584 dir = opendir(CLOSEFROM_DIR);
585 if (dir != NULL) {
586 long my_fd;
587 char *endp;
588 struct dirent *dp;
589
590 while ((dp = readdir(dir)) != NULL) {
591 my_fd = strtol(dp->d_name, &endp, 10);
592 if (my_fd <= 0) continue;
593
594 if (*endp) continue;
595
596 if (my_fd == dirfd(dir)) continue;
597
598 if ((my_fd >= fd) && (my_fd <= maxfd)) {
599 (void) close((int) my_fd);
600 }
601 }
602 (void) closedir(dir);
603 return;
604 }
605# endif
606
607# ifdef F_MAXFD
608do_close:
609# endif
610
611 if (fd > maxfd) return;
612
613 /*
614 * FIXME: return EINTR?
615 */
616 for (i = fd; i < maxfd; i++) {
617 close(i);
618 }
619
620 return;
621}
622#endif
623
624#ifndef HAVE_MEMSET_EXPLICIT
625void *memset_explicit(void *ptr,
626#ifdef HAVE_EXPLICIT_BZERO
627 UNUSED
628#endif
629 int ch,
630 size_t len)
631{
632 if (!len) return ptr;
633
634#ifdef HAVE_EXPLICIT_BZERO
635 explicit_bzero(ptr, len);
636#else
637 {
638 volatile unsigned char *volatile p = (volatile unsigned char *volatile) ptr;
639 size_t i = len;
640
641 while (i--) {
642 *(p++) = ch;
643 }
644 }
645#endif
646
647 return ptr;
648}
649#endif
int n
Definition acutest.h:579
strcpy(log_entry->msg, buffer)
va_list args
Definition acutest.h:772
#define RCSID(id)
Definition build.h:487
#define UNUSED
Definition build.h:317
static int sockfd
Definition dhcpclient.c:56
long int ssize_t
unsigned char uint8_t
void * memset_explicit(void *ptr, int ch, size_t len)
Definition missing.c:625
int inet_pton(int af, char const *src, void *dst)
Definition missing.c:432
void closefrom(int fd)
Definition missing.c:556
char const * inet_ntop(int af, void const *src, char *dst, size_t cnt)
Definition missing.c:448
int strncasecmp(char *s1, char *s2, int n)
Definition missing.c:36
int vdprintf(int fd, char const *format, va_list args)
Definition missing.c:215
void * memrchr(void const *s, int c, size_t n)
GNU libc extension on some platforms.
Definition missing.c:83
char * strsep(char **stringp, char const *delim)
Definition missing.c:123
int strcasecmp(char *s1, char *s2)
Definition missing.c:66
struct tm * gmtime_r(time_t const *l_clock, struct tm *result)
Definition missing.c:206
struct tm * localtime_r(time_t const *l_clock, struct tm *result)
Definition missing.c:163
int sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags)
Emulates the real sendmmsg in userland.
Definition missing.c:505
int inet_aton(char const *cp, struct in_addr *inp)
Definition missing.c:97
char * ctime_r(time_t const *l_clock, char *l_buf)
Definition missing.c:182
static int inet_pton4(char const *src, struct in_addr *dst)
Definition missing.c:281
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))