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 buffer_init; 75 static int file_type; 76 static int fd; 77 78 /* 79 * misc routines 80 */ 81 uint16_t get_random(void); 82 void get_current_time(uuid_time_t *); 83 84 void struct_to_string(uuid_t, struct uuid *); 85 void string_to_struct(struct uuid *, uuid_t); 86 int get_ethernet_address(uuid_node_t *); 87 88 /* 89 * local functions 90 */ 91 static int map_state(); 92 static void format_uuid(struct uuid *, uint16_t, uuid_time_t, 93 uuid_node_t); 94 static void fill_random_bytes(uchar_t *, int); 95 static int uuid_create(struct uuid *); 96 static void gen_ethernet_address(uuid_node_t *); 97 static void revalidate_data(uuid_node_t *); 98 99 /* 100 * Generates a uuid based on version 1 format. 101 * Returns 0 on success and -1 on failure. 102 */ 103 static int 104 uuid_create(struct uuid *uuid) 105 { 106 uuid_time_t timestamp; 107 uuid_node_t system_node; 108 int ret, non_unique = 0; 109 110 /* 111 * Get the system MAC address and/or cache it 112 */ 113 if (node_init) { 114 bcopy(&node_id_cache, &system_node, sizeof (uuid_node_t)); 115 } else { 116 gen_ethernet_address(&system_node); 117 bcopy(&system_node, &node_id_cache, sizeof (uuid_node_t)); 118 node_init = 1; 119 } 120 121 /* 122 * Access the state file, mmap it and initialize the shared lock. 123 * file_type tells us whether we had access to the state file or 124 * created a temporary one. 125 */ 126 buffer_init = map_state(); 127 128 if (!buffer_init) { 129 return (buffer_init); 130 } 131 132 /* 133 * Acquire the lock 134 */ 135 for (;;) { 136 if ((ret = mutex_lock(&data->lock)) == 0) 137 break; 138 else 139 switch (ret) { 140 case EOWNERDEAD: 141 revalidate_data(&system_node); 142 (void) mutex_consistent(&data->lock); 143 (void) mutex_unlock(&data->lock); 144 break; 145 case ENOTRECOVERABLE: 146 return (ret); 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(×tamp); 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(ðeraddr[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