Coverage Report

Created: 2025-11-11 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/util-linux/libuuid/src/gen_uuid.c
Line
Count
Source
1
/*
2
 * gen_uuid.c --- generate a DCE-compatible uuid
3
 *
4
 * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o.
5
 *
6
 * %Begin-Header%
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, and the entire permission notice in its entirety,
12
 *    including the disclaimer of warranties.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. The name of the author may not be used to endorse or promote
17
 *    products derived from this software without specific prior
18
 *    written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
21
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
23
 * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
24
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
30
 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
31
 * DAMAGE.
32
 * %End-Header%
33
 */
34
35
#ifdef _WIN32
36
#define _WIN32_WINNT 0x0500
37
#include <windows.h>
38
#define UUID MYUUID
39
#endif
40
#include <stdio.h>
41
#ifdef HAVE_UNISTD_H
42
#include <unistd.h>
43
#endif
44
#ifdef HAVE_STDLIB_H
45
#include <stdlib.h>
46
#endif
47
#include <string.h>
48
#include <fcntl.h>
49
#include <errno.h>
50
#include <limits.h>
51
#include <sys/types.h>
52
#ifdef HAVE_SYS_TIME_H
53
#include <sys/time.h>
54
#endif
55
#include <sys/stat.h>
56
#ifdef HAVE_SYS_FILE_H
57
#include <sys/file.h>
58
#endif
59
#ifdef HAVE_SYS_IOCTL_H
60
#include <sys/ioctl.h>
61
#endif
62
#ifdef HAVE_SYS_SOCKET_H
63
#include <sys/socket.h>
64
#endif
65
#ifdef HAVE_SYS_UN_H
66
#include <sys/un.h>
67
#endif
68
#ifdef HAVE_SYS_SOCKIO_H
69
#include <sys/sockio.h>
70
#endif
71
#ifdef HAVE_NET_IF_H
72
#include <net/if.h>
73
#endif
74
#ifdef HAVE_NETINET_IN_H
75
#include <netinet/in.h>
76
#endif
77
#ifdef HAVE_NET_IF_DL_H
78
#include <net/if_dl.h>
79
#endif
80
#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)
81
#include <sys/syscall.h>
82
#endif
83
#ifdef HAVE_LIBPTHREAD
84
# include <pthread.h>
85
#endif
86
87
#include <signal.h>
88
89
#include "all-io.h"
90
#include "uuidP.h"
91
#include "uuidd.h"
92
#include "randutils.h"
93
#include "strutils.h"
94
#include "c.h"
95
#include "md5.h"
96
#include "sha1.h"
97
#include "timeutils.h"
98
99
100
#ifdef _WIN32
101
static void gettimeofday (struct timeval *tv, void *dummy)
102
{
103
  FILETIME  ftime;
104
  uint64_t  n;
105
106
  GetSystemTimeAsFileTime (&ftime);
107
  n = (((uint64_t) ftime.dwHighDateTime << 32)
108
       + (uint64_t) ftime.dwLowDateTime);
109
  if (n) {
110
    n /= 10;
111
    n -= ((369 * 365 + 89) * (uint64_t) 86400) * 1000000;
112
  }
113
114
  tv->tv_sec = n / 1000000;
115
  tv->tv_usec = n % 1000000;
116
}
117
118
static int getuid (void)
119
{
120
  return 1;
121
}
122
#endif
123
124
#ifdef TEST_PROGRAM
125
#define gettimeofday gettimeofday_fixed
126
127
static int gettimeofday_fixed(struct timeval *tv, void *tz __attribute__((unused)))
128
{
129
  tv->tv_sec = 1645557742;
130
  tv->tv_usec = 123456;
131
  return 0;
132
}
133
#endif
134
135
/*
136
 * Get the ethernet hardware address, if we can find it...
137
 *
138
 * XXX for a windows version, probably should use GetAdaptersInfo:
139
 * http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451
140
 * commenting out get_node_id just to get gen_uuid to compile under windows
141
 * is not the right way to go!
142
 */
