Coverage Report

Created: 2025-12-14 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/lib/util/misc.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
/** Various miscellaneous utility functions
18
 *
19
 * @file src/lib/util/misc.c
20
 *
21
 * @copyright 2000,2006 The FreeRADIUS server project
22
 */
23
RCSID("$Id: bf4c82aa58893f3fbc7cf3d98fbf52299fe213e6 $")
24
25
#include <freeradius-devel/util/dbuff.h>
26
#include <freeradius-devel/util/sbuff.h>
27
#include <freeradius-devel/util/syserror.h>
28
29
#include <string.h>
30
#include <fcntl.h>
31
#include <grp.h>
32
#include <pwd.h>
33
#include <sys/file.h>
34
#include <sys/stat.h>
35
#include <sys/uio.h>
36
37
#define FR_PUT_LE16(a, val)\
38
0
  do {\
39
0
    a[1] = ((uint16_t) (val)) >> 8;\
40
0
    a[0] = ((uint16_t) (val)) & 0xff;\
41
0
  } while (0)
42
43
/** Sets a signal handler using sigaction if available, else signal
44
 *
45
 * @param sig to set handler for.
46
 * @param func handler to set.
47
 */
48
int fr_set_signal(int sig, sig_t func)
49
0
{
50
0
#ifdef HAVE_SIGACTION
51
0
  struct sigaction act;
52
53
0
  memset(&act, 0, sizeof(act));
54
0
  act.sa_flags = 0;
55
0
  sigemptyset(&act.sa_mask);
56
0
  act.sa_handler = func;
57
58
0
  if (sigaction(sig, &act, NULL) < 0) {
59
0
    fr_strerror_printf("Failed setting signal %i handler via sigaction(): %s", sig, fr_syserror(errno));
60
0
    return -1;
61
0
  }
62
#else
63
  if (signal(sig, func) < 0) {
64
    fr_strerror_printf("Failed setting signal %i handler via signal(): %s", sig, fr_syserror(errno));
65
    return -1;
66
  }
67
#endif
68
0
  return 0;
69
0
}
70
71
/** Uninstall a signal for a specific handler
72
 *
73
 * man sigaction says these are fine to call from a signal handler.
74
 *
75
 * @param sig SIGNAL
76
 */
77
int fr_unset_signal(int sig)
78
0
{
79
0
#ifdef HAVE_SIGACTION
80
0
        struct sigaction act;
81
82
0
        memset(&act, 0, sizeof(act));
83
0
        act.sa_flags = 0;
84
0
        sigemptyset(&act.sa_mask);
85
0
        act.sa_handler = SIG_DFL;
86
87
0
        return sigaction(sig, &act, NULL);
88
#else
89
        return signal(sig, SIG_DFL);
90
#endif
91
0
}
92
93
#ifndef F_WRLCK
94
#error "missing definition for F_WRLCK, all file locks will fail"
95
#endif
96
97
/*
98
 *  cppcheck apparently can't pick this up from the system headers.
99
 */
100
#ifdef CPPCHECK
101
#define F_WRLCK
102
#endif
103
104
static int rad_lock(int fd, int lock_len, int cmd, int type)
105
0
{
106
0
  struct flock fl;
107
108
0
  fl.l_start = 0;
109
0
  fl.l_len = lock_len;
110
0
  fl.l_pid = getpid();
111
0
  fl.l_type = type;
112
0
  fl.l_whence = SEEK_CUR;
113
114
0
  return fcntl(fd, cmd, (void *)&fl);
115
0
}
116
117
/*
118
 *  Internal wrapper for locking, to minimize the number of ifdef's
119
 */
120
int rad_lockfd(int fd, int lock_len)
121
0
{
122
0
  return rad_lock(fd, lock_len, F_SETLKW, F_WRLCK);
123
0
}
124
125
/*
126
 *  Internal wrapper for locking, to minimize the number of ifdef's
127
 *
128
 *  Nonblocking version.
129
 */
130
int rad_lockfd_nonblock(int fd, int lock_len)
131
0
{
132
  /*
133
   *  Note that there's no "W" on SETLK
134
   */
135
0
  return rad_lock(fd, lock_len, F_SETLK, F_WRLCK);
136
0
}
137
138
/*
139
 *  Internal wrapper for unlocking, to minimize the number of ifdef's
140
 *  in the source.
141
 */
