xref: /illumos-gate/usr/src/lib/libuuid/common/uuid.c (revision ad2de4358b2074634b0f2355c34b0986da0e95f9)
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  */
26 
27 /*
28  * The copyright in this file is taken from the original Leach & Salz
29  * UUID specification, from which this implementation is derived.
30  */
31 
32 /*
33  * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
34  * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
35  * Digital Equipment Corporation, Maynard, Mass.  Copyright (c) 1998
36  * Microsoft.  To anyone who acknowledges that this file is provided
37  * "AS IS" without any express or implied warranty: permission to use,
38  * copy, modify, and distribute this file for any purpose is hereby
39  * granted without fee, provided that the above copyright notices and
40  * this notice appears in all source code copies, and that none of the
41  * names of Open Software Foundation, Inc., Hewlett-Packard Company,
42  * or Digital Equipment Corporation be used in advertising or
43  * publicity pertaining to distribution of the software without
44  * specific, written prior permission.  Neither Open Software
45  * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
46  * Equipment Corporation makes any representations about the
47  * suitability of this software for any purpose.
48  */
49 
50 /*
51  * This module is the workhorse for generating abstract
52  * UUIDs.  It delegates system-specific tasks (such
53  * as obtaining the node identifier or system time)
54  * to the sysdep module.
55  */
56 
57 #include <ctype.h>
58 #include <sys/param.h>
59 #include <sys/stat.h>
60 #include <errno.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <strings.h>
64 #include <fcntl.h>
65 #include <unistd.h>
66 #include <synch.h>
67 #include <sys/mman.h>
68 #include "uuid_misc.h"
69 
70 shared_buffer_t		*data;
71 
72 static	uuid_node_t	node_id_cache;
73 static	int		node_init;
74 static	int		file_type;
75 static	int		fd;
76 
77 /*
78  * misc routines
79  */
80 uint16_t		get_random(void);
81 void			get_current_time(uuid_time_t *);
82 
83 void			struct_to_string(uuid_t, struct uuid *);
84 void			string_to_struct(struct uuid *, uuid_t);
85 int			get_ethernet_address(uuid_node_t *);
86 
87 /*
88  * local functions
89  */
90 static	int		map_state();
91 static	void 		format_uuid(struct uuid *, uint16_t, uuid_time_t,
92     uuid_node_t);
93 static	void		fill_random_bytes(uchar_t *, int);
94 static	int		uuid_create(struct uuid *);
95 static	void		gen_ethernet_address(uuid_node_t *);
96 static	void		revalidate_data(uuid_node_t *);
97 
98 /*
99  * Generates a uuid based on version 1 format.
100  * Returns 0 on success and -1 on failure.
101  */
102 static int
103 uuid_create(struct uuid *uuid)
104 {
105 	uuid_time_t	timestamp;
106 	uuid_node_t	system_node;
107 	int		ret, non_unique = 0;
108 
109 	/*
110 	 * Get the system MAC address and/or cache it
111 	 */
112 	if (node_init) {
113 		bcopy(&node_id_cache, &system_node, sizeof (uuid_node_t));
114 	} else {
115 		gen_ethernet_address(&system_node);
116 		bcopy(&system_node, &node_id_cache, sizeof (uuid_node_t));
117 		node_init = 1;
118 	}
119 
120 	/*
121 	 * Access the state file, mmap it and initialize the shared lock.
122 	 * file_type tells us whether we had access to the state file or
123 	 * created a temporary one.
124 	 */
125 	if (map_state() == -1)
126 		return (-1);
127 
128 	/*
129 	 * Acquire the lock
130 	 */
131 	for (;;) {
132 		if ((ret = mutex_lock(&data->lock)) == 0)
133 			break;
134 		else
135 			switch (ret) {
136 				case EOWNERDEAD:
137 					revalidate_data(&system_node);
138 					(void) mutex_consistent(&data->lock);
139 					(void) mutex_unlock(&data->lock);
140 					break;
141 				case ENOTRECOVERABLE:
142 					return (ret);
143 			}
144 	}
145 
146 	/* State file is either new or is temporary, get a random clock seq */
147 	if (data->state.clock == 0) {
148 		data->state.clock = get_random();
149 		non_unique++;
150 	}
151 
152 	if (memcmp(&system_node, &data->state.node, sizeof (uuid_node_t)) != 0)
153 		data->state.clock++;
154 
155 	get_current_time(&timestamp);
156 
157 	/*
158 	 * If timestamp is not set or is not in the past, bump
159 	 * data->state.clock
160 	 */
161 	if ((data->state.ts == 0) || (data->state.ts >= timestamp)) {
162 		data->state.clock++;
163 		data->state.ts = timestamp;
164 	}
165 
166 	if (non_unique)
167 		system_node.nodeID[0] |= 0x80;
168 
169 	/* Stuff fields into the UUID struct */
170 	format_uuid(uuid, data->state.clock, timestamp, system_node);
171 
172 	(void) mutex_unlock(&data->lock);
173 
174 	return (0);
175 }
176 
177 /*
178  * Fills system_node with Ethernet address if available,
179  * else fills random numbers
180  */
181 static void
182 gen_ethernet_address(uuid_node_t *system_node)
183 {
184 	uchar_t		node[6];
185 
186 	if (get_ethernet_address(system_node) != 0) {
187 		fill_random_bytes(node, 6);
188 		(void) memcpy(system_node->nodeID, node, 6);
189 		/*
190 		 * use 8:0:20 with the multicast bit set
191 		 * to avoid namespace collisions.
192 		 */
193 		system_node->nodeID[0] = 0x88;
194 		system_node->nodeID[1] = 0x00;
195 		system_node->nodeID[2] = 0x20;
196 	}
197 }
198 
199 /*
200  * Formats a UUID, given the clock_seq timestamp, and node address.
201  * Fills in passed-in pointer with the resulting uuid.
202  */
203 static void
204 format_uuid(struct uuid *uuid, uint16_t clock_seq,
205     uuid_time_t timestamp, uuid_node_t node)
206 {
207 
208 	/*
209 	 * First set up the first 60 bits from the timestamp
210 	 */
211 	uuid->time_low = (uint32_t)(timestamp & 0xFFFFFFFF);
212 	uuid->time_mid = (uint16_t)((timestamp >> 32) & 0xFFFF);
213 	uuid->time_hi_and_version = (uint16_t)((timestamp >> 48) & 0x0FFF);
214 
215 	/*
216 	 * This is version 1, so say so in the UUID version field (4 bits)
217 	 */
218 	uuid->time_hi_and_version |= (1 << 12);
219 
220 	/*
221 	 * Now do the clock sequence
222 	 */
223 	uuid->clock_seq_low = clock_seq & 0xFF;
224 
225 	/*
226 	 * We must save the most-significant 2 bits for the reserved field
227 	 */
228 	uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8;
229 
230 	/*
231 	 * The variant for this format is the 2 high bits set to 10,
232 	 * so here it is
233 	 */
234 	uuid->clock_seq_hi_and_reserved |= 0x80;
235 
236 	/*
237 	 * write result to passed-in pointer
238 	 */
239 	(void) memcpy(&uuid->node_addr, &node, sizeof (uuid->node_addr));
240 }
241 
242 /*
243  * Opens/creates the state file, falling back to a tmp
244  */
245 static int
246 map_state()
247 {
248 	FILE	*tmp;
249 
250 	/* If file's mapped, return */
251 	if (file_type != 0)
252 		return (1);
253 
254 	if ((fd = open(STATE_LOCATION, O_RDWR)) < 0) {
255 		file_type = TEMP_FILE;
256 
257 		if ((tmp = tmpfile()) == NULL)
258 			return (-1);
259 		else
260 			fd = fileno(tmp);
261 	} else {
262 		file_type = STATE_FILE;
263 	}
264 
265 	(void) ftruncate(fd, (off_t)sizeof (shared_buffer_t));
266 
267 	/* LINTED - alignment */
268 	data = (shared_buffer_t *)mmap(NULL, sizeof (shared_buffer_t),
269 	    PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
270 
271 	if (data == MAP_FAILED)
272 		return (-1);
273 
274 	(void) mutex_init(&data->lock, USYNC_PROCESS|LOCK_ROBUST, 0);
275 
276 	(void) close(fd);
277 
278 	return (1);
279 }
280 
281 static void
282 revalidate_data(uuid_node_t *node)
283 {
284 	int i;
285 
286 	data->state.ts = 0;
287 
288 	for (i = 0; i < sizeof (data->state.node.nodeID); i++)
289 		data->state.node.nodeID[i] = 0;
290 
291 	data->state.clock = 0;
292 
293 	gen_ethernet_address(node);
294 	bcopy(node, &node_id_cache, sizeof (uuid_node_t));
295 	node_init = 1;
296 }
297 
298 /*
299  * Prints a nicely-formatted uuid to stdout.
300  */
301 void
302 uuid_print(struct uuid u)
303 {
304 	int i;
305 
306 	(void) printf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", u.time_low, u.time_mid,
307 	    u.time_hi_and_version, u.clock_seq_hi_and_reserved,
308 	    u.clock_seq_low);
309 	for (i = 0; i < 6; i++)
310 		(void) printf("%2.2x", u.node_addr[i]);
311 	(void) printf("\n");
312 }
313 
314 /*
315  * Fills buf with random numbers - nbytes is the number of bytes
316  * to fill-in. Tries to use /dev/urandom random number generator-
317  * if that fails for some reason, it retries MAX_RETRY times. If
318  * it still fails then it uses srand48(3C)
319  */
320 static void
321 fill_random_bytes(uchar_t *buf, int nbytes)
322 {
323 	int i, fd, retries = 0;
324 
325 	fd = open(URANDOM_PATH, O_RDONLY);
326 	if (fd >= 0) {
327 		while (nbytes > 0) {
328 			i = read(fd, buf, nbytes);
329 			if ((i < 0) && (errno == EINTR)) {
330 				continue;
331 			}
332 			if (i <= 0) {
333 				if (retries++ == MAX_RETRY)
334 					break;
335 				continue;
336 			}
337 			nbytes -= i;
338 			buf += i;
339 			retries = 0;
340 		}
341 		if (nbytes == 0) {
342 			(void) close(fd);
343 			return;
344 		}
345 	}
346 	for (i = 0; i < nbytes; i++) {
347 		*buf++ = get_random() & 0xFF;
348 	}
349 	if (fd >= 0) {
350 		(void) close(fd);
351 	}
352 }
353 
354 /*
355  * Unpacks the structure members in "struct uuid" to a char string "uuid_t".
356  */
357 void
358 struct_to_string(uuid_t ptr, struct uuid *uu)
359 {
360 	uint_t		tmp;
361 	uchar_t		*out = ptr;
362 
363 	tmp = uu->time_low;
364 	out[3] = (uchar_t)tmp;
365 	tmp >>= 8;
366 	out[2] = (uchar_t)tmp;
367 	tmp >>= 8;
368 	out[1] = (uchar_t)tmp;
369 	tmp >>= 8;
370 	out[0] = (uchar_t)tmp;
371 
372 	tmp = uu->time_mid;
373 	out[5] = (uchar_t)tmp;
374 	tmp >>= 8;
375 	out[4] = (uchar_t)tmp;
376 
377 	tmp = uu->time_hi_and_version;
378 	out[7] = (uchar_t)tmp;
379 	tmp >>= 8;
380 	out[6] = (uchar_t)tmp;
381 
382 	tmp = uu->clock_seq_hi_and_reserved;
383 	out[8] = (uchar_t)tmp;
384 	tmp = uu->clock_seq_low;
385 	out[9] = (uchar_t)tmp;
386 
387 	(void) memcpy(out+10, uu->node_addr, 6);
388 
389 }
390 
391 /*
392  * Packs the values in the "uuid_t" string into "struct uuid".
393  */
394 void
395 string_to_struct(struct uuid *uuid, uuid_t in)
396 {
397 	uchar_t	*ptr;
398 	uint_t	tmp;
399 
400 	ptr = in;
401 
402 	tmp = *ptr++;
403 	tmp = (tmp << 8) | *ptr++;
404 	tmp = (tmp << 8) | *ptr++;
405 	tmp = (tmp << 8) | *ptr++;
406 	uuid->time_low = tmp;
407 
408 	tmp = *ptr++;
409 	tmp = (tmp << 8) | *ptr++;
410 	uuid->time_mid = tmp;
411 
412 	tmp = *ptr++;
413 	tmp = (tmp << 8) | *ptr++;
414 	uuid->time_hi_and_version = tmp;
415 
416 	tmp = *ptr++;
417 	uuid->clock_seq_hi_and_reserved = tmp;
418 
419 	tmp = *ptr++;
420 	uuid->clock_seq_low = tmp;
421 
422 	(void) memcpy(uuid->node_addr, ptr, 6);
423 
424 }
425 
426 /*
427  * Generates UUID based on DCE Version 4
428  */
429 void
430 uuid_generate_random(uuid_t uu)
431 {
432 	struct uuid	uuid;
433 
434 	if (uu == NULL)
435 		return;
436 
437 	(void) memset(uu, 0, sizeof (uuid_t));
438 	(void) memset(&uuid, 0, sizeof (struct uuid));
439 
440 	fill_random_bytes(uu, sizeof (uuid_t));
441 	string_to_struct(&uuid, uu);
442 	/*
443 	 * This is version 4, so say so in the UUID version field (4 bits)
444 	 */
445 	uuid.time_hi_and_version |= (1 << 14);
446 	/*
447 	 * we don't want the bit 1 to be set also which is for version 1
448 	 */
449 	uuid.time_hi_and_version &= VER1_MASK;
450 
451 	/*
452 	 * The variant for this format is the 2 high bits set to 10,
453 	 * so here it is
454 	 */
455 	uuid.clock_seq_hi_and_reserved |= 0x80;
456 
457 	/*
458 	 * Set MSB of Ethernet address to 1 to indicate that it was generated
459 	 * randomly
460 	 */
461 	uuid.node_addr[0] |= 0x80;
462 	struct_to_string(uu, &uuid);
463 }
464 
465 /*
466  * Generates UUID based on DCE Version 1.
467  */
468 void
469 uuid_generate_time(uuid_t uu)
470 {
471 	struct 	uuid uuid;
472 
473 	if (uu == NULL)
474 		return;
475 
476 	if (uuid_create(&uuid) < 0) {
477 		uuid_generate_random(uu);
478 		return;
479 	}
480 
481 	struct_to_string(uu, &uuid);
482 }
483 
484 /*
485  * Creates a new UUID. The uuid will be generated based on high-quality
486  * randomness from /dev/urandom, if available by calling uuid_generate_random.
487  * If it failed to generate UUID then uuid_generate will call
488  * uuid_generate_time.
489  */
490 void
491 uuid_generate(uuid_t uu)
492 {
493 	int fd;
494 
495 	if (uu == NULL) {
496 		return;
497 	}
498 	fd = open(URANDOM_PATH, O_RDONLY);
499 	if (fd >= 0) {
500 		(void) close(fd);
501 		uuid_generate_random(uu);
502 	} else {
503 		(void) uuid_generate_time(uu);
504 	}
505 }
506 
507 /*
508  * Copies the UUID variable src to dst.
509  */
510 void
511 uuid_copy(uuid_t dst, uuid_t src)
512 {
513 	(void) memcpy(dst, src, UUID_LEN);
514 }
515 
516 /*
517  * Sets the value of the supplied uuid variable uu, to the NULL value.
518  */
519 void
520 uuid_clear(uuid_t uu)
521 {
522 	(void) memset(uu, 0, UUID_LEN);
523 }
524 
525 /*
526  * This function converts the supplied UUID uu from the internal
527  * binary format into a 36-byte string (plus trailing null char)
528  * and stores this value in the character string pointed to by out.
529  */
530 void
531 uuid_unparse(uuid_t uu, char *out)
532 {
533 	struct uuid 	uuid;
534 	uint16_t	clock_seq;
535 	char		etheraddr[13];
536 	int		index = 0, i;
537 
538 	/* basic sanity checking */
539 	if (uu == NULL) {
540 		return;
541 	}
542 
543 	/* XXX user should have allocated enough memory */
544 	/*
545 	 * if (strlen(out) < UUID_PRINTABLE_STRING_LENGTH) {
546 	 * return;
547 	 * }
548 	 */
549 	string_to_struct(&uuid, uu);
550 	clock_seq = uuid.clock_seq_hi_and_reserved;
551 	clock_seq = (clock_seq  << 8) | uuid.clock_seq_low;
552 	for (i = 0; i < 6; i++) {
553 		(void) sprintf(&etheraddr[index++], "%.2x", uuid.node_addr[i]);
554 		index++;
555 	}
556 	etheraddr[index] = '\0';
557 
558 	(void) snprintf(out, 25, "%08x-%04x-%04x-%04x-",
559 	    uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, clock_seq);
560 	(void) strlcat(out, etheraddr, UUID_PRINTABLE_STRING_LENGTH);
561 }
562 
563 /*
564  * The uuid_is_null function compares the value of the supplied
565  * UUID variable uu to the NULL value. If the value is equal
566  * to the NULL UUID, 1 is returned, otherwise 0 is returned.
567  */
568 int
569 uuid_is_null(uuid_t uu)
570 {
571 	int		i;
572 	uuid_t		null_uu;
573 
574 	(void) memset(null_uu, 0, sizeof (uuid_t));
575 	i = memcmp(uu, null_uu, sizeof (uuid_t));
576 	if (i == 0) {
577 		/* uu is NULL uuid */
578 		return (1);
579 	} else {
580 		return (0);
581 	}
582 }
583 
584 /*
585  * uuid_parse converts the UUID string given by 'in' into the
586  * internal uuid_t format. The input UUID is a string of the form
587  * cefa7a9c-1dd2-11b2-8350-880020adbeef in printf(3C) format.
588  * Upon successfully parsing the input string, UUID is stored
589  * in the location pointed to by uu
590  */
591 int
592 uuid_parse(char *in, uuid_t uu)
593 {
594 
595 	char		*ptr, buf[3];
596 	int		i;
597 	struct uuid	uuid;
598 	uint16_t	clock_seq;
599 
600 	/* do some sanity checking */
601 	if ((strlen(in) != 36) || (uu == NULL) || (in[36] != '\0')) {
602 		return (-1);
603 	}
604 
605 	ptr = in;
606 	for (i = 0; i < 36; i++, ptr++) {
607 		if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
608 			if (*ptr != '-') {
609 				return (-1);
610 			}
611 		} else {
612 			if (!isxdigit(*ptr)) {
613 				return (-1);
614 			}
615 		}
616 	}
617 
618 	uuid.time_low = strtoul(in, NULL, 16);
619 	uuid.time_mid = strtoul(in+9, NULL, 16);
620 	uuid.time_hi_and_version = strtoul(in+14, NULL, 16);
621 	clock_seq = strtoul(in+19, NULL, 16);
622 	uuid.clock_seq_hi_and_reserved = (clock_seq & 0xFF00) >> 8;
623 	uuid.clock_seq_low = (clock_seq & 0xFF);
624 
625 	ptr = in+24;
626 	buf[2] = '\0';
627 	for (i = 0; i < 6; i++) {
628 		buf[0] = *ptr++;
629 		buf[1] = *ptr++;
630 		uuid.node_addr[i] = strtoul(buf, NULL, 16);
631 	}
632 	struct_to_string(uu, &uuid);
633 	return (0);
634 }
635 
636 /*
637  * uuid_time extracts the time at which the supplied UUID uu
638  * was created. This function can only extract the creation
639  * time for UUIDs created with the uuid_generate_time function.
640  * The time at which the UUID was created, in seconds and
641  * microseconds since the epoch is stored in the location
642  * pointed to by ret_tv.
643  */
644 time_t
645 uuid_time(uuid_t uu, struct timeval *ret_tv)
646 {
647 	struct uuid	uuid;
648 	uint_t		high;
649 	struct timeval	tv;
650 	u_longlong_t	clock_reg;
651 	uint_t		tmp;
652 	uint8_t		clk;
653 
654 	string_to_struct(&uuid, uu);
655 	tmp = (uuid.time_hi_and_version & 0xF000) >> 12;
656 	clk = uuid.clock_seq_hi_and_reserved;
657 
658 	/* check if uu is NULL, Version = 1 of DCE and Variant = 0b10x */
659 	if ((uu == NULL) || ((tmp & 0x01) != 0x01) || ((clk & 0x80) != 0x80)) {
660 		return (-1);
661 	}
662 	high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
663 	clock_reg = uuid.time_low | ((u_longlong_t)high << 32);
664 
665 	clock_reg -= (((u_longlong_t)0x01B21DD2) << 32) + 0x13814000;
666 	tv.tv_sec = clock_reg / 10000000;
667 	tv.tv_usec = (clock_reg % 10000000) / 10;
668 
669 	if (ret_tv) {
670 		*ret_tv = tv;
671 	}
672 
673 	return (tv.tv_sec);
674 }
675