143
static int get_node_id(unsigned char *node_id)
144
0
{
145
0
#ifdef HAVE_NET_IF_H
146
0
  int   sd;
147
0
  struct ifreq  ifr, *ifrp;
148
0
  struct ifconf ifc;
149
0
  char buf[1024];
150
0
  int   n, i;
151
0
  unsigned char *a = NULL;
152
#ifdef HAVE_NET_IF_DL_H
153
  struct sockaddr_dl *sdlp;
154
#endif
155
156
/*
157
 * BSD 4.4 defines the size of an ifreq to be
158
 * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
159
 * However, under earlier systems, sa_len isn't present, so the size is
160
 * just sizeof(struct ifreq)
161
 */
162
#ifdef HAVE_SA_LEN
163
#define ifreq_size(i) max(sizeof(struct ifreq),\
164
     sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
165
#else
166
0
#define ifreq_size(i) sizeof(struct ifreq)
167
0
#endif /* HAVE_SA_LEN */
168
169
0
  sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
170
0
  if (sd < 0) {
171
0
    return -1;
172
0
  }
173
0
  memset(buf, 0, sizeof(buf));
174
0
  ifc.ifc_len = sizeof(buf);
175
0
  ifc.ifc_buf = buf;
176
0
  if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
177
0
    close(sd);
178
0
    return -1;
179
0
  }
180
0
  n = ifc.ifc_len;
181
0
  for (i = 0; i < n; i+= ifreq_size(*ifrp) ) {
182
0
    ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
183
0
    strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
184
0
#ifdef SIOCGIFHWADDR
185
0
    if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
186
0
      continue;
187
0
    a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
188
#else
189
#ifdef SIOCGENADDR
190
    if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
191
      continue;
192
    a = (unsigned char *) ifr.ifr_enaddr;
193
#else
194
#ifdef HAVE_NET_IF_DL_H
195
    sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr;
196
    if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6))
197
      continue;
198
    a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen];
199
#else
200
    /*
201
     * XXX we don't have a way of getting the hardware
202
     * address
203
     */
204
    close(sd);
205
    return 0;
206
#endif /* HAVE_NET_IF_DL_H */
207
#endif /* SIOCGENADDR */
208
#endif /* SIOCGIFHWADDR */
209
0
    if (a == NULL || (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]))
210
0
      continue;
211
0
    if (node_id) {
212
0
      memcpy(node_id, a, 6);
213
0
      close(sd);
214
0
      return 1;
215
0
    }
216
0
  }
217
0
  close(sd);
218
0
#endif
219
0
  return 0;
220
0
}
221
222
enum { STATE_FD_ERROR = -1, STATE_FD_INIT = -2 };
223
224
static int state_fd_init(const char *clock_file, FILE **fp)
225
0
{
226
0
  mode_t save_umask;
227
0
  int state_fd;
228
0
  FILE *state_f;
229
230
0
  save_umask = umask(0);
231
0
  state_fd = open(clock_file, O_RDWR|O_CREAT|O_CLOEXEC, 0660);
232
0
  (void) umask(save_umask);
233
0
  if (state_fd != -1) {
234
0
    state_f = fdopen(state_fd, "r+" UL_CLOEXECSTR);
235
0
    if (!state_f) {
236
0
      close(state_fd);
237
0
      state_fd = STATE_FD_ERROR;
238
0
    } else
239
0
      *fp = state_f;
240
0
  }
241
0
  return state_fd;
242
0
}
243
244
/* Assume that the gettimeofday() has microsecond granularity */
245
0
#define MAX_ADJUSTMENT 10
246
/* Reserve a clock_seq value for the 'continuous clock' implementation */
247
0
#define CLOCK_SEQ_CONT 0
248
249
/*
250
 * Get clock from global sequence clock counter.
251
 *
252
 * Return -1 if the clock counter could not be opened/locked (in this case
253
 * pseudorandom value is returned in @ret_clock_seq), otherwise return 0.
254
 */
