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