142
int rad_unlockfd(int fd, int lock_len)
143
0
{
144
  /*
145
   *  Note UNLOCK.
146
   */
147
0
  return rad_lock(fd, lock_len, F_SETLK, F_UNLCK);
148
0
}
149
150
/** Consume the integer (or hex) portion of a value string
151
 *
152
 * Allows integer or hex representations of integers (but not octal,
153
 * as octal is deemed to be confusing).
154
 *
155
 * @param[out] out  Result of parsing string as unsigned 64bit integer.
156
 * @param[out] end  pointer to the first non numeric char.
157
 * @param[in] value string to parse.
158
 *
159
 * @return integer value.
160
 */
161
int fr_strtoull(uint64_t *out, char **end, char const *value)
162
0
{
163
0
  errno = 0;  /* Explicitly clear errors, as glibc appears not to do this */
164
165
0
  if ((value[0] == '0') && (value[1] == 'x')) {
166
0
    *out = strtoull(value, end, 16);
167
0
    if (errno == ERANGE) {
168
0
    error:
169
0
      fr_strerror_printf("Unsigned integer value \"%s\" too large, would overflow", value);
170
0
      return -1;
171
0
    }
172
0
    return 0;
173
0
  }
174
175
0
  *out = strtoull(value, end, 10);
176
0
  if (errno == ERANGE) goto error;
177
0
  return 0;
178
0
}
179
180
/** Consume the integer (or hex) portion of a value string
181
 *
182
 * Allows integer or hex representations of integers (but not octal,
183
 * as octal is deemed to be confusing).
184
 *
185
 * @note Check for overflow with errno == ERANGE.
186
 *
187
 * @param[out] out  Result of parsing string as signed 64bit integer.
188
 * @param[out] end  pointer to the first non numeric char.
189
 * @param[in] value string to parse.
190
 * @return integer value.
191
 */
192
int fr_strtoll(int64_t *out, char **end, char const *value)
193
0
{
194
0
  errno = 0;  /* Explicitly clear errors, as glibc appears not to do this */
195
196
0
  if ((value[0] == '0') && (value[1] == 'x')) {
197
0
    *out = strtoll(value, end, 16);
198
0
    if (errno == ERANGE) {
199
0
    error:
200
0
      fr_strerror_printf("Signed integer value \"%s\" too large, would overflow", value);
201
0
      return -1;
202
0
    }
203
0
    return 0;
204
0
  }
205
206
0
  *out = strtoll(value, end, 10);
207
0
  if (errno == ERANGE) goto error;
208
0
  return 0;
209
0
}
210
211
/** Trim whitespace from the end of a string
212
 *
213
 */
214
char *fr_trim(char const *str, size_t size)
215
0
{
216
0
  char *q;
217
218
0
  if (!str || !size) return NULL;
219
220
0
  memcpy(&q, &str, sizeof(q));
221
0
  for (q = q + size; q > str && isspace((uint8_t) *q); q--);
222
223
0
  return q;
224
0
}
225
226
char *fr_tolower(char *str)
227
8
{
228
8
  char *p;
229
230
56
  for (p = str; *p != '\0'; p++) *p = tolower(*p);
231
232
8
  return str;
233
8
}
234
235
#ifdef O_NONBLOCK
236
/** Set O_NONBLOCK on a socket
237
 *
238
 * @note O_NONBLOCK is POSIX.
239
 *
240
 * @param fd to set nonblocking flag on.
241
 * @return
242
 *  - Flags set on the socket.
243
 *  - -1 on failure.
244
 */
245
int fr_nonblock(int fd)
246
0
{
247
0
  int flags;
248
249
0
  flags = fcntl(fd, F_GETFL, NULL);
250
0
  if (flags < 0)  {
251
0
    fr_strerror_printf("Failed getting socket flags: %s", fr_syserror(errno));
252
0
    return -1;
253
0
  }
254
255
0
  flags |= O_NONBLOCK;
256
0
  if (fcntl(fd, F_SETFL, flags) < 0) {
257
0
    fr_strerror_printf("Failed setting socket flags: %s", fr_syserror(errno));
258
0
    return -1;
259
0
  }
260
261
0
  return flags;
262
0
}
263
264
/** Unset O_NONBLOCK on a socket
265
 *
266
 * @note O_NONBLOCK is POSIX.
267
 *
268
 * @param fd to set nonblocking flag on.
269
 * @return
270
 *  - Flags set on the socket.
271
 *  - -1 on failure.
272
 */