255
static int get_clock(uint32_t *clock_high, uint32_t *clock_low,
256
         uint16_t *ret_clock_seq, int *num)
257
0
{
258
0
  THREAD_LOCAL int    adjustment = 0;
259
0
  THREAD_LOCAL struct timeval last = {0, 0};
260
0
  THREAD_LOCAL int    state_fd = STATE_FD_INIT;
261
0
  THREAD_LOCAL FILE   *state_f;
262
0
  THREAD_LOCAL uint16_t   clock_seq;
263
0
  struct timeval      tv;
264
0
  uint64_t      clock_reg;
265
0
  int       ret = 0;
266
267
0
  if (state_fd == STATE_FD_INIT)
268
0
    state_fd = state_fd_init(LIBUUID_CLOCK_FILE, &state_f);
269
270
0
  if (state_fd >= 0) {
271
0
    rewind(state_f);
272
0
    while (flock(state_fd, LOCK_EX) < 0) {
273
0
      if ((errno == EAGAIN) || (errno == EINTR))
274
0
        continue;
275
0
      fclose(state_f);
276
0
      close(state_fd);
277
0
      state_fd = STATE_FD_ERROR;
278
0
      ret = -1;
279
0
      break;
280
0
    }
281
0
  } else
282
0
    ret = -1;
283
284
0
  if (state_fd >= 0) {
285
0
    unsigned int cl;
286
0
    unsigned long tv1, tv2;
287
0
    int a;
288
289
0
    if (fscanf(state_f, "clock: %04x tv: %lu %lu adj: %d\n",
290
0
         &cl, &tv1, &tv2, &a) == 4) {
291
0
      clock_seq = cl & 0x3FFF;
292
0
      last.tv_sec = tv1;
293
0
      last.tv_usec = tv2;
294
0
      adjustment = a;
295
0
    }
296
    // reset in case of reserved CLOCK_SEQ_CONT
297
0
    if (clock_seq == CLOCK_SEQ_CONT) {
298
0
      last.tv_sec = 0;
299
0
      last.tv_usec = 0;
300
0
    }
301
0
  }
302
303
0
  if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
304
0
    do {
305
0
      ul_random_get_bytes(&clock_seq, sizeof(clock_seq));
306
0
      clock_seq &= 0x3FFF;
307
0
    } while (clock_seq == CLOCK_SEQ_CONT);
308
0
    gettimeofday(&last, NULL);
309
0
    last.tv_sec--;
310
0
  }
311
312
0
try_again:
313
0
  gettimeofday(&tv, NULL);
314
0
  if ((tv.tv_sec < last.tv_sec) ||
315
0
      ((tv.tv_sec == last.tv_sec) &&
316
0
       (tv.tv_usec < last.tv_usec))) {
317
0
    do {
318
0
      clock_seq = (clock_seq+1) & 0x3FFF;
319
0
    } while (clock_seq == CLOCK_SEQ_CONT);
320
0
    adjustment = 0;
321
0
    last = tv;
322
0
  } else if ((tv.tv_sec == last.tv_sec) &&
323
0
      (tv.tv_usec == last.tv_usec)) {
324
0
    if (adjustment >= MAX_ADJUSTMENT)
325
0
      goto try_again;
326
0
    adjustment++;
327
0
  } else {
328
0
    adjustment = 0;
329
0
    last = tv;
330
0
  }
331
332
0
  clock_reg = tv.tv_usec*10 + adjustment;
333
0
  clock_reg += ((uint64_t) tv.tv_sec)*10000000;
334
0
  clock_reg += (((uint64_t) 0x01B21DD2) << 32) + 0x13814000;
335
336
0
  if (num && (*num > 1)) {
337
0
    adjustment += *num - 1;
338
0
    last.tv_usec += adjustment / 10;
339
0
    adjustment = adjustment % 10;
340
0
    last.tv_sec += last.tv_usec / 1000000;
341
0
    last.tv_usec = last.tv_usec % 1000000;
342
0
  }
