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