273
int fr_blocking(int fd)
274
0
{
275
0
  int flags;
276
277
0
  flags = fcntl(fd, F_GETFL, NULL);
278
0
  if (flags < 0)  {
279
0
    fr_strerror_printf("Failed getting socket flags: %s", fr_syserror(errno));
280
0
    return -1;
281
0
  }
282
283
0
  if (!(flags & O_NONBLOCK)) return flags;
284
285
0
  flags ^= O_NONBLOCK;
286
0
  if (fcntl(fd, F_SETFL, flags) < 0) {
287
0
    fr_strerror_printf("Failed setting socket flags: %s", fr_syserror(errno));
288
0
    return -1;
289
0
  }
290
291
0
  return flags;
292
0
}
293
#else
294
int fr_nonblock(UNUSED int fd)
295
{
296
  fr_strerror_const("Non blocking sockets are not supported");
297
  return -1;
298
}
299
int fr_blocking(UNUSED int fd)
300
{
301
  fr_strerror_const("Non blocking sockets are not supported");
302
  return -1;
303
}
304
#endif
305
306
/** Convert UTF8 string to UCS2 encoding
307
 *
308
 * @note Borrowed from src/crypto/ms_funcs.c of wpa_supplicant project (http://hostap.epitest.fi/wpa_supplicant/)
309
 *
310
 * @param[out] out Where to write the ucs2 string.
311
 * @param[in] outlen Size of output buffer.
312
 * @param[in] in UTF8 string to convert.
313
 * @param[in] inlen length of UTF8 string.
314
 * @return the size of the UCS2 string written to the output buffer (in bytes).
315
 */
316
ssize_t fr_utf8_to_ucs2(uint8_t *out, size_t outlen, char const *in, size_t inlen)
317
0
{
318
0
  size_t i;
319
0
  uint8_t *start = out;
320
321
0
  for (i = 0; i < inlen; i++) {
322
0
    uint8_t c, c2, c3;
323
324
0
    c = in[i];
325
0
    if ((size_t)(out - start) >= outlen) {
326
      /* input too long */
327
0
      return -1;
328
0
    }
329
330
    /* One-byte encoding */
331
0
    if (c <= 0x7f) {
332
0
      out[0] = (uint8_t)c;
333
0
      out[1] = 0;
334
0
      out += 2;
335
0
      continue;
336
0
    } else if ((i == (inlen - 1)) || ((size_t)(out - start) >= (outlen - 1))) {
337
      /* Incomplete surrogate */
338
0
      return -1;
339
0
    }
340
341
0
    c2 = in[++i];
342
    /* Two-byte encoding */
343
0
    if ((c & 0xe0) == 0xc0) {
344
0
      FR_PUT_LE16(out, ((c & 0x1f) << 6) | (c2 & 0x3f));
345
0
      out += 2;
346
0
      continue;
347
0
    }
348
0
    if ((i == inlen) || ((size_t)(out - start) >= (outlen - 1))) {
349
      /* Incomplete surrogate */
350
0
      return -1;
351
0
    }
352
353
    /* Three-byte encoding */
354
0
    c3 = in[++i];
355
0
    FR_PUT_LE16(out, ((c & 0xf) << 12) | ((c2 & 0x3f) << 6) | (c3 & 0x3f));
356
0
    out += 2;
357
0
  }
358
359
0
  return out - start;
360
0
}
361
362
/** Write 128bit unsigned integer to buffer
363
 *
364
 * @author Alexey Frunze
365
 *
366
 * @param out where to write result to.
367
 * @param outlen size of out.
368
 * @param num 128 bit integer.
369
 */
370
size_t fr_snprint_uint128(char *out, size_t outlen, uint128_t const num)
371
0
{
372
0
  char buff[] = "00000000000000000000000000000000000000000000";
373
0
  uint64_t n[2];
374
0
  char *p = buff;
375
0
  int i;
376
0
#ifndef WORDS_BIGENDIAN
377
0
  size_t const l = 0;
378
0
  size_t const h = 1;
379
#else
380
  size_t const l = 1;
381
  size_t const h = 0;
382
#endif
383
384
0
  memcpy(n, &num, sizeof(n));
385
386
0
  for (i = 0; i < 128; i++) {
387
0
    ssize_t j;
388
0
    int carry;
389
390
0
    carry = (n[h] >= 0x8000000000000000);
391
392
    // Shift n[] left, doubling it
393
0
    n[h] = ((n[h] << 1) & 0xffffffffffffffff) + (n[l] >= 0x8000000000000000);
394
0
    n[l] = ((n[l] << 1) & 0xffffffffffffffff);
395
396
    // Add s[] to itself in float, doubling it
397
0
    for (j = sizeof(buff) - 2; j >= 0; j--) {
398
0
      buff[j] += buff[j] - '0' + carry;
399
0
      carry = (buff[j] > '9');
400
0
      if (carry) buff[j] -= 10;
401
0
    }
402
0
  }
403
404
0
  while ((*p == '0') && (p < &buff[sizeof(buff) - 2])) p++;
405
406
0
  return strlcpy(out, p, outlen);
407
0
}
408
409
/** Compares two pointers
410
 *
411
 * @param a first pointer to compare.
412
 * @param b second pointer to compare.
413
 * @return
414
 *  - -1 if a < b.
415
 *  - +1 if b > a.
416
 *  - 0 if both equal.
417
 */
