Coverage Report

Created: 2026-01-17 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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