blob: eb793391c493701818e1da03441bb0d1b351bbc1 [file] [log] [blame]
bigbiff7b4c7a62015-01-01 19:44:14 -05001/*
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
84#include "all-io.h"
85#include "uuidP.h"
86#include "uuidd.h"
87#include "randutils.h"
88#include "c.h"
89
90#ifdef HAVE_TLS
91#define THREAD_LOCAL static __thread
92#else
93#define THREAD_LOCAL static
94#endif
95
96#ifdef _WIN32
97static void gettimeofday (struct timeval *tv, void *dummy)
98{
99 FILETIME ftime;
100 uint64_t n;
101
102 GetSystemTimeAsFileTime (&ftime);
103 n = (((uint64_t) ftime.dwHighDateTime << 32)
104 + (uint64_t) ftime.dwLowDateTime);
105 if (n) {
106 n /= 10;
107 n -= ((369 * 365 + 89) * (uint64_t) 86400) * 1000000;
108 }
109
110 tv->tv_sec = n / 1000000;
111 tv->tv_usec = n % 1000000;
112}
113
114static int getuid (void)
115{
116 return 1;
117}
118#endif
119
120/*
121 * Get the ethernet hardware address, if we can find it...
122 *
123 * XXX for a windows version, probably should use GetAdaptersInfo:
124 * http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451
125 * commenting out get_node_id just to get gen_uuid to compile under windows
126 * is not the right way to go!
127 */
128static int get_node_id(unsigned char *node_id)
129{
130#ifdef HAVE_NET_IF_H
131 int sd;
132 struct ifreq ifr, *ifrp;
133 struct ifconf ifc;
134 char buf[1024];
135 int n, i;
136 unsigned char *a;
137#ifdef HAVE_NET_IF_DL_H
138 struct sockaddr_dl *sdlp;
139#endif
140
141/*
142 * BSD 4.4 defines the size of an ifreq to be
143 * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
144 * However, under earlier systems, sa_len isn't present, so the size is
145 * just sizeof(struct ifreq)
146 */
147#ifdef HAVE_SA_LEN
148#define ifreq_size(i) max(sizeof(struct ifreq),\
149 sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
150#else
151#define ifreq_size(i) sizeof(struct ifreq)
152#endif /* HAVE_SA_LEN */
153
154 sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
155 if (sd < 0) {
156 return -1;
157 }
158 memset(buf, 0, sizeof(buf));
159 ifc.ifc_len = sizeof(buf);
160 ifc.ifc_buf = buf;
161 if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
162 close(sd);
163 return -1;
164 }
165 n = ifc.ifc_len;
166 for (i = 0; i < n; i+= ifreq_size(*ifrp) ) {
167 ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
168 strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
169#ifdef SIOCGIFHWADDR
170 if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
171 continue;
172 a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
173#else
174#ifdef SIOCGENADDR
175 if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
176 continue;
177 a = (unsigned char *) ifr.ifr_enaddr;
178#else
179#ifdef HAVE_NET_IF_DL_H
180 sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr;
181 if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6))
182 continue;
183 a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen];
184#else
185 /*
186 * XXX we don't have a way of getting the hardware
187 * address
188 */
189 close(sd);
190 return 0;
191#endif /* HAVE_NET_IF_DL_H */
192#endif /* SIOCGENADDR */
193#endif /* SIOCGIFHWADDR */
194 if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
195 continue;
196 if (node_id) {
197 memcpy(node_id, a, 6);
198 close(sd);
199 return 1;
200 }
201 }
202 close(sd);
203#endif
204 return 0;
205}
206
207/* Assume that the gettimeofday() has microsecond granularity */
208#define MAX_ADJUSTMENT 10
209
210/*
211 * Get clock from global sequence clock counter.
212 *
213 * Return -1 if the clock counter could not be opened/locked (in this case
214 * pseudorandom value is returned in @ret_clock_seq), otherwise return 0.
215 */
216static int get_clock(uint32_t *clock_high, uint32_t *clock_low,
217 uint16_t *ret_clock_seq, int *num)
218{
219 THREAD_LOCAL int adjustment = 0;
220 THREAD_LOCAL struct timeval last = {0, 0};
221 THREAD_LOCAL int state_fd = -2;
222 THREAD_LOCAL FILE *state_f;
223 THREAD_LOCAL uint16_t clock_seq;
224 struct timeval tv;
225 uint64_t clock_reg;
226 mode_t save_umask;
227 int len;
228 int ret = 0;
229
230 if (state_fd == -2) {
231 save_umask = umask(0);
232 state_fd = open(LIBUUID_CLOCK_FILE, O_RDWR|O_CREAT|O_CLOEXEC, 0660);
233 (void) umask(save_umask);
234 if (state_fd != -1) {
235 state_f = fdopen(state_fd, "r+" UL_CLOEXECSTR);
236 if (!state_f) {
237 close(state_fd);
238 state_fd = -1;
239 ret = -1;
240 }
241 }
242 else
243 ret = -1;
244 }
245 if (state_fd >= 0) {
246 rewind(state_f);
247 while (flock(state_fd, LOCK_EX) < 0) {
248 if ((errno == EAGAIN) || (errno == EINTR))
249 continue;
250 fclose(state_f);
251 close(state_fd);
252 state_fd = -1;
253 ret = -1;
254 break;
255 }
256 }
257 if (state_fd >= 0) {
258 unsigned int cl;
259 unsigned long tv1, tv2;
260 int a;
261
262 if (fscanf(state_f, "clock: %04x tv: %lu %lu adj: %d\n",
263 &cl, &tv1, &tv2, &a) == 4) {
264 clock_seq = cl & 0x3FFF;
265 last.tv_sec = tv1;
266 last.tv_usec = tv2;
267 adjustment = a;
268 }
269 }
270
271 if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
272 random_get_bytes(&clock_seq, sizeof(clock_seq));
273 clock_seq &= 0x3FFF;
274 gettimeofday(&last, 0);
275 last.tv_sec--;
276 }
277
278try_again:
279 gettimeofday(&tv, 0);
280 if ((tv.tv_sec < last.tv_sec) ||
281 ((tv.tv_sec == last.tv_sec) &&
282 (tv.tv_usec < last.tv_usec))) {
283 clock_seq = (clock_seq+1) & 0x3FFF;
284 adjustment = 0;
285 last = tv;
286 } else if ((tv.tv_sec == last.tv_sec) &&
287 (tv.tv_usec == last.tv_usec)) {
288 if (adjustment >= MAX_ADJUSTMENT)
289 goto try_again;
290 adjustment++;
291 } else {
292 adjustment = 0;
293 last = tv;
294 }
295
296 clock_reg = tv.tv_usec*10 + adjustment;
297 clock_reg += ((uint64_t) tv.tv_sec)*10000000;
298 clock_reg += (((uint64_t) 0x01B21DD2) << 32) + 0x13814000;
299
300 if (num && (*num > 1)) {
301 adjustment += *num - 1;
302 last.tv_usec += adjustment / 10;
303 adjustment = adjustment % 10;
304 last.tv_sec += last.tv_usec / 1000000;
305 last.tv_usec = last.tv_usec % 1000000;
306 }
307
308 if (state_fd >= 0) {
309 rewind(state_f);
310 len = fprintf(state_f,
311 "clock: %04x tv: %016lu %08lu adj: %08d\n",
312 clock_seq, last.tv_sec, last.tv_usec, adjustment);
313 fflush(state_f);
314 if (ftruncate(state_fd, len) < 0) {
315 fprintf(state_f, " \n");
316 fflush(state_f);
317 }
318 rewind(state_f);
319 flock(state_fd, LOCK_UN);
320 }
321
322 *clock_high = clock_reg >> 32;
323 *clock_low = clock_reg;
324 *ret_clock_seq = clock_seq;
325 return ret;
326}
327
328#if defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H)
329/*
330 * Try using the uuidd daemon to generate the UUID
331 *
332 * Returns 0 on success, non-zero on failure.
333 */
334static int get_uuid_via_daemon(int op, uuid_t out, int *num)
335{
336 char op_buf[64];
337 int op_len;
338 int s;
339 ssize_t ret;
340 int32_t reply_len = 0, expected = 16;
341 struct sockaddr_un srv_addr;
342
343 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
344 return -1;
345
346 srv_addr.sun_family = AF_UNIX;
347 strcpy(srv_addr.sun_path, UUIDD_SOCKET_PATH);
348
349 if (connect(s, (const struct sockaddr *) &srv_addr,
350 sizeof(struct sockaddr_un)) < 0)
351 goto fail;
352
353 op_buf[0] = op;
354 op_len = 1;
355 if (op == UUIDD_OP_BULK_TIME_UUID) {
356 memcpy(op_buf+1, num, sizeof(*num));
357 op_len += sizeof(*num);
358 expected += sizeof(*num);
359 }
360
361 ret = write(s, op_buf, op_len);
362 if (ret < 1)
363 goto fail;
364
365 ret = read_all(s, (char *) &reply_len, sizeof(reply_len));
366 if (ret < 0)
367 goto fail;
368
369 if (reply_len != expected)
370 goto fail;
371
372 ret = read_all(s, op_buf, reply_len);
373
374 if (op == UUIDD_OP_BULK_TIME_UUID)
375 memcpy(op_buf+16, num, sizeof(int));
376
377 memcpy(out, op_buf, 16);
378
379 close(s);
380 return ((ret == expected) ? 0 : -1);
381
382fail:
383 close(s);
384 return -1;
385}
386
387#else /* !defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H) */
388static int get_uuid_via_daemon(int op, uuid_t out, int *num)
389{
390 return -1;
391}
392#endif
393
394int __uuid_generate_time(uuid_t out, int *num)
395{
396 static unsigned char node_id[6];
397 static int has_init = 0;
398 struct uuid uu;
399 uint32_t clock_mid;
400 int ret;
401
402 if (!has_init) {
403 if (get_node_id(node_id) <= 0) {
404 random_get_bytes(node_id, 6);
405 /*
406 * Set multicast bit, to prevent conflicts
407 * with IEEE 802 addresses obtained from
408 * network cards
409 */
410 node_id[0] |= 0x01;
411 }
412 has_init = 1;
413 }
414 ret = get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num);
415 uu.clock_seq |= 0x8000;
416 uu.time_mid = (uint16_t) clock_mid;
417 uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000;
418 memcpy(uu.node, node_id, 6);
419 uuid_pack(&uu, out);
420 return ret;
421}
422
423/*
424 * Generate time-based UUID and store it to @out
425 *
426 * Tries to guarantee uniqueness of the generated UUIDs by obtaining them from the uuidd daemon,
427 * or, if uuidd is not usable, by using the global clock state counter (see get_clock()).
428 * If neither of these is possible (e.g. because of insufficient permissions), it generates
429 * the UUID anyway, but returns -1. Otherwise, returns 0.
430 */
431static int uuid_generate_time_generic(uuid_t out) {
432#ifdef HAVE_TLS
433 THREAD_LOCAL int num = 0;
434 THREAD_LOCAL struct uuid uu;
435 THREAD_LOCAL time_t last_time = 0;
436 time_t now;
437
438 if (num > 0) {
439 now = time(0);
440 if (now > last_time+1)
441 num = 0;
442 }
443 if (num <= 0) {
444 num = 1000;
445 if (get_uuid_via_daemon(UUIDD_OP_BULK_TIME_UUID,
446 out, &num) == 0) {
447 last_time = time(0);
448 uuid_unpack(out, &uu);
449 num--;
450 return 0;
451 }
452 num = 0;
453 }
454 if (num > 0) {
455 uu.time_low++;
456 if (uu.time_low == 0) {
457 uu.time_mid++;
458 if (uu.time_mid == 0)
459 uu.time_hi_and_version++;
460 }
461 num--;
462 uuid_pack(&uu, out);
463 return 0;
464 }
465#else
466 if (get_uuid_via_daemon(UUIDD_OP_TIME_UUID, out, 0) == 0)
467 return 0;
468#endif
469
470 return __uuid_generate_time(out, 0);
471}
472
473/*
474 * Generate time-based UUID and store it to @out.
475 *
476 * Discards return value from uuid_generate_time_generic()
477 */
478void uuid_generate_time(uuid_t out)
479{
480 (void)uuid_generate_time_generic(out);
481}
482
483
484int uuid_generate_time_safe(uuid_t out)
485{
486 return uuid_generate_time_generic(out);
487}
488
489
490void __uuid_generate_random(uuid_t out, int *num)
491{
492 uuid_t buf;
493 struct uuid uu;
494 int i, n;
495
496 if (!num || !*num)
497 n = 1;
498 else
499 n = *num;
500
501 for (i = 0; i < n; i++) {
502 random_get_bytes(buf, sizeof(buf));
503 uuid_unpack(buf, &uu);
504
505 uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
506 uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF)
507 | 0x4000;
508 uuid_pack(&uu, out);
509 out += sizeof(uuid_t);
510 }
511}
512
513void uuid_generate_random(uuid_t out)
514{
515 int num = 1;
516 /* No real reason to use the daemon for random uuid's -- yet */
517
518 __uuid_generate_random(out, &num);
519}
520
521/*
522 * Check whether good random source (/dev/random or /dev/urandom)
523 * is available.
524 */
525static int have_random_source(void)
526{
527 struct stat s;
528
529 return (!stat("/dev/random", &s) || !stat("/dev/urandom", &s));
530}
531
532
533/*
534 * This is the generic front-end to uuid_generate_random and
535 * uuid_generate_time. It uses uuid_generate_random only if
536 * /dev/urandom is available, since otherwise we won't have
537 * high-quality randomness.
538 */
539void uuid_generate(uuid_t out)
540{
541 if (have_random_source())
542 uuid_generate_random(out);
543 else
544 uuid_generate_time(out);
545}