418
int8_t fr_pointer_cmp(void const *a, void const *b)
419
0
{
420
0
  return CMP(a, b);
421
0
}
422
423
/** Quick sort an array of pointers using a comparator
424
 *
425
 * @param to_sort array of pointers to sort.
426
 * @param start the lowest index (usually 0).
427
 * @param end the length of the array.
428
 * @param cmp the comparison function to use to sort the array elements.
429
 */
430
void fr_quick_sort(void const *to_sort[], int start, int end, fr_cmp_t cmp)
431
0
{
432
0
  int   i, pi;
433
0
  void const  *pivot;
434
435
0
  if (start >= end) return;
436
437
0
#define SWAP(_a, _b) \
438
0
  do { \
439
0
    void const *_tmp = to_sort[_a]; \
440
0
    to_sort[_a] = to_sort[_b]; \
441
0
    to_sort[_b] = _tmp; \
442
0
  } while (0)
443
444
0
  pivot = to_sort[end];
445
0
  for (pi = start, i = start; i < end; i++) {
446
0
    if (cmp(to_sort[i], pivot) < 0) {
447
0
      SWAP(i , pi);
448
0
      pi++;
449
0
    }
450
0
  }
451
0
  SWAP(end, pi);
452
453
0
  fr_quick_sort(to_sort, start, pi - 1, cmp);
454
0
  fr_quick_sort(to_sort, pi + 1, end, cmp);
455
0
}
456
457
#ifdef TALLOC_DEBUG
458
void fr_talloc_verify_cb(UNUSED const void *ptr, UNUSED int depth,
459
       UNUSED int max_depth, UNUSED int is_ref,
460
       UNUSED void *private_data)
461
{
462
  /* do nothing */
463
}
464
#endif
465
466
467
/** Do a comparison of two authentication digests by comparing the FULL data.
468
 *
469
 * Otherwise, the server can be subject to timing attacks.
470
 *
471
 * http://www.cs.rice.edu/~dwallach/pub/crosby-timing2009.pdf
472
 */
473
int fr_digest_cmp(uint8_t const *a, uint8_t const *b, size_t length)
474
0
{
475
0
  int result = 0;
476
0
  size_t i;
477
478
0
  for (i = 0; i < length; i++) result |= a[i] ^ b[i];
479
480
0
  return result;    /* 0 is OK, !0 is !OK, just like memcmp */
481
0
}
482
483
/** Get the filename from a path
484
 *
485
 * @param path to get filename from.
486
 * @return
487
 *  - pointer to the filename in the path.
488
 *  - pointer to the path if no '/' is found.
489
 */
490
char const *fr_filename(char const *path)
491
0
{
492
0
  char const *p = strrchr(path, '/');
493
494
0
  if (p) return p + 1;
495
496
0
  return path;
497
0
}
498
499
/** Trim a common prefix from a filename
500
 *
501
 * @param path to get filename from.
502
 * @param common prefix to trim from the path.
503
 * @return
504
 *  - pointer to the position on the path where the common prefix match ended.
505
 */
506
char const *fr_filename_common_trim(char const *path, char const *common)
507
0
{
508
0
  char const *p_p, *p_c, *p_pn, *p_cn;
509
510
0
  if (!path) return NULL;
511
0
  if (!common) return NULL;
512
513
0
  p_p = path;
514
0
  p_c = common;
515
516
0
  while ((p_pn = strchr(p_p, '/')) != NULL) {
517
0
    p_cn = strchr(p_c, '/');
518
0
    if (!p_cn) p_cn = p_c + strlen(p_c);
519
520
0
    if ((p_pn - p_p) != (p_cn - p_c)) break; /* path component not the same len */
521
0
    if (strncmp(p_p, p_c, p_pn - p_p) != 0) break;  /* path component not the same */
522
523
0
    p_p = p_pn + 1;
524
0
    p_c = p_cn + 1;
525
0
  }
526
527
0
  return p_p;
528
0
}