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
uuid_create(struct uuid * uuid)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(×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
gen_ethernet_address(uuid_node_t * system_node)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
format_uuid(struct uuid * uuid,uint16_t clock_seq,uuid_time_t timestamp,uuid_node_t node)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
map_state()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
revalidate_data(uuid_node_t * node)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
uuid_print(struct uuid u)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
fill_random_bytes(uchar_t * buf,int nbytes)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
struct_to_string(uuid_t ptr,struct uuid * uu)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
string_to_struct(struct uuid * uuid,uuid_t in)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
uuid_generate_random(uuid_t uu)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
uuid_generate_time(uuid_t uu)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
uuid_generate(uuid_t uu)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
uuid_copy(uuid_t dst,uuid_t src)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
uuid_clear(uuid_t uu)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
uuid_unparse(uuid_t uu,char * out)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
uuid_is_null(uuid_t uu)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
uuid_parse(char * in,uuid_t uu)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
uuid_time(uuid_t uu,struct timeval * ret_tv)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