4430 libuuid could cache /dev/random
[unleashed.git] / usr / src / lib / libuuid / common / uuid.c
blobd0601e4fbfd08eca836a8f113169f65420f56574
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2012 Milan Jurik. All rights reserved.
25 * Copyright 2013 Joyent, Inc. All rights reserved.
29 * The copyright in this file is taken from the original Leach & Salz
30 * UUID specification, from which this implementation is derived.
34 * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
35 * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
36 * Digital Equipment Corporation, Maynard, Mass. Copyright (c) 1998
37 * Microsoft. To anyone who acknowledges that this file is provided
38 * "AS IS" without any express or implied warranty: permission to use,
39 * copy, modify, and distribute this file for any purpose is hereby
40 * granted without fee, provided that the above copyright notices and
41 * this notice appears in all source code copies, and that none of the
42 * names of Open Software Foundation, Inc., Hewlett-Packard Company,
43 * or Digital Equipment Corporation be used in advertising or
44 * publicity pertaining to distribution of the software without
45 * specific, written prior permission. Neither Open Software
46 * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
47 * Equipment Corporation makes any representations about the
48 * suitability of this software for any purpose.
52 * This module is the workhorse for generating abstract
53 * UUIDs. It delegates system-specific tasks (such
54 * as obtaining the node identifier or system time)
55 * to the sysdep module.
58 #include <ctype.h>
59 #include <sys/param.h>
60 #include <sys/stat.h>
61 #include <errno.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <strings.h>
65 #include <fcntl.h>
66 #include <unistd.h>
67 #include <synch.h>
68 #include <sys/mman.h>
69 #include "uuid_misc.h"
71 shared_buffer_t *data;
73 static uuid_node_t node_id_cache;
74 static int node_init;
75 static int file_type;
76 static int fd;
79 * The urandmtx mutex prevents multiple opens of /dev/urandom and protects the
80 * cache.
82 #define RCACHE_SIZE 65535
83 static mutex_t urandmtx;
84 static int fd_urand = -1;
85 static char rcache[RCACHE_SIZE];
86 static char *rcachep = rcache;
89 * misc routines
91 uint16_t get_random(void);
92 void get_current_time(uuid_time_t *);
94 void struct_to_string(uuid_t, struct uuid *);
95 void string_to_struct(struct uuid *, uuid_t);
96 int get_ethernet_address(uuid_node_t *);
99 * local functions
101 static int map_state();
102 static void format_uuid(struct uuid *, uint16_t, uuid_time_t,
103 uuid_node_t);
104 static void fill_random_bytes(uchar_t *, int);
105 static int uuid_create(struct uuid *);
106 static void gen_ethernet_address(uuid_node_t *);
107 static void revalidate_data(uuid_node_t *);
110 * Generates a uuid based on version 1 format.
111 * Returns 0 on success and -1 on failure.
113 static int
114 uuid_create(struct uuid *uuid)
116 uuid_time_t timestamp;
117 uuid_node_t system_node;
118 int ret, non_unique = 0;
121 * Get the system MAC address and/or cache it
123 if (node_init) {
124 bcopy(&node_id_cache, &system_node, sizeof (uuid_node_t));
125 } else {
126 gen_ethernet_address(&system_node);
127 bcopy(&system_node, &node_id_cache, sizeof (uuid_node_t));
128 node_init = 1;
132 * Access the state file, mmap it and initialize the shared lock.
133 * file_type tells us whether we had access to the state file or
134 * created a temporary one.
136 if (map_state() == -1)
137 return (-1);
140 * Acquire the lock
142 for (;;) {
143 if ((ret = mutex_lock(&data->lock)) == 0)
144 break;
145 else
146 switch (ret) {
147 case EOWNERDEAD:
148 revalidate_data(&system_node);
149 (void) mutex_consistent(&data->lock);
150 (void) mutex_unlock(&data->lock);
151 break;
152 case ENOTRECOVERABLE:
153 return (ret);
157 /* State file is either new or is temporary, get a random clock seq */
158 if (data->state.clock == 0) {
159 data->state.clock = get_random();
160 non_unique++;
163 if (memcmp(&system_node, &data->state.node, sizeof (uuid_node_t)) != 0)
164 data->state.clock++;
166 get_current_time(&timestamp);
169 * If timestamp is not set or is not in the past, bump
170 * data->state.clock
172 if ((data->state.ts == 0) || (data->state.ts >= timestamp)) {
173 data->state.clock++;
174 data->state.ts = timestamp;
177 if (non_unique)
178 system_node.nodeID[0] |= 0x80;
180 /* Stuff fields into the UUID struct */
181 format_uuid(uuid, data->state.clock, timestamp, system_node);
183 (void) mutex_unlock(&data->lock);
185 return (0);
189 * Fills system_node with Ethernet address if available,
190 * else fills random numbers
192 static void
193 gen_ethernet_address(uuid_node_t *system_node)
195 uchar_t node[6];
197 if (get_ethernet_address(system_node) != 0) {
198 fill_random_bytes(node, 6);
199 (void) memcpy(system_node->nodeID, node, 6);
201 * use 8:0:20 with the multicast bit set
202 * to avoid namespace collisions.
204 system_node->nodeID[0] = 0x88;
205 system_node->nodeID[1] = 0x00;
206 system_node->nodeID[2] = 0x20;
211 * Formats a UUID, given the clock_seq timestamp, and node address.
212 * Fills in passed-in pointer with the resulting uuid.
214 static void
215 format_uuid(struct uuid *uuid, uint16_t clock_seq,
216 uuid_time_t timestamp, uuid_node_t node)
220 * First set up the first 60 bits from the timestamp
222 uuid->time_low = (uint32_t)(timestamp & 0xFFFFFFFF);
223 uuid->time_mid = (uint16_t)((timestamp >> 32) & 0xFFFF);
224 uuid->time_hi_and_version = (uint16_t)((timestamp >> 48) & 0x0FFF);
227 * This is version 1, so say so in the UUID version field (4 bits)
229 uuid->time_hi_and_version |= (1 << 12);
232 * Now do the clock sequence
234 uuid->clock_seq_low = clock_seq & 0xFF;
237 * We must save the most-significant 2 bits for the reserved field
239 uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8;
242 * The variant for this format is the 2 high bits set to 10,
243 * so here it is
245 uuid->clock_seq_hi_and_reserved |= 0x80;
248 * write result to passed-in pointer
250 (void) memcpy(&uuid->node_addr, &node, sizeof (uuid->node_addr));
254 * Opens/creates the state file, falling back to a tmp
256 static int
257 map_state()
259 FILE *tmp;
261 /* If file's mapped, return */
262 if (file_type != 0)
263 return (1);
265 if ((fd = open(STATE_LOCATION, O_RDWR)) < 0) {
266 file_type = TEMP_FILE;
268 if ((tmp = tmpfile()) == NULL)
269 return (-1);
270 else
271 fd = fileno(tmp);
272 } else {
273 file_type = STATE_FILE;
276 (void) ftruncate(fd, (off_t)sizeof (shared_buffer_t));
278 /* LINTED - alignment */
279 data = (shared_buffer_t *)mmap(NULL, sizeof (shared_buffer_t),
280 PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
282 if (data == MAP_FAILED)
283 return (-1);
285 (void) mutex_init(&data->lock, USYNC_PROCESS|LOCK_ROBUST, 0);
287 (void) close(fd);
289 return (1);
292 static void
293 revalidate_data(uuid_node_t *node)
295 int i;
297 data->state.ts = 0;
299 for (i = 0; i < sizeof (data->state.node.nodeID); i++)
300 data->state.node.nodeID[i] = 0;
302 data->state.clock = 0;
304 gen_ethernet_address(node);
305 bcopy(node, &node_id_cache, sizeof (uuid_node_t));
306 node_init = 1;
310 * Prints a nicely-formatted uuid to stdout.
312 void
313 uuid_print(struct uuid u)
315 int i;
317 (void) printf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", u.time_low, u.time_mid,
318 u.time_hi_and_version, u.clock_seq_hi_and_reserved,
319 u.clock_seq_low);
320 for (i = 0; i < 6; i++)
321 (void) printf("%2.2x", u.node_addr[i]);
322 (void) printf("\n");
326 * Only called with urandmtx held.
327 * Fills/refills the cache of randomness. We know that our allocations of
328 * randomness are always much less than the total size of the cache.
329 * Tries to use /dev/urandom random number generator - if that fails for some
330 * reason, it retries MAX_RETRY times then sets rcachep to NULL so we no
331 * longer use the cache.
333 static void
334 load_cache()
336 int i, retries = 0;
337 int nbytes = RCACHE_SIZE;
338 char *buf = rcache;
340 while (nbytes > 0) {
341 i = read(fd_urand, buf, nbytes);
342 if ((i < 0) && (errno == EINTR)) {
343 continue;
345 if (i <= 0) {
346 if (retries++ == MAX_RETRY)
347 break;
348 continue;
350 nbytes -= i;
351 buf += i;
352 retries = 0;
354 if (nbytes == 0)
355 rcachep = rcache;
356 else
357 rcachep = NULL;
361 * Fills buf with random numbers - nbytes is the number of bytes
362 * to fill-in. Tries to use cached data from the /dev/urandom random number
363 * generator - if that fails for some reason, it uses srand48(3C)
365 static void
366 fill_random_bytes(uchar_t *buf, int nbytes)
368 int i;
370 if (fd_urand == -1) {
371 (void) mutex_lock(&urandmtx);
372 /* check again now that we have the mutex */
373 if (fd_urand == -1) {
374 if ((fd_urand = open(URANDOM_PATH, O_RDONLY)) >= 0)
375 load_cache();
377 (void) mutex_unlock(&urandmtx);
379 if (fd_urand >= 0 && rcachep != NULL) {
380 int cnt;
382 (void) mutex_lock(&urandmtx);
383 if (rcachep != NULL &&
384 (rcachep + nbytes) >= (rcache + RCACHE_SIZE))
385 load_cache();
387 if (rcachep != NULL) {
388 for (cnt = 0; cnt < nbytes; cnt++)
389 *buf++ = *rcachep++;
390 (void) mutex_unlock(&urandmtx);
391 return;
393 (void) mutex_unlock(&urandmtx);
395 for (i = 0; i < nbytes; i++) {
396 *buf++ = get_random() & 0xFF;
401 * Unpacks the structure members in "struct uuid" to a char string "uuid_t".
403 void
404 struct_to_string(uuid_t ptr, struct uuid *uu)
406 uint_t tmp;
407 uchar_t *out = ptr;
409 tmp = uu->time_low;
410 out[3] = (uchar_t)tmp;
411 tmp >>= 8;
412 out[2] = (uchar_t)tmp;
413 tmp >>= 8;
414 out[1] = (uchar_t)tmp;
415 tmp >>= 8;
416 out[0] = (uchar_t)tmp;
418 tmp = uu->time_mid;
419 out[5] = (uchar_t)tmp;
420 tmp >>= 8;
421 out[4] = (uchar_t)tmp;
423 tmp = uu->time_hi_and_version;
424 out[7] = (uchar_t)tmp;
425 tmp >>= 8;
426 out[6] = (uchar_t)tmp;
428 tmp = uu->clock_seq_hi_and_reserved;
429 out[8] = (uchar_t)tmp;
430 tmp = uu->clock_seq_low;
431 out[9] = (uchar_t)tmp;
433 (void) memcpy(out+10, uu->node_addr, 6);
438 * Packs the values in the "uuid_t" string into "struct uuid".
440 void
441 string_to_struct(struct uuid *uuid, uuid_t in)
443 uchar_t *ptr;
444 uint_t tmp;
446 ptr = in;
448 tmp = *ptr++;
449 tmp = (tmp << 8) | *ptr++;
450 tmp = (tmp << 8) | *ptr++;
451 tmp = (tmp << 8) | *ptr++;
452 uuid->time_low = tmp;
454 tmp = *ptr++;
455 tmp = (tmp << 8) | *ptr++;
456 uuid->time_mid = tmp;
458 tmp = *ptr++;
459 tmp = (tmp << 8) | *ptr++;
460 uuid->time_hi_and_version = tmp;
462 tmp = *ptr++;
463 uuid->clock_seq_hi_and_reserved = tmp;
465 tmp = *ptr++;
466 uuid->clock_seq_low = tmp;
468 (void) memcpy(uuid->node_addr, ptr, 6);
473 * Generates UUID based on DCE Version 4
475 void
476 uuid_generate_random(uuid_t uu)
478 struct uuid uuid;
480 if (uu == NULL)
481 return;
483 (void) memset(uu, 0, sizeof (uuid_t));
484 (void) memset(&uuid, 0, sizeof (struct uuid));
486 fill_random_bytes(uu, sizeof (uuid_t));
487 string_to_struct(&uuid, uu);
489 * This is version 4, so say so in the UUID version field (4 bits)
491 uuid.time_hi_and_version |= (1 << 14);
493 * we don't want the bit 1 to be set also which is for version 1
495 uuid.time_hi_and_version &= VER1_MASK;
498 * The variant for this format is the 2 high bits set to 10,
499 * so here it is
501 uuid.clock_seq_hi_and_reserved |= 0x80;
504 * Set MSB of Ethernet address to 1 to indicate that it was generated
505 * randomly
507 uuid.node_addr[0] |= 0x80;
508 struct_to_string(uu, &uuid);
512 * Generates UUID based on DCE Version 1.
514 void
515 uuid_generate_time(uuid_t uu)
517 struct uuid uuid;
519 if (uu == NULL)
520 return;
522 if (uuid_create(&uuid) < 0) {
523 uuid_generate_random(uu);
524 return;
527 struct_to_string(uu, &uuid);
531 * Creates a new UUID. The uuid will be generated based on high-quality
532 * randomness from /dev/urandom, if available by calling uuid_generate_random.
533 * If it failed to generate UUID then uuid_generate will call
534 * uuid_generate_time.
536 void
537 uuid_generate(uuid_t uu)
539 if (uu == NULL) {
540 return;
542 if (fd_urand == -1) {
543 (void) mutex_lock(&urandmtx);
544 /* check again now that we have the mutex */
545 if (fd_urand == -1) {
546 if ((fd_urand = open(URANDOM_PATH, O_RDONLY)) >= 0)
547 load_cache();
549 (void) mutex_unlock(&urandmtx);
551 if (fd_urand >= 0) {
552 uuid_generate_random(uu);
553 } else {
554 (void) uuid_generate_time(uu);
559 * Copies the UUID variable src to dst.
561 void
562 uuid_copy(uuid_t dst, uuid_t src)
564 (void) memcpy(dst, src, UUID_LEN);
568 * Sets the value of the supplied uuid variable uu, to the NULL value.
570 void
571 uuid_clear(uuid_t uu)
573 (void) memset(uu, 0, UUID_LEN);
577 * This function converts the supplied UUID uu from the internal
578 * binary format into a 36-byte string (plus trailing null char)
579 * and stores this value in the character string pointed to by out.
581 void
582 uuid_unparse(uuid_t uu, char *out)
584 struct uuid uuid;
585 uint16_t clock_seq;
586 char etheraddr[13];
587 int index = 0, i;
589 /* basic sanity checking */
590 if (uu == NULL) {
591 return;
594 /* XXX user should have allocated enough memory */
596 * if (strlen(out) < UUID_PRINTABLE_STRING_LENGTH) {
597 * return;
600 string_to_struct(&uuid, uu);
601 clock_seq = uuid.clock_seq_hi_and_reserved;
602 clock_seq = (clock_seq << 8) | uuid.clock_seq_low;
603 for (i = 0; i < 6; i++) {
604 (void) sprintf(&etheraddr[index++], "%.2x", uuid.node_addr[i]);
605 index++;
607 etheraddr[index] = '\0';
609 (void) snprintf(out, 25, "%08x-%04x-%04x-%04x-",
610 uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, clock_seq);
611 (void) strlcat(out, etheraddr, UUID_PRINTABLE_STRING_LENGTH);
615 * The uuid_is_null function compares the value of the supplied
616 * UUID variable uu to the NULL value. If the value is equal
617 * to the NULL UUID, 1 is returned, otherwise 0 is returned.
620 uuid_is_null(uuid_t uu)
622 int i;
623 uuid_t null_uu;
625 (void) memset(null_uu, 0, sizeof (uuid_t));
626 i = memcmp(uu, null_uu, sizeof (uuid_t));
627 if (i == 0) {
628 /* uu is NULL uuid */
629 return (1);
630 } else {
631 return (0);
636 * uuid_parse converts the UUID string given by 'in' into the
637 * internal uuid_t format. The input UUID is a string of the form
638 * cefa7a9c-1dd2-11b2-8350-880020adbeef in printf(3C) format.
639 * Upon successfully parsing the input string, UUID is stored
640 * in the location pointed to by uu
643 uuid_parse(char *in, uuid_t uu)
646 char *ptr, buf[3];
647 int i;
648 struct uuid uuid;
649 uint16_t clock_seq;
651 /* do some sanity checking */
652 if ((strlen(in) != 36) || (uu == NULL) || (in[36] != '\0')) {
653 return (-1);
656 ptr = in;
657 for (i = 0; i < 36; i++, ptr++) {
658 if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
659 if (*ptr != '-') {
660 return (-1);
662 } else {
663 if (!isxdigit(*ptr)) {
664 return (-1);
669 uuid.time_low = strtoul(in, NULL, 16);
670 uuid.time_mid = strtoul(in+9, NULL, 16);
671 uuid.time_hi_and_version = strtoul(in+14, NULL, 16);
672 clock_seq = strtoul(in+19, NULL, 16);
673 uuid.clock_seq_hi_and_reserved = (clock_seq & 0xFF00) >> 8;
674 uuid.clock_seq_low = (clock_seq & 0xFF);
676 ptr = in+24;
677 buf[2] = '\0';
678 for (i = 0; i < 6; i++) {
679 buf[0] = *ptr++;
680 buf[1] = *ptr++;
681 uuid.node_addr[i] = strtoul(buf, NULL, 16);
683 struct_to_string(uu, &uuid);
684 return (0);
688 * uuid_time extracts the time at which the supplied UUID uu
689 * was created. This function can only extract the creation
690 * time for UUIDs created with the uuid_generate_time function.
691 * The time at which the UUID was created, in seconds and
692 * microseconds since the epoch is stored in the location
693 * pointed to by ret_tv.
695 time_t
696 uuid_time(uuid_t uu, struct timeval *ret_tv)
698 struct uuid uuid;
699 uint_t high;
700 struct timeval tv;
701 u_longlong_t clock_reg;
702 uint_t tmp;
703 uint8_t clk;
705 string_to_struct(&uuid, uu);
706 tmp = (uuid.time_hi_and_version & 0xF000) >> 12;
707 clk = uuid.clock_seq_hi_and_reserved;
709 /* check if uu is NULL, Version = 1 of DCE and Variant = 0b10x */
710 if ((uu == NULL) || ((tmp & 0x01) != 0x01) || ((clk & 0x80) != 0x80)) {
711 return (-1);
713 high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
714 clock_reg = uuid.time_low | ((u_longlong_t)high << 32);
716 clock_reg -= (((u_longlong_t)0x01B21DD2) << 32) + 0x13814000;
717 tv.tv_sec = clock_reg / 10000000;
718 tv.tv_usec = (clock_reg % 10000000) / 10;
720 if (ret_tv) {
721 *ret_tv = tv;
724 return (tv.tv_sec);