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