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