gen_uuid.c revision d1154eb460efe588eaed3d439c1caaca149fa362
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/* 36 * Force inclusion of SVID stuff since we need it if we're compiling in 37 * gcc-wall wall mode 38 */ 39#define _SVID_SOURCE 40 41#include "config.h" 42 43#ifdef _WIN32 44#define _WIN32_WINNT 0x0500 45#include <windows.h> 46#define UUID MYUUID 47#endif 48#include <stdio.h> 49#ifdef HAVE_UNISTD_H 50#include <unistd.h> 51#endif 52#ifdef HAVE_STDLIB_H 53#include <stdlib.h> 54#endif 55#include <string.h> 56#include <fcntl.h> 57#include <errno.h> 58#include <sys/types.h> 59#ifdef HAVE_SYS_TIME_H 60#include <sys/time.h> 61#endif 62#include <sys/wait.h> 63#include <sys/stat.h> 64#ifdef HAVE_SYS_FILE_H 65#include <sys/file.h> 66#endif 67#ifdef HAVE_SYS_IOCTL_H 68#include <sys/ioctl.h> 69#endif 70#ifdef HAVE_SYS_SOCKET_H 71#include <sys/socket.h> 72#endif 73#ifdef HAVE_SYS_UN_H 74#include <sys/un.h> 75#endif 76#ifdef HAVE_SYS_SOCKIO_H 77#include <sys/sockio.h> 78#endif 79#ifdef HAVE_NET_IF_H 80#include <net/if.h> 81#endif 82#ifdef HAVE_NETINET_IN_H 83#include <netinet/in.h> 84#endif 85#ifdef HAVE_NET_IF_DL_H 86#include <net/if_dl.h> 87#endif 88#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) 89#include <sys/syscall.h> 90#endif 91#ifdef HAVE_SYS_RESOURCE_H 92#include <sys/resource.h> 93#endif 94 95#include "uuidP.h" 96#include "uuidd.h" 97 98#ifdef HAVE_SRANDOM 99#define srand(x) srandom(x) 100#define rand() random() 101#endif 102 103#ifdef TLS 104#define THREAD_LOCAL static TLS 105#else 106#define THREAD_LOCAL static 107#endif 108 109#if defined(__linux__) && defined(__NR_gettid) && defined(HAVE_JRAND48) 110#define DO_JRAND_MIX 111THREAD_LOCAL unsigned short jrand_seed[3]; 112#endif 113 114#ifdef _WIN32 115static void gettimeofday (struct timeval *tv, void *dummy) 116{ 117 FILETIME ftime; 118 uint64_t n; 119 120 GetSystemTimeAsFileTime (&ftime); 121 n = (((uint64_t) ftime.dwHighDateTime << 32) 122 + (uint64_t) ftime.dwLowDateTime); 123 if (n) { 124 n /= 10; 125 n -= ((369 * 365 + 89) * (uint64_t) 86400) * 1000000; 126 } 127 128 tv->tv_sec = n / 1000000; 129 tv->tv_usec = n % 1000000; 130} 131 132static int getuid (void) 133{ 134 return 1; 135} 136#endif 137 138static int get_random_fd(void) 139{ 140 struct timeval tv; 141 static int fd = -2; 142 int i; 143 144 if (fd == -2) { 145 gettimeofday(&tv, 0); 146#ifndef _WIN32 147 fd = open("/dev/urandom", O_RDONLY); 148 if (fd == -1) 149 fd = open("/dev/random", O_RDONLY | O_NONBLOCK); 150 if (fd >= 0) { 151 i = fcntl(fd, F_GETFD); 152 if (i >= 0) 153 fcntl(fd, F_SETFD, i | FD_CLOEXEC); 154 } 155#endif 156 srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); 157#ifdef DO_JRAND_MIX 158 jrand_seed[0] = getpid() ^ (tv.tv_sec & 0xFFFF); 159 jrand_seed[1] = getppid() ^ (tv.tv_usec & 0xFFFF); 160 jrand_seed[2] = (tv.tv_sec ^ tv.tv_usec) >> 16; 161#endif 162 } 163 /* Crank the random number generator a few times */ 164 gettimeofday(&tv, 0); 165 for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) 166 rand(); 167 return fd; 168} 169 170 171/* 172 * Generate a series of random bytes. Use /dev/urandom if possible, 173 * and if not, use srandom/random. 174 */ 175static void get_random_bytes(void *buf, int nbytes) 176{ 177 int i, n = nbytes, fd = get_random_fd(); 178 int lose_counter = 0; 179 unsigned char *cp = (unsigned char *) buf; 180 unsigned short tmp_seed[3]; 181 182 if (fd >= 0) { 183 while (n > 0) { 184 i = read(fd, cp, n); 185 if (i <= 0) { 186 if (lose_counter++ > 16) 187 break; 188 continue; 189 } 190 n -= i; 191 cp += i; 192 lose_counter = 0; 193 } 194 } 195 196 /* 197 * We do this all the time, but this is the only source of 198 * randomness if /dev/random/urandom is out to lunch. 199 */ 200 for (cp = buf, i = 0; i < nbytes; i++) 201 *cp++ ^= (rand() >> 7) & 0xFF; 202#ifdef DO_JRAND_MIX 203 memcpy(tmp_seed, jrand_seed, sizeof(tmp_seed)); 204 jrand_seed[2] = jrand_seed[2] ^ syscall(__NR_gettid); 205 for (cp = buf, i = 0; i < nbytes; i++) 206 *cp++ ^= (jrand48(tmp_seed) >> 7) & 0xFF; 207 memcpy(jrand_seed, tmp_seed, 208 sizeof(jrand_seed)-sizeof(unsigned short)); 209#endif 210 211 return; 212} 213 214/* 215 * Get the ethernet hardware address, if we can find it... 216 * 217 * XXX for a windows version, probably should use GetAdaptersInfo: 218 * http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451 219 * commenting out get_node_id just to get gen_uuid to compile under windows 220 * is not the right way to go! 221 */ 222static int get_node_id(unsigned char *node_id) 223{ 224#ifdef HAVE_NET_IF_H 225 int sd; 226 struct ifreq ifr, *ifrp; 227 struct ifconf ifc; 228 char buf[1024]; 229 int n, i; 230 unsigned char *a; 231#ifdef HAVE_NET_IF_DL_H 232 struct sockaddr_dl *sdlp; 233#endif 234 235/* 236 * BSD 4.4 defines the size of an ifreq to be 237 * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len 238 * However, under earlier systems, sa_len isn't present, so the size is 239 * just sizeof(struct ifreq) 240 */ 241#ifdef HAVE_SA_LEN 242#ifndef max 243#define max(a,b) ((a) > (b) ? (a) : (b)) 244#endif 245#define ifreq_size(i) max(sizeof(struct ifreq),\ 246 sizeof((i).ifr_name)+(i).ifr_addr.sa_len) 247#else 248#define ifreq_size(i) sizeof(struct ifreq) 249#endif /* HAVE_SA_LEN*/ 250 251 sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); 252 if (sd < 0) { 253 return -1; 254 } 255 memset(buf, 0, sizeof(buf)); 256 ifc.ifc_len = sizeof(buf); 257 ifc.ifc_buf = buf; 258 if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) { 259 close(sd); 260 return -1; 261 } 262 n = ifc.ifc_len; 263 for (i = 0; i < n; i+= ifreq_size(*ifrp) ) { 264 ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i); 265 strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); 266#ifdef SIOCGIFHWADDR 267 if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) 268 continue; 269 a = (unsigned char *) &ifr.ifr_hwaddr.sa_data; 270#else 271#ifdef SIOCGENADDR 272 if (ioctl(sd, SIOCGENADDR, &ifr) < 0) 273 continue; 274 a = (unsigned char *) ifr.ifr_enaddr; 275#else 276#ifdef HAVE_NET_IF_DL_H 277 sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr; 278 if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6)) 279 continue; 280 a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen]; 281#else 282 /* 283 * XXX we don't have a way of getting the hardware 284 * address 285 */ 286 close(sd); 287 return 0; 288#endif /* HAVE_NET_IF_DL_H */ 289#endif /* SIOCGENADDR */ 290#endif /* SIOCGIFHWADDR */ 291 if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) 292 continue; 293 if (node_id) { 294 memcpy(node_id, a, 6); 295 close(sd); 296 return 1; 297 } 298 } 299 close(sd); 300#endif 301 return 0; 302} 303 304/* Assume that the gettimeofday() has microsecond granularity */ 305#define MAX_ADJUSTMENT 10 306 307static int get_clock(uint32_t *clock_high, uint32_t *clock_low, 308 uint16_t *ret_clock_seq, int *num) 309{ 310 THREAD_LOCAL int adjustment = 0; 311 THREAD_LOCAL struct timeval last = {0, 0}; 312 THREAD_LOCAL int state_fd = -2; 313 THREAD_LOCAL FILE *state_f; 314 THREAD_LOCAL uint16_t clock_seq; 315 struct timeval tv; 316 struct flock fl; 317 uint64_t clock_reg; 318 mode_t save_umask; 319 int len; 320 321 if (state_fd == -2) { 322 save_umask = umask(0); 323 state_fd = open("/var/lib/libuuid/clock.txt", 324 O_RDWR|O_CREAT, 0660); 325 (void) umask(save_umask); 326 state_f = fdopen(state_fd, "r+"); 327 if (!state_f) { 328 close(state_fd); 329 state_fd = -1; 330 } 331 } 332 fl.l_type = F_WRLCK; 333 fl.l_whence = SEEK_SET; 334 fl.l_start = 0; 335 fl.l_len = 0; 336 fl.l_pid = 0; 337 if (state_fd >= 0) { 338 rewind(state_f); 339 while (fcntl(state_fd, F_SETLKW, &fl) < 0) { 340 if ((errno == EAGAIN) || (errno == EINTR)) 341 continue; 342 fclose(state_f); 343 close(state_fd); 344 state_fd = -1; 345 break; 346 } 347 } 348 if (state_fd >= 0) { 349 unsigned int cl; 350 unsigned long tv1, tv2; 351 int a; 352 353 if (fscanf(state_f, "clock: %04x tv: %lu %lu adj: %d\n", 354 &cl, &tv1, &tv2, &a) == 4) { 355 clock_seq = cl & 0x3FFF; 356 last.tv_sec = tv1; 357 last.tv_usec = tv2; 358 adjustment = a; 359 } 360 } 361 362 if ((last.tv_sec == 0) && (last.tv_usec == 0)) { 363 get_random_bytes(&clock_seq, sizeof(clock_seq)); 364 clock_seq &= 0x3FFF; 365 gettimeofday(&last, 0); 366 last.tv_sec--; 367 } 368 369try_again: 370 gettimeofday(&tv, 0); 371 if ((tv.tv_sec < last.tv_sec) || 372 ((tv.tv_sec == last.tv_sec) && 373 (tv.tv_usec < last.tv_usec))) { 374 clock_seq = (clock_seq+1) & 0x3FFF; 375 adjustment = 0; 376 last = tv; 377 } else if ((tv.tv_sec == last.tv_sec) && 378 (tv.tv_usec == last.tv_usec)) { 379 if (adjustment >= MAX_ADJUSTMENT) 380 goto try_again; 381 adjustment++; 382 } else { 383 adjustment = 0; 384 last = tv; 385 } 386 387 clock_reg = tv.tv_usec*10 + adjustment; 388 clock_reg += ((uint64_t) tv.tv_sec)*10000000; 389 clock_reg += (((uint64_t) 0x01B21DD2) << 32) + 0x13814000; 390 391 if (num && (*num > 1)) { 392 adjustment += *num - 1; 393 last.tv_usec += adjustment / 10; 394 adjustment = adjustment % 10; 395 last.tv_sec += last.tv_usec / 1000000; 396 last.tv_usec = last.tv_usec % 1000000; 397 } 398 399 if (state_fd > 0) { 400 rewind(state_f); 401 len = fprintf(state_f, 402 "clock: %04x tv: %016lu %08lu adj: %08d\n", 403 clock_seq, last.tv_sec, last.tv_usec, adjustment); 404 fflush(state_f); 405 if (ftruncate(state_fd, len) < 0) { 406 fprintf(state_f, " \n"); 407 fflush(state_f); 408 } 409 rewind(state_f); 410 fl.l_type = F_UNLCK; 411 fcntl(state_fd, F_SETLK, &fl); 412 } 413 414 *clock_high = clock_reg >> 32; 415 *clock_low = clock_reg; 416 *ret_clock_seq = clock_seq; 417 return 0; 418} 419 420static ssize_t read_all(int fd, char *buf, size_t count) 421{ 422 ssize_t ret; 423 ssize_t c = 0; 424 int tries = 0; 425 426 memset(buf, 0, count); 427 while (count > 0) { 428 ret = read(fd, buf, count); 429 if (ret <= 0) { 430 if ((errno == EAGAIN || errno == EINTR || ret == 0) && 431 (tries++ < 5)) 432 continue; 433 return c ? c : -1; 434 } 435 if (ret > 0) 436 tries = 0; 437 count -= ret; 438 buf += ret; 439 c += ret; 440 } 441 return c; 442} 443 444/* 445 * Close all file descriptors 446 */ 447static void close_all_fds(void) 448{ 449 int i, max; 450 451#if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) 452 max = sysconf(_SC_OPEN_MAX); 453#elif defined(HAVE_GETDTABLESIZE) 454 max = getdtablesize(); 455#elif defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) 456 struct rlimit rl; 457 458 getrlimit(RLIMIT_NOFILE, &rl); 459 max = rl.rlim_cur; 460#else 461 max = OPEN_MAX; 462#endif 463 464 for (i=0; i < max; i++) { 465 close(i); 466 if (i <= 2) 467 open("/dev/null", O_RDWR); 468 } 469} 470 471 472/* 473 * Try using the uuidd daemon to generate the UUID 474 * 475 * Returns 0 on success, non-zero on failure. 476 */ 477static int get_uuid_via_daemon(int op, uuid_t out, int *num) 478{ 479#if defined(USE_UUIDD) && defined(HAVE_SYS_UN_H) 480 char op_buf[64]; 481 int op_len; 482 int s; 483 ssize_t ret; 484 int32_t reply_len = 0, expected = 16; 485 struct sockaddr_un srv_addr; 486 struct stat st; 487 pid_t pid; 488 static const char *uuidd_path = UUIDD_PATH; 489 static int access_ret = -2; 490 static int start_attempts = 0; 491 492 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 493 return -1; 494 495 srv_addr.sun_family = AF_UNIX; 496 strcpy(srv_addr.sun_path, UUIDD_SOCKET_PATH); 497 498 if (connect(s, (const struct sockaddr *) &srv_addr, 499 sizeof(struct sockaddr_un)) < 0) { 500 if (access_ret == -2) 501 access_ret = access(uuidd_path, X_OK); 502 if (access_ret == 0) 503 access_ret = stat(uuidd_path, &st); 504 if (access_ret == 0 && (st.st_mode & (S_ISUID | S_ISGID)) == 0) 505 access_ret = access(UUIDD_DIR, W_OK); 506 if (access_ret == 0 && start_attempts++ < 5) { 507 if ((pid = fork()) == 0) { 508 close_all_fds(); 509 execl(uuidd_path, "uuidd", "-qT", "300", 510 (char *) NULL); 511 exit(1); 512 } 513 (void) waitpid(pid, 0, 0); 514 if (connect(s, (const struct sockaddr *) &srv_addr, 515 sizeof(struct sockaddr_un)) < 0) 516 goto fail; 517 } else 518 goto fail; 519 } 520 op_buf[0] = op; 521 op_len = 1; 522 if (op == UUIDD_OP_BULK_TIME_UUID) { 523 memcpy(op_buf+1, num, sizeof(*num)); 524 op_len += sizeof(*num); 525 expected += sizeof(*num); 526 } 527 528 ret = write(s, op_buf, op_len); 529 if (ret < 1) 530 goto fail; 531 532 ret = read_all(s, (char *) &reply_len, sizeof(reply_len)); 533 if (ret < 0) 534 goto fail; 535 536 if (reply_len != expected) 537 goto fail; 538 539 ret = read_all(s, op_buf, reply_len); 540 541 if (op == UUIDD_OP_BULK_TIME_UUID) 542 memcpy(op_buf+16, num, sizeof(int)); 543 544 memcpy(out, op_buf, 16); 545 546 close(s); 547 return ((ret == expected) ? 0 : -1); 548 549fail: 550 close(s); 551#endif 552 return -1; 553} 554 555void uuid__generate_time(uuid_t out, int *num) 556{ 557 static unsigned char node_id[6]; 558 static int has_init = 0; 559 struct uuid uu; 560 uint32_t clock_mid; 561 562 if (!has_init) { 563 if (get_node_id(node_id) <= 0) { 564 get_random_bytes(node_id, 6); 565 /* 566 * Set multicast bit, to prevent conflicts 567 * with IEEE 802 addresses obtained from 568 * network cards 569 */ 570 node_id[0] |= 0x01; 571 } 572 has_init = 1; 573 } 574 get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num); 575 uu.clock_seq |= 0x8000; 576 uu.time_mid = (uint16_t) clock_mid; 577 uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000; 578 memcpy(uu.node, node_id, 6); 579 uuid_pack(&uu, out); 580} 581 582void uuid_generate_time(uuid_t out) 583{ 584#ifdef TLS 585 THREAD_LOCAL int num = 0; 586 THREAD_LOCAL struct uuid uu; 587 THREAD_LOCAL time_t last_time = 0; 588 time_t now; 589 590 if (num > 0) { 591 now = time(0); 592 if (now > last_time+1) 593 num = 0; 594 } 595 if (num <= 0) { 596 num = 1000; 597 if (get_uuid_via_daemon(UUIDD_OP_BULK_TIME_UUID, 598 out, &num) == 0) { 599 last_time = time(0); 600 uuid_unpack(out, &uu); 601 num--; 602 return; 603 } 604 num = 0; 605 } 606 if (num > 0) { 607 uu.time_low++; 608 if (uu.time_low == 0) { 609 uu.time_mid++; 610 if (uu.time_mid == 0) 611 uu.time_hi_and_version++; 612 } 613 num--; 614 uuid_pack(&uu, out); 615 return; 616 } 617#else 618 if (get_uuid_via_daemon(UUIDD_OP_TIME_UUID, out, 0) == 0) 619 return; 620#endif 621 622 uuid__generate_time(out, 0); 623} 624 625 626void uuid__generate_random(uuid_t out, int *num) 627{ 628 uuid_t buf; 629 struct uuid uu; 630 int i, n; 631 632 if (!num || !*num) 633 n = 1; 634 else 635 n = *num; 636 637 for (i = 0; i < n; i++) { 638 get_random_bytes(buf, sizeof(buf)); 639 uuid_unpack(buf, &uu); 640 641 uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000; 642 uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) 643 | 0x4000; 644 uuid_pack(&uu, out); 645 out += sizeof(uuid_t); 646 } 647} 648 649void uuid_generate_random(uuid_t out) 650{ 651 int num = 1; 652 /* No real reason to use the daemon for random uuid's -- yet */ 653 654 uuid__generate_random(out, &num); 655} 656 657 658/* 659 * This is the generic front-end to uuid_generate_random and 660 * uuid_generate_time. It uses uuid_generate_random only if 661 * /dev/urandom is available, since otherwise we won't have 662 * high-quality randomness. 663 */ 664void uuid_generate(uuid_t out) 665{ 666 if (get_random_fd() >= 0) 667 uuid_generate_random(out); 668 else 669 uuid_generate_time(out); 670} 671