The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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  */
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 {
627  if (!len) return ptr;
628 
629 #ifdef HAVE_EXPLICIT_BZERO
630  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  return ptr;
643 }
644 #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:444
#define UNUSED
Definition: build.h:313
static int sockfd
Definition: dhcpclient.c:56
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
void * memset_explicit(void *ptr, int ch, size_t len)
Definition: missing.c:620
struct tm * gmtime_r(time_t const *l_clock, struct tm *result)
Definition: missing.c:201
int inet_pton(int af, char const *src, void *dst)
Definition: missing.c:427
void closefrom(int fd)
Definition: missing.c:551
int strncasecmp(char *s1, char *s2, int n)
Definition: missing.c:36
void * memrchr(void const *s, int c, size_t n)
GNU libc extension on some platforms.
Definition: missing.c:83
int vdprintf(int fd, char const *format, va_list args)
Definition: missing.c:210
char * ctime_r(time_t const *l_clock, char *l_buf)
Definition: missing.c:182
int strcasecmp(char *s1, char *s2)
Definition: missing.c:66
char const * inet_ntop(int af, void const *src, char *dst, size_t cnt)
Definition: missing.c:443
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:500
int inet_aton(char const *cp, struct in_addr *inp)
Definition: missing.c:97
static int inet_pton4(char const *src, struct in_addr *dst)
Definition: missing.c:276
char * strsep(char **stringp, char const *delim)
Definition: missing.c:123
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:137
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
close(uq->fd)
int format(printf, 5, 0))