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 #include <stdio.h> 36 #include <unistd.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <fcntl.h> 40 #include <errno.h> 41 #include <sys/types.h> 42 #include <sys/time.h> 43 #include <sys/wait.h> 44 #include <sys/stat.h> 45 #include <sys/file.h> 46 #include <sys/ioctl.h> 47 #include <sys/socket.h> 48 #include <sys/un.h> 49 #include <sys/sockio.h> 50 #include <net/if.h> 51 #include <netinet/in.h> 52 #include <net/if_dl.h> 53 #include <sys/resource.h> 54 55 #include "uuidP.h" 56 57 #ifdef HAVE_SRANDOM 58 #define srand(x) srandom(x) 59 #define rand() random() 60 #endif 61 62 #ifdef TLS 63 #define THREAD_LOCAL static TLS 64 #else 65 #define THREAD_LOCAL static 66 #endif 67 68 #if defined(__linux__) && defined(__NR_gettid) && defined(HAVE_JRAND48) 69 #define DO_JRAND_MIX 70 THREAD_LOCAL unsigned short jrand_seed[3]; 71 #endif 72 73 static int get_random_fd(void) 74 { 75 struct timeval tv; 76 static int fd = -2; 77 int i; 78 79 if (fd == -2) { 80 gettimeofday(&tv, 0); 81 fd = open("/dev/urandom", O_RDONLY); 82 if (fd == -1) 83 fd = open("/dev/random", O_RDONLY | O_NONBLOCK); 84 if (fd >= 0) { 85 i = fcntl(fd, F_GETFD); 86 if (i >= 0) 87 fcntl(fd, F_SETFD, i | FD_CLOEXEC); 88 } 89 srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); 90 #ifdef DO_JRAND_MIX 91 jrand_seed[0] = getpid() ^ (tv.tv_sec & 0xFFFF); 92 jrand_seed[1] = getppid() ^ (tv.tv_usec & 0xFFFF); 93 jrand_seed[2] = (tv.tv_sec ^ tv.tv_usec) >> 16; 94 #endif 95 } 96 /* Crank the random number generator a few times */ 97 gettimeofday(&tv, 0); 98 for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) 99 rand(); 100 return fd; 101 } 102 103 104 /* 105 * Generate a series of random bytes. Use /dev/urandom if possible, 106 * and if not, use srandom/random. 107 */ 108 static void get_random_bytes(void *buf, int nbytes) 109 { 110 int i, n = nbytes, fd = get_random_fd(); 111 int lose_counter = 0; 112 unsigned char *cp = buf; 113 114 if (fd >= 0) { 115 while (n > 0) { 116 i = read(fd, cp, n); 117 if (i <= 0) { 118 if (lose_counter++ > 16) 119 break; 120 continue; 121 } 122 n -= i; 123 cp += i; 124 lose_counter = 0; 125 } 126 } 127 128 /* 129 * We do this all the time, but this is the only source of 130 * randomness if /dev/random/urandom is out to lunch. 131 */ 132 for (cp = buf, i = 0; i < nbytes; i++) 133 *cp++ ^= (rand() >> 7) & 0xFF; 134 #ifdef DO_JRAND_MIX 135 { 136 unsigned short tmp_seed[3]; 137 138 memcpy(tmp_seed, jrand_seed, sizeof(tmp_seed)); 139 jrand_seed[2] = jrand_seed[2] ^ syscall(__NR_gettid); 140 for (cp = buf, i = 0; i < nbytes; i++) 141 *cp++ ^= (jrand48(tmp_seed) >> 7) & 0xFF; 142 memcpy(jrand_seed, tmp_seed, 143 sizeof(jrand_seed) - sizeof(unsigned short)); 144 } 145 #endif 146 147 return; 148 } 149 150 #ifndef _KERNEL_MODE 151 /* 152 * Get the ethernet hardware address, if we can find it... 153 * 154 * XXX for a windows version, probably should use GetAdaptersInfo: 155 * http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451 156 * commenting out get_node_id just to get gen_uuid to compile under windows 157 * is not the right way to go! 158 */ 159 static int get_node_id(unsigned char *node_id) 160 { 161 int sd; 162 struct ifreq ifr, *ifrp; 163 struct ifconf ifc; 164 char buf[1024]; 165 int n, i; 166 unsigned char *a; 167 struct sockaddr_dl *sdlp; 168 169 /* 170 * BSD 4.4 defines the size of an ifreq to be 171 * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len 172 * However, under earlier systems, sa_len isn't present, so the size is 173 * just sizeof(struct ifreq) 174 */ 175 #ifndef max 176 #define max(a,b) ((a) > (b) ? (a) : (b)) 177 #endif 178 #define ifreq_size(i) max(sizeof(struct ifreq),\ 179 sizeof((i).ifr_name)+(i).ifr_addr.sa_len) 180 181 sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); 182 if (sd < 0) { 183 return -1; 184 } 185 memset(buf, 0, sizeof(buf)); 186 ifc.ifc_len = sizeof(buf); 187 ifc.ifc_buf = buf; 188 if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) { 189 close(sd); 190 return -1; 191 } 192 n = ifc.ifc_len; 193 for (i = 0; i < n; i+= ifreq_size(*ifrp) ) { 194 ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i); 195 strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); 196 #ifdef SIOCGIFHWADDR 197 if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) 198 continue; 199 a = (unsigned char *) &ifr.ifr_hwaddr.sa_data; 200 #else 201 #ifdef SIOCGENADDR 202 if (ioctl(sd, SIOCGENADDR, &ifr) < 0) 203 continue; 204 a = (unsigned char *) ifr.ifr_enaddr; 205 #else 206 sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr; 207 if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6)) 208 continue; 209 a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen]; 210 #endif /* SIOCGENADDR */ 211 #endif /* SIOCGIFHWADDR */ 212 if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) 213 continue; 214 if (node_id) { 215 memcpy(node_id, a, 6); 216 close(sd); 217 return 1; 218 } 219 } 220 close(sd); 221 return 0; 222 } 223 224 /* Assume that the gettimeofday() has microsecond granularity */ 225 #define MAX_ADJUSTMENT 10 226 227 static int get_clock(uint32_t *clock_high, uint32_t *clock_low, 228 uint16_t *ret_clock_seq, int *num) 229 { 230 THREAD_LOCAL int adjustment = 0; 231 THREAD_LOCAL struct timeval last = {0, 0}; 232 THREAD_LOCAL int state_fd = -2; 233 THREAD_LOCAL FILE *state_f; 234 THREAD_LOCAL uint16_t clock_seq; 235 struct timeval tv; 236 struct flock fl; 237 uint64_t clock_reg; 238 mode_t save_umask; 239 int len; 240 241 if (state_fd == -2) { 242 save_umask = umask(0); 243 state_fd = open("/var/lib/libuuid/clock.txt", 244 O_RDWR|O_CREAT, 0660); 245 (void) umask(save_umask); 246 if (state_fd >= 0) { 247 state_f = fdopen(state_fd, "r+"); 248 if (!state_f) { 249 close(state_fd); 250 state_fd = -1; 251 } 252 } 253 } 254 fl.l_type = F_WRLCK; 255 fl.l_whence = SEEK_SET; 256 fl.l_start = 0; 257 fl.l_len = 0; 258 fl.l_pid = 0; 259 if (state_fd >= 0) { 260 rewind(state_f); 261 while (fcntl(state_fd, F_SETLKW, &fl) < 0) { 262 if ((errno == EAGAIN) || (errno == EINTR)) 263 continue; 264 fclose(state_f); 265 state_fd = -1; 266 break; 267 } 268 } 269 if (state_fd >= 0) { 270 unsigned int cl; 271 unsigned long tv1, tv2; 272 int a; 273 274 if (fscanf(state_f, "clock: %04x tv: %lu %lu adj: %d\n", 275 &cl, &tv1, &tv2, &a) == 4) { 276 clock_seq = cl & 0x3FFF; 277 last.tv_sec = tv1; 278 last.tv_usec = tv2; 279 adjustment = a; 280 } 281 } 282 283 if ((last.tv_sec == 0) && (last.tv_usec == 0)) { 284 get_random_bytes(&clock_seq, sizeof(clock_seq)); 285 clock_seq &= 0x3FFF; 286 gettimeofday(&last, 0); 287 last.tv_sec--; 288 } 289 290 try_again: 291 gettimeofday(&tv, 0); 292 if ((tv.tv_sec < last.tv_sec) || 293 ((tv.tv_sec == last.tv_sec) && 294 (tv.tv_usec < last.tv_usec))) { 295 clock_seq = (clock_seq+1) & 0x3FFF; 296 adjustment = 0; 297 last = tv; 298 } else if ((tv.tv_sec == last.tv_sec) && 299 (tv.tv_usec == last.tv_usec)) { 300 if (adjustment >= MAX_ADJUSTMENT) 301 goto try_again; 302 adjustment++; 303 } else { 304 adjustment = 0; 305 last = tv; 306 } 307 308 clock_reg = tv.tv_usec*10 + adjustment; 309 clock_reg += ((uint64_t) tv.tv_sec)*10000000; 310 clock_reg += (((uint64_t) 0x01B21DD2) << 32) + 0x13814000; 311 312 if (num && (*num > 1)) { 313 adjustment += *num - 1; 314 last.tv_usec += adjustment / 10; 315 adjustment = adjustment % 10; 316 last.tv_sec += last.tv_usec / 1000000; 317 last.tv_usec = last.tv_usec % 1000000; 318 } 319 320 if (state_fd > 0) { 321 rewind(state_f); 322 len = fprintf(state_f, 323 "clock: %04x tv: %016lu %08lu adj: %08d\n", 324 clock_seq, last.tv_sec, (long)last.tv_usec, 325 adjustment); 326 fflush(state_f); 327 if (ftruncate(state_fd, len) < 0) { 328 fprintf(state_f, " \n"); 329 fflush(state_f); 330 } 331 rewind(state_f); 332 fl.l_type = F_UNLCK; 333 if (fcntl(state_fd, F_SETLK, &fl) < 0) { 334 fclose(state_f); 335 state_fd = -1; 336 } 337 } 338 339 *clock_high = clock_reg >> 32; 340 *clock_low = clock_reg; 341 *ret_clock_seq = clock_seq; 342 return 0; 343 } 344 345 void uuid__generate_time(uuid_t out, int *num) 346 { 347 static unsigned char node_id[6]; 348 static int has_init = 0; 349 struct uuid uu; 350 uint32_t clock_mid; 351 352 if (!has_init) { 353 if (get_node_id(node_id) <= 0) { 354 get_random_bytes(node_id, 6); 355 /* 356 * Set multicast bit, to prevent conflicts 357 * with IEEE 802 addresses obtained from 358 * network cards 359 */ 360 node_id[0] |= 0x01; 361 } 362 has_init = 1; 363 } 364 get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num); 365 uu.clock_seq |= 0x8000; 366 uu.time_mid = (uint16_t) clock_mid; 367 uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000; 368 memcpy(uu.node, node_id, 6); 369 uuid_pack(&uu, out); 370 } 371 372 void uuid_generate_time(uuid_t out) 373 { 374 #ifdef TLS 375 THREAD_LOCAL int num = 0; 376 THREAD_LOCAL struct uuid uu; 377 THREAD_LOCAL time_t last_time = 0; 378 time_t now; 379 380 if (num > 0) { 381 now = time(0); 382 if (now > last_time+1) 383 num = 0; 384 } 385 if (num <= 0) { 386 num = 1000; 387 if (-1 == 0) { 388 last_time = time(0); 389 uuid_unpack(out, &uu); 390 num--; 391 return; 392 } 393 num = 0; 394 } 395 if (num > 0) { 396 uu.time_low++; 397 if (uu.time_low == 0) { 398 uu.time_mid++; 399 if (uu.time_mid == 0) 400 uu.time_hi_and_version++; 401 } 402 num--; 403 uuid_pack(&uu, out); 404 return; 405 } 406 #else 407 if (-1 == 0) 408 return; 409 #endif 410 411 uuid__generate_time(out, 0); 412 } 413 #endif // !_KERNEL_MODE 414 415 void uuid__generate_random(uuid_t out, int *num) 416 { 417 uuid_t buf; 418 struct uuid uu; 419 int i, n; 420 421 if (!num || !*num) 422 n = 1; 423 else 424 n = *num; 425 426 for (i = 0; i < n; i++) { 427 get_random_bytes(buf, sizeof(buf)); 428 uuid_unpack(buf, &uu); 429 430 uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000; 431 uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) 432 | 0x4000; 433 uuid_pack(&uu, out); 434 out += sizeof(uuid_t); 435 } 436 } 437 438 void uuid_generate_random(uuid_t out) 439 { 440 int num = 1; 441 /* No real reason to use the daemon for random uuid's -- yet */ 442 443 uuid__generate_random(out, &num); 444 } 445 446 /* 447 * Check whether good random source (/dev/random or /dev/urandom) 448 * is available. 449 */ 450 static int have_random_source(void) 451 { 452 struct stat s; 453 454 return (!stat("/dev/random", &s) || !stat("/dev/urandom", &s)); 455 } 456 457 458 #ifndef _KERNEL_MODE 459 /* 460 * This is the generic front-end to uuid_generate_random and 461 * uuid_generate_time. It uses uuid_generate_random only if 462 * /dev/urandom is available, since otherwise we won't have 463 * high-quality randomness. 464 */ 465 void uuid_generate(uuid_t out) 466 { 467 if (have_random_source()) 468 uuid_generate_random(out); 469 else 470 uuid_generate_time(out); 471 } 472 #else 473 void uuid_generate(uuid_t out) 474 { 475 uuid_generate_random(out); 476 } 477 #endif 478