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(&timestamp);
 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(&etheraddr[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 }