xref: /illumos-gate/usr/src/lib/libuuid/common/uuid.c (revision 84615402a46a91be66843bd64e4fb72642b06e9d)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
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.
26  */
27 
28 /*
29  * The copyright in this file is taken from the original Leach & Salz
30  * UUID specification, from which this implementation is derived.
31  */
32 
33 /*
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.
49  */
50 
51 /*
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.
56  */
57 
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"
70 
71 shared_buffer_t		*data;
72 
73 static	uuid_node_t	node_id_cache;
74 static	int		node_init;
75 static	int		file_type;
76 static	int		fd;
77 
78 /*
79  * The urandmtx mutex prevents multiple opens of /dev/urandom and protects the
80  * cache.
81  */
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;
87 
88 /*
89  * misc routines
90  */
91 uint16_t		get_random(void);
92 void			get_current_time(uuid_time_t *);
93 
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 *);
97 
98 /*
99  * local functions
100  */
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 *);
108 
109 /*
110  * Generates a uuid based on version 1 format.
111  * Returns 0 on success and -1 on failure.
112  */
113 static int
114 uuid_create(struct uuid *uuid)
115 {
116 	uuid_time_t	timestamp;
117 	uuid_node_t	system_node;
118 	int		ret, non_unique = 0;
119 
120 	/*
121 	 * Get the system MAC address and/or cache it
122 	 */
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;
129 	}
130 
131 	/*
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.
135 	 */
136 	if (map_state() == -1)
137 		return (-1);
138 
139 	/*
140 	 * Acquire the lock
141 	 */
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);
154 			}
155 	}
156 
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++;
161 	}
162 
163 	if (memcmp(&system_node, &data->state.node, sizeof (uuid_node_t)) != 0)
164 		data->state.clock++;
165 
166 	get_current_time(&timestamp);
167 
168 	/*
169 	 * If timestamp is not set or is not in the past, bump
170 	 * data->state.clock
171 	 */
172 	if ((data->state.ts == 0) || (data->state.ts >= timestamp)) {
173 		data->state.clock++;
174 		data->state.ts = timestamp;
175 	}
176 
177 	if (non_unique)
178 		system_node.nodeID[0] |= 0x80;
179 
180 	/* Stuff fields into the UUID struct */
181 	format_uuid(uuid, data->state.clock, timestamp, system_node);
182 
183 	(void) mutex_unlock(&data->lock);
184 
185 	return (0);
186 }
187 
188 /*
189  * Fills system_node with Ethernet address if available,
190  * else fills random numbers
191  */
192 static void
193 gen_ethernet_address(uuid_node_t *system_node)
194 {
195 	uchar_t		node[6];
196 
197 	if (get_ethernet_address(system_node) != 0) {
198 		fill_random_bytes(node, 6);
199 		(void) memcpy(system_node->nodeID, node, 6);
200 		/*
201 		 * use 8:0:20 with the multicast bit set
202 		 * to avoid namespace collisions.
203 		 */
204 		system_node->nodeID[0] = 0x88;
205 		system_node->nodeID[1] = 0x00;
206 		system_node->nodeID[2] = 0x20;
207 	}
208 }
209 
210 /*
211  * Formats a UUID, given the clock_seq timestamp, and node address.
212  * Fills in passed-in pointer with the resulting uuid.
213  */
214 static void
215 format_uuid(struct uuid *uuid, uint16_t clock_seq,
216     uuid_time_t timestamp, uuid_node_t node)
217 {
218 
219 	/*
220 	 * First set up the first 60 bits from the timestamp
221 	 */
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);
225 
226 	/*
227 	 * This is version 1, so say so in the UUID version field (4 bits)
228 	 */
229 	uuid->time_hi_and_version |= (1 << 12);
230 
231 	/*
232 	 * Now do the clock sequence
233 	 */
234 	uuid->clock_seq_low = clock_seq & 0xFF;
235 
236 	/*
237 	 * We must save the most-significant 2 bits for the reserved field
238 	 */
239 	uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8;
240 
241 	/*
242 	 * The variant for this format is the 2 high bits set to 10,
243 	 * so here it is
244 	 */
245 	uuid->clock_seq_hi_and_reserved |= 0x80;
246 
247 	/*
248 	 * write result to passed-in pointer
249 	 */
250 	(void) memcpy(&uuid->node_addr, &node, sizeof (uuid->node_addr));
251 }
252 
253 /*
254  * Opens/creates the state file, falling back to a tmp
255  */
256 static int
257 map_state()
258 {
259 	FILE	*tmp;
260 
261 	/* If file's mapped, return */
262 	if (file_type != 0)
263 		return (1);
264 
265 	if ((fd = open(STATE_LOCATION, O_RDWR)) < 0) {
266 		file_type = TEMP_FILE;
267 
268 		if ((tmp = tmpfile()) == NULL)
269 			return (-1);
270 		else
271 			fd = fileno(tmp);
272 	} else {
273 		file_type = STATE_FILE;
274 	}
275 
276 	(void) ftruncate(fd, (off_t)sizeof (shared_buffer_t));
277 
278 	/* LINTED - alignment */
279 	data = (shared_buffer_t *)mmap(NULL, sizeof (shared_buffer_t),
280 	    PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
281 
282 	if (data == MAP_FAILED)
283 		return (-1);
284 
285 	(void) mutex_init(&data->lock, USYNC_PROCESS|LOCK_ROBUST, 0);
286 
287 	(void) close(fd);
288 
289 	return (1);
290 }
291 
292 static void
293 revalidate_data(uuid_node_t *node)
294 {
295 	int i;
296 
297 	data->state.ts = 0;
298 
299 	for (i = 0; i < sizeof (data->state.node.nodeID); i++)
300 		data->state.node.nodeID[i] = 0;
301 
302 	data->state.clock = 0;
303 
304 	gen_ethernet_address(node);
305 	bcopy(node, &node_id_cache, sizeof (uuid_node_t));
306 	node_init = 1;
307 }
308 
309 /*
310  * Prints a nicely-formatted uuid to stdout.
311  */
312 void
313 uuid_print(struct uuid u)
314 {
315 	int i;
316 
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");
323 }
324 
325 /*
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.
332  */
333 static void
334 load_cache()
335 {
336 	int i, retries = 0;
337 	int nbytes = RCACHE_SIZE;
338 	char *buf = rcache;
339 
340 	while (nbytes > 0) {
341 		i = read(fd_urand, buf, nbytes);
342 		if ((i < 0) && (errno == EINTR)) {
343 			continue;
344 		}
345 		if (i <= 0) {
346 			if (retries++ == MAX_RETRY)
347 				break;
348 			continue;
349 		}
350 		nbytes -= i;
351 		buf += i;
352 		retries = 0;
353 	}
354 	if (nbytes == 0)
355 		rcachep = rcache;
356 	else
357 		rcachep = NULL;
358 }
359 
360 /*
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)
364  */
365 static void
366 fill_random_bytes(uchar_t *buf, int nbytes)
367 {
368 	int i;
369 
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();
376 		}
377 		(void) mutex_unlock(&urandmtx);
378 	}
379 	if (fd_urand >= 0 && rcachep != NULL) {
380 		int cnt;
381 
382 		(void) mutex_lock(&urandmtx);
383 		if (rcachep != NULL &&
384 		    (rcachep + nbytes) >= (rcache + RCACHE_SIZE))
385 			load_cache();
386 
387 		if (rcachep != NULL) {
388 			for (cnt = 0; cnt < nbytes; cnt++)
389 				*buf++ = *rcachep++;
390 			(void) mutex_unlock(&urandmtx);
391 			return;
392 		}
393 		(void) mutex_unlock(&urandmtx);
394 	}
395 	for (i = 0; i < nbytes; i++) {
396 		*buf++ = get_random() & 0xFF;
397 	}
398 }
399 
400 /*
401  * Unpacks the structure members in "struct uuid" to a char string "uuid_t".
402  */
403 void
404 struct_to_string(uuid_t ptr, struct uuid *uu)
405 {
406 	uint_t		tmp;
407 	uchar_t		*out = ptr;
408 
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;
417 
418 	tmp = uu->time_mid;
419 	out[5] = (uchar_t)tmp;
420 	tmp >>= 8;
421 	out[4] = (uchar_t)tmp;
422 
423 	tmp = uu->time_hi_and_version;
424 	out[7] = (uchar_t)tmp;
425 	tmp >>= 8;
426 	out[6] = (uchar_t)tmp;
427 
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;
432 
433 	(void) memcpy(out+10, uu->node_addr, 6);
434 
435 }
436 
437 /*
438  * Packs the values in the "uuid_t" string into "struct uuid".
439  */
440 void
441 string_to_struct(struct uuid *uuid, uuid_t in)
442 {
443 	uchar_t	*ptr;
444 	uint_t	tmp;
445 
446 	ptr = in;
447 
448 	tmp = *ptr++;
449 	tmp = (tmp << 8) | *ptr++;
450 	tmp = (tmp << 8) | *ptr++;
451 	tmp = (tmp << 8) | *ptr++;
452 	uuid->time_low = tmp;
453 
454 	tmp = *ptr++;
455 	tmp = (tmp << 8) | *ptr++;
456 	uuid->time_mid = tmp;
457 
458 	tmp = *ptr++;
459 	tmp = (tmp << 8) | *ptr++;
460 	uuid->time_hi_and_version = tmp;
461 
462 	tmp = *ptr++;
463 	uuid->clock_seq_hi_and_reserved = tmp;
464 
465 	tmp = *ptr++;
466 	uuid->clock_seq_low = tmp;
467 
468 	(void) memcpy(uuid->node_addr, ptr, 6);
469 
470 }
471 
472 /*
473  * Generates UUID based on DCE Version 4
474  */
475 void
476 uuid_generate_random(uuid_t uu)
477 {
478 	struct uuid	uuid;
479 
480 	if (uu == NULL)
481 		return;
482 
483 	(void) memset(uu, 0, sizeof (uuid_t));
484 	(void) memset(&uuid, 0, sizeof (struct uuid));
485 
486 	fill_random_bytes(uu, sizeof (uuid_t));
487 	string_to_struct(&uuid, uu);
488 	/*
489 	 * This is version 4, so say so in the UUID version field (4 bits)
490 	 */
491 	uuid.time_hi_and_version |= (1 << 14);
492 	/*
493 	 * we don't want the bit 1 to be set also which is for version 1
494 	 */
495 	uuid.time_hi_and_version &= VER1_MASK;
496 
497 	/*
498 	 * The variant for this format is the 2 high bits set to 10,
499 	 * so here it is
500 	 */
501 	uuid.clock_seq_hi_and_reserved |= 0x80;
502 
503 	/*
504 	 * Set MSB of Ethernet address to 1 to indicate that it was generated
505 	 * randomly
506 	 */
507 	uuid.node_addr[0] |= 0x80;
508 	struct_to_string(uu, &uuid);
509 }
510 
511 /*
512  * Generates UUID based on DCE Version 1.
513  */
514 void
515 uuid_generate_time(uuid_t uu)
516 {
517 	struct 	uuid uuid;
518 
519 	if (uu == NULL)
520 		return;
521 
522 	if (uuid_create(&uuid) < 0) {
523 		uuid_generate_random(uu);
524 		return;
525 	}
526 
527 	struct_to_string(uu, &uuid);
528 }
529 
530 /*
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.
535  */
536 void
537 uuid_generate(uuid_t uu)
538 {
539 	if (uu == NULL) {
540 		return;
541 	}
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();
548 		}
549 		(void) mutex_unlock(&urandmtx);
550 	}
551 	if (fd_urand >= 0) {
552 		uuid_generate_random(uu);
553 	} else {
554 		(void) uuid_generate_time(uu);
555 	}
556 }
557 
558 /*
559  * Copies the UUID variable src to dst.
560  */
561 void
562 uuid_copy(uuid_t dst, uuid_t src)
563 {
564 	(void) memcpy(dst, src, UUID_LEN);
565 }
566 
567 /*
568  * Sets the value of the supplied uuid variable uu, to the NULL value.
569  */
570 void
571 uuid_clear(uuid_t uu)
572 {
573 	(void) memset(uu, 0, UUID_LEN);
574 }
575 
576 /*
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.
580  */
581 void
582 uuid_unparse(uuid_t uu, char *out)
583 {
584 	struct uuid 	uuid;
585 	uint16_t	clock_seq;
586 	char		etheraddr[13];
587 	int		index = 0, i;
588 
589 	/* basic sanity checking */
590 	if (uu == NULL) {
591 		return;
592 	}
593 
594 	/* XXX user should have allocated enough memory */
595 	/*
596 	 * if (strlen(out) < UUID_PRINTABLE_STRING_LENGTH) {
597 	 * return;
598 	 * }
599 	 */
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++;
606 	}
607 	etheraddr[index] = '\0';
608 
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);
612 }
613 
614 /*
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.
618  */
619 int
620 uuid_is_null(uuid_t uu)
621 {
622 	int		i;
623 	uuid_t		null_uu;
624 
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);
632 	}
633 }
634 
635 /*
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
641  */
642 int
643 uuid_parse(char *in, uuid_t uu)
644 {
645 
646 	char		*ptr, buf[3];
647 	int		i;
648 	struct uuid	uuid;
649 	uint16_t	clock_seq;
650 
651 	/* do some sanity checking */
652 	if ((strlen(in) != 36) || (uu == NULL) || (in[36] != '\0')) {
653 		return (-1);
654 	}
655 
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);
661 			}
662 		} else {
663 			if (!isxdigit(*ptr)) {
664 				return (-1);
665 			}
666 		}
667 	}
668 
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);
675 
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);
682 	}
683 	struct_to_string(uu, &uuid);
684 	return (0);
685 }
686 
687 /*
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.
694  */
695 time_t
696 uuid_time(uuid_t uu, struct timeval *ret_tv)
697 {
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;
704 
705 	string_to_struct(&uuid, uu);
706 	tmp = (uuid.time_hi_and_version & 0xF000) >> 12;
707 	clk = uuid.clock_seq_hi_and_reserved;
708 
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);
712 	}
713 	high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
714 	clock_reg = uuid.time_low | ((u_longlong_t)high << 32);
715 
716 	clock_reg -= (((u_longlong_t)0x01B21DD2) << 32) + 0x13814000;
717 	tv.tv_sec = clock_reg / 10000000;
718 	tv.tv_usec = (clock_reg % 10000000) / 10;
719 
720 	if (ret_tv) {
721 		*ret_tv = tv;
722 	}
723 
724 	return (tv.tv_sec);
725 }
726