343
344
0
  if (state_fd >= 0) {
345
0
    rewind(state_f);
346
0
    fprintf(state_f,
347
0
            "clock: %04x tv: %016ld %08ld adj: %08d                   \n",
348
0
            clock_seq, (long)last.tv_sec, (long)last.tv_usec, adjustment);
349
0
    fflush(state_f);
350
0
    rewind(state_f);
351
0
    flock(state_fd, LOCK_UN);
352
0
  }
353
354
0
  *clock_high = clock_reg >> 32;
355
0
  *clock_low = clock_reg;
356
0
  *ret_clock_seq = clock_seq;
357
0
  return ret;
358
0
}
359
360
/*
361
 * Get current time in 100ns ticks.
362
 */
363
static uint64_t get_clock_counter(void)
364
0
{
365
0
  struct timeval tv;
366
0
  uint64_t clock_reg;
367
368
0
  gettimeofday(&tv, NULL);
369
0
  clock_reg = tv.tv_usec*10;
370
0
  clock_reg += ((uint64_t) tv.tv_sec) * 10000000ULL;
371
372
0
  return clock_reg;
373
0
}
374
375
/*
376
 * Get continuous clock value.
377
 *
378
 * Return -1 if there is no valid clock counter available,
379
 * otherwise return 0.
380
 *
381
 * This implementation doesn't deliver clock counters based on
382
 * the current time because last_clock_reg is only incremented
383
 * by the number of requested UUIDs.
384
 * max_clock_offset is used to limit the offset of last_clock_reg.
385
 * used/reserved UUIDs are written to LIBUUID_CLOCK_CONT_FILE.
386
 */
387
static int get_clock_cont(uint32_t *clock_high,
388
        uint32_t *clock_low,
389
        int num,
390
        uint32_t max_clock_offset)
391
0
{
392
  /* all 64bit clock_reg values in this function represent '100ns ticks'
393
   * due to the combination of tv_usec + MAX_ADJUSTMENT */
394
395
  /* time offset according to RFC 4122. 4.1.4. */
396
0
  const uint64_t reg_offset = (((uint64_t) 0x01B21DD2) << 32) + 0x13814000;
397
0
  static uint64_t last_clock_reg = 0;
398
0
  static uint64_t saved_clock_reg = 0;
399
0
  static int state_fd = STATE_FD_INIT;
400
0
  static FILE *state_f = NULL;
401
0
  uint64_t clock_reg, next_clock_reg;
402
403
0
  if (state_fd == STATE_FD_ERROR)
404
0
    return -1;
405
406
0
  clock_reg = get_clock_counter();
407
408
0
  if (state_fd == STATE_FD_INIT) {
409
0
    struct stat st;
410
411
0
    state_fd = state_fd_init(LIBUUID_CLOCK_CONT_FILE, &state_f);
412
0
    if (state_fd == STATE_FD_ERROR)
413
0
      return -1;
414
415
0
    if (fstat(state_fd, &st))
416
0
      goto error;
417
418
0
    if (st.st_size) {
419
0
      rewind(state_f);
420
0
      if (fscanf(state_f, "cont: %"SCNu64"\n", &last_clock_reg) != 1)
421
0
        goto error;
422
0
    } else
423
0
      last_clock_reg = clock_reg;
424
425
0
    saved_clock_reg = last_clock_reg;
426
0
  }
427
428
0
  if (max_clock_offset) {
429
0
    uint64_t co = 10000000ULL * (uint64_t)max_clock_offset; // clock_offset in [100ns]
430
431
0
    if ((last_clock_reg + co) < clock_reg)
432
0
      last_clock_reg = clock_reg - co;
433
0
  }
434
435
0
  clock_reg += MAX_ADJUSTMENT;
436
437
0
  next_clock_reg = last_clock_reg + (uint64_t)num;
438
0
  if (next_clock_reg >= clock_reg)
439
0
    return -1;
440
441
0
  if (next_clock_reg >= saved_clock_reg) {
442
0
    uint64_t cl = next_clock_reg + 100000000ULL;  // 10s interval in [100ns]
443
0
    int l;
444
445
0
    rewind(state_f);
446
0
    l = fprintf(state_f, "cont: %020"PRIu64"                   \n", cl);
447
0
    if (l < 30 || fflush(state_f))
448
0
      goto error;
449
0
    saved_clock_reg = cl;
450
0
  }
451
452
0
  *clock_high = (last_clock_reg + reg_offset) >> 32;
453
0
  *clock_low = last_clock_reg + reg_offset;
454
0
  last_clock_reg = next_clock_reg;
455
456
0
  return 0;
457
458
0
error:
459
0
  if (state_fd >= 0)
460
0
    close(state_fd);
461
0
  if (state_f)
462
0
    fclose(state_f);
463
0
  state_fd = STATE_FD_ERROR;
464
0
  state_f = NULL;
465
0
  return -1;
466
0
}
467
468
#if defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H) && !defined(TEST_PROGRAM)
469
470
/*
471
 * Try using the uuidd daemon to generate the UUID
472
 *
473
 * Returns 0 on success, non-zero on failure.
474
 */
