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(×tamp); 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(ðeraddr[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