475
static int get_uuid_via_daemon(int op, uuid_t out, int *num)
476
{
477
  char op_buf[64];
478
  int op_len;
479
  int s;
480
  ssize_t ret;
481
  int32_t reply_len = 0, expected = 16;
482
  struct sockaddr_un srv_addr;
483
484
  if (sizeof(UUIDD_SOCKET_PATH) > sizeof(srv_addr.sun_path))
485
    return -1;
486
487
  if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
488
    return -1;
489
490
  srv_addr.sun_family = AF_UNIX;
491
  xstrncpy(srv_addr.sun_path, UUIDD_SOCKET_PATH, sizeof(srv_addr.sun_path));
492
493
  if (connect(s, (const struct sockaddr *) &srv_addr,
494
        sizeof(struct sockaddr_un)) < 0)
495
    goto fail;
496
497
  op_buf[0] = op;
498
  op_len = 1;
499
  if (op == UUIDD_OP_BULK_TIME_UUID) {
500
    memcpy(op_buf+1, num, sizeof(*num));
501
    op_len += sizeof(*num);
502
    expected += sizeof(*num);
503
  }
504
505
  ret = write(s, op_buf, op_len);
506
  if (ret < 1)
507
    goto fail;
508
509
  ret = read_all(s, (char *) &reply_len, sizeof(reply_len));
510
  if (ret < 0)
511
    goto fail;
512
513
  if (reply_len != expected)
514
    goto fail;
515
516
  ret = read_all(s, op_buf, reply_len);
517
518
  if (op == UUIDD_OP_BULK_TIME_UUID)
519
    memcpy(op_buf+16, num, sizeof(int));
520
521
  memcpy(out, op_buf, 16);
522
523
  close(s);
524
  return ((ret == expected) ? 0 : -1);
525
526
fail:
527
  close(s);
528
  return -1;
529
}
530
531
#else /* !defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H) */
532
static int get_uuid_via_daemon(int op __attribute__((__unused__)),
533
        uuid_t out __attribute__((__unused__)),
534
        int *num __attribute__((__unused__)))
535
0
{
536
0
  return -1;
537
0
}
538
#endif
539
540
static int __uuid_generate_time_internal(uuid_t out, int *num, uint32_t cont_offset)
541
0
{
542
0
  static unsigned char node_id[6];
543
0
  static int has_init = 0;
544
0
  struct uuid uu;
545
0
  uint32_t  clock_mid;
546
0
  int ret;
547
548
0
  if (!has_init) {
549
0
    if (get_node_id(node_id) <= 0) {
550
0
      ul_random_get_bytes(node_id, 6);
551
      /*
552
       * Set multicast bit, to prevent conflicts
553
       * with IEEE 802 addresses obtained from
554
       * network cards
555
       */
556
0
      node_id[0] |= 0x01;
557
0
    }
558
0
    has_init = 1;
559
0
  }
560
0
  if (cont_offset) {
561
0
    ret = get_clock_cont(&clock_mid, &uu.time_low, *num, cont_offset);
562
0
    uu.clock_seq = CLOCK_SEQ_CONT;
563
0
    if (ret != 0) /* fallback to previous implpementation */
564
0
      ret = get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num);
565
0
  } else {
566
0
    ret = get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num);
567
0
  }
568
0
  uu.clock_seq |= 0x8000;
569
0
  uu.time_mid = (uint16_t) clock_mid;
570
0
  uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000;
571
0
  memcpy(uu.node, node_id, 6);
572
0
  uuid_pack(&uu, out);
573
0
  return ret;
574
0
}
575
576
int __uuid_generate_time(uuid_t out, int *num)
577
0
{
578
0
  return __uuid_generate_time_internal(out, num, 0);
579
0
}
580
581
int __uuid_generate_time_cont(uuid_t out, int *num, uint32_t cont_offset)
582
0
{
583
0
  return __uuid_generate_time_internal(out, num, cont_offset);
584
0
}
585
586
0
#define CS_MIN    (1<<6)
587
0
#define CS_MAX    (1<<18)
588
0
#define CS_FACTOR 2
589
590
static void __uuid_set_variant_and_version(uuid_t uuid, int version)
591
0
{
592
0
  uuid[6] = (uuid[6] & UUID_TYPE_MASK) | version << UUID_TYPE_SHIFT;
593
  /* only DCE is supported */
594
0
  uuid[8] = (uuid[8] & 0x3F) | 0x80;
595
0
}
596
597
/*
598
 * Generate time-based UUID and store it to @out
599
 *
600
 * Tries to guarantee uniqueness of the generated UUIDs by obtaining them from the uuidd daemon,
601
 * or, if uuidd is not usable, by using the global clock state counter (see get_clock()).
602
 * If neither of these is possible (e.g. because of insufficient permissions), it generates
603
 * the UUID anyway, but returns -1. Otherwise, returns 0.
604
 */
605
#ifdef HAVE_LIBPTHREAD
606
THREAD_LOCAL struct {
607
  int   num;
608
  int   cache_size;
609
  int   last_used;
610
  struct uuid uu;
611
  time_t    last_time;
612
} uuidd_cache = {
613
  .cache_size = CS_MIN,
614
};
615
616
static void reset_uuidd_cache(void)
617
0
{
618
0
  memset(&uuidd_cache, 0, sizeof(uuidd_cache));
619
0
  uuidd_cache.cache_size = CS_MIN;
620
0
}
621
#endif /* HAVE_LIBPTHREAD */
622
623
0
static int uuid_generate_time_generic(uuid_t out) {
624
0
#ifdef HAVE_LIBPTHREAD
625
0
  static volatile sig_atomic_t atfork_registered;
626
0
  time_t  now;
627
628
0
  if (!atfork_registered) {
629
0
    pthread_atfork(NULL, NULL, reset_uuidd_cache);
630
0
    atfork_registered = 1;
631
0
  }
632
633
0
  if (uuidd_cache.num > 0) { /* expire cache */
634
0
    now = time(NULL);
635
0
    if (now > uuidd_cache.last_time+1) {
636
0
      uuidd_cache.last_used = uuidd_cache.cache_size - uuidd_cache.num;
637
0
      uuidd_cache.num = 0;
638
0
    }
639
0
  }
640
0
  if (uuidd_cache.num <= 0) { /* fill cache */
641
    /*
642
     * num + OP_BULK provides a local cache in each application.
643
     * Start with a small cache size to cover short running applications
644
     * and adjust the cache size over the runntime.
645
     */
646
0
    if ((uuidd_cache.last_used == uuidd_cache.cache_size) && (uuidd_cache.cache_size < CS_MAX))
647
0
      uuidd_cache.cache_size *= CS_FACTOR;
648
0
    else if ((uuidd_cache.last_used < (uuidd_cache.cache_size / CS_FACTOR)) && (uuidd_cache.cache_size > CS_MIN))
649
0
      uuidd_cache.cache_size /= CS_FACTOR;
650
651
0
    uuidd_cache.num = uuidd_cache.cache_size;
652
653
0
    if (get_uuid_via_daemon(UUIDD_OP_BULK_TIME_UUID,
654
0
          out, &uuidd_cache.num) == 0) {
655
0
      uuidd_cache.last_time = time(NULL);
656
0
      uuid_unpack(out, &uuidd_cache.uu);
657
0
      uuidd_cache.num--;
658
0
      return 0;
659
0
    }
660
    /* request to daemon failed, reset cache */
661
0
    reset_uuidd_cache();
662
0
  }
663
0
  if (uuidd_cache.num > 0) { /* serve uuid from cache */
664
0
    uuidd_cache.uu.time_low++;
665
0
    if (uuidd_cache.uu.time_low == 0) {
666
0
      uuidd_cache.uu.time_mid++;
667
0
      if (uuidd_cache.uu.time_mid == 0)
668
0
        uuidd_cache.uu.time_hi_and_version++;
669
0
    }
670
0
    uuidd_cache.num--;
671
0
    uuid_pack(&uuidd_cache.uu, out);
672
0
    if (uuidd_cache.num == 0)
673
0
      uuidd_cache.last_used = uuidd_cache.cache_size;
674
0
    return 0;
675
0
  }
676
677
#else /* !HAVE_LIBPTHREAD */
678
  {
679
    int num = 1;
680
    if (get_uuid_via_daemon(UUIDD_OP_TIME_UUID, out, &num) == 0)
681
      return 0;
682
  }
683
#endif /* HAVE_LIBPTHREAD */
684
685
0
  return __uuid_generate_time(out, NULL);
686
0
}
687
688
/*
689
 * Generate time-based UUID and store it to @out.
690
 *
691
 * Discards return value from uuid_generate_time_generic()
692
 */
693
void uuid_generate_time(uuid_t out)
694
0
{
695
0
  (void)uuid_generate_time_generic(out);
696
0
}
697
698
699
int uuid_generate_time_safe(uuid_t out)
700
0
{
701
0
  return uuid_generate_time_generic(out);
702
0
}
703
704
void uuid_generate_time_v6(uuid_t out)
705
0
{
706
0
  uint32_t clock_high, clock_low;
707
0
  uint16_t clock_seq;
708
709
0
  get_clock(&clock_high, &clock_low, &clock_seq, NULL);
710
711
0
  out[0] = clock_high >> 20;
712
0
  out[1] = clock_high >> 12;
713
0
  out[2] = clock_high >>  4;
714
0
  out[3] = clock_high <<  4;
715
0
  out[3] |= clock_low >> 28;
716
0
  out[4] = clock_low >> 20;
717
0
  out[5] = clock_low >> 12;
718
0
  out[6] = clock_low >>  8;
719
0
  out[7] = clock_low >>  0;
720
721
0
  ul_random_get_bytes(out + 8, 8);
722
0
  __uuid_set_variant_and_version(out, UUID_TYPE_DCE_TIME_V6);
723
0
}
724
725
// FIXME variable additional information
726
void uuid_generate_time_v7(uuid_t out)
727
0
{
728
0
  struct timeval tv;
729
0
  uint64_t ms;
730
731
0
  gettimeofday(&tv, NULL);
732
733
0
  ms = tv.tv_sec * MSEC_PER_SEC + tv.tv_usec / USEC_PER_MSEC;
734
735
0
  out[0] = ms >> 40;
736
0
  out[1] = ms >> 32;
737
0
  out[2] = ms >> 24;
738
0
  out[3] = ms >> 16;
739
0
  out[4] = ms >>  8;
740
0
  out[5] = ms >>  0;
741
0
  ul_random_get_bytes(out + 6, 10);
742
0
  __uuid_set_variant_and_version(out, UUID_TYPE_DCE_TIME_V7);
743
0
}
744
745
746
int __uuid_generate_random(uuid_t out, int *num)
747
0
{
748
0
  uuid_t  buf;
749
0
  struct uuid uu;
750
0
  int i, n, r = 0;
751
752
0
  if (!num || !*num)
753
0
    n = 1;
754
0
  else
755
0
    n = *num;
756
757
0
  for (i = 0; i < n; i++) {
758
0
    if (ul_random_get_bytes(buf, sizeof(buf)))
759
0
      r = -1;
760
0
    uuid_unpack(buf, &uu);
761
762
0
    uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
763
0
    uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF)
764
0
      | 0x4000;
765
0
    uuid_pack(&uu, out);
766
0
    out += sizeof(uuid_t);
767
0
  }
768
769
0
  return r;
770
0
}
771
772
void uuid_generate_random(uuid_t out)
773
0
{
774
0
  int num = 1;
775
  /* No real reason to use the daemon for random uuid's -- yet */
776
777
0
  __uuid_generate_random(out, &num);
778
0
}
779
780
/*
781
 * This is the generic front-end to __uuid_generate_random and
782
 * uuid_generate_time.  It uses __uuid_generate_random output
783
 * only if high-quality randomness is available.
784
 */
785
void uuid_generate(uuid_t out)
786
0
{
787
0
  int num = 1;
788
789
0
  if (__uuid_generate_random(out, &num))
790
0
    uuid_generate_time(out);
791
0
}
792
793
/*
794
 * Generate an MD5 hashed (predictable) UUID based on a well-known UUID
795
 * providing the namespace and an arbitrary binary string.
796
 */
797
void uuid_generate_md5(uuid_t out, const uuid_t ns, const char *name, size_t len)
798
0
{
799
0
  UL_MD5_CTX ctx;
800
0
  char hash[UL_MD5LENGTH];
801
0
  uuid_t buf;
802
0
  struct uuid uu;
803
804
0
  ul_MD5Init(&ctx);
805
0
  ul_MD5Update(&ctx, ns, sizeof(uuid_t));
806
0
  ul_MD5Update(&ctx, (const unsigned char *)name, len);
807
0
  ul_MD5Final((unsigned char *)hash, &ctx);
808
809
0
  assert(sizeof(buf) <= sizeof(hash));
810
811
0
  memcpy(buf, hash, sizeof(buf));
812
0
  uuid_unpack(buf, &uu);
813
814
0
  uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
815
0
  uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x3000;
816
0
  uuid_pack(&uu, out);
817
0
}
818
819
/*
820
 * Generate a SHA1 hashed (predictable) UUID based on a well-known UUID
821
 * providing the namespace and an arbitrary binary string.
822
 */
823
void uuid_generate_sha1(uuid_t out, const uuid_t ns, const char *name, size_t len)
824
0
{
825
0
  UL_SHA1_CTX ctx;
826
0
  char hash[UL_SHA1LENGTH];
827
0
  uuid_t buf;
828
0
  struct uuid uu;
829
830
0
  ul_SHA1Init(&ctx);
831
0
  ul_SHA1Update(&ctx, ns, sizeof(uuid_t));
832
0
  ul_SHA1Update(&ctx, (const unsigned char *)name, len);
833
0
  ul_SHA1Final((unsigned char *)hash, &ctx);
834
835
0
  assert(sizeof(buf) <= sizeof(hash));
836
837
0
  memcpy(buf, hash, sizeof(buf));
838
0
  uuid_unpack(buf, &uu);
839
840
0
  uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
841
0
  uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x5000;
842
0
  uuid_pack(&uu, out);
843
0
}
844
845
#ifdef TEST_PROGRAM
846
int main(void)
847
{
848
  char buf[UUID_STR_LEN];
849
  uuid_t uuid;
850
851
  uuid_generate_time(uuid);
852
  uuid_unparse(uuid, buf);
853
  printf("%s\n", buf);
854
855
  uuid_generate_time_v6(uuid);
856
  uuid_unparse(uuid, buf);
857
  printf("%s\n", buf);
858
859
  uuid_generate_time_v7(uuid);
860
  uuid_unparse(uuid, buf);
861
  printf("%s\n", buf);
862
863
  return 0;
864
}
865
#endif