1 /*
2 ** OSSP uuid - Universally Unique Identifier
3 ** Copyright (c) 2004-2008 Ralf S. Engelschall <rse@engelschall.com>
4 ** Copyright (c) 2004-2008 The OSSP Project <http://www.ossp.org/>
5 **
6 ** This file is part of OSSP uuid, a library for the generation
7 ** of UUIDs which can found at http://www.ossp.org/pkg/lib/uuid/
8 **
9 ** Permission to use, copy, modify, and distribute this software for
10 ** any purpose with or without fee is hereby granted, provided that
11 ** the above copyright notice and this permission notice appear in all
12 ** copies.
13 **
14 ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
15 ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16 ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
18 ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
21 ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
24 ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 ** SUCH DAMAGE.
26 **
27 ** uuid.c: library API implementation
28 */
29
30 /* own headers (part 1/2) */
31 #include "uuid.h"
32 #include "uuid_ac.h"
33
34 /* system headers */
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <ctype.h>
41 #include <fcntl.h>
42 #include <time.h>
43 #include <sys/time.h>
44 #include <sys/types.h>
45
46 /* own headers (part 2/2) */
47 #include "uuid_vers.h"
48 #include "uuid_md5.h"
49 #include "uuid_sha1.h"
50 #include "uuid_prng.h"
51 #include "uuid_mac.h"
52 #include "uuid_time.h"
53 #include "uuid_ui64.h"
54 #include "uuid_ui128.h"
55 #include "uuid_str.h"
56 #include "uuid_bm.h"
57 #include "uuid_ac.h"
58
59 /* maximum number of 100ns ticks of the actual resolution of system clock
60 (which in our case is 1us (= 1000ns) because we use gettimeofday(2) */
61 #define UUIDS_PER_TICK 10
62
63 /* time offset between UUID and Unix Epoch time according to standards.
64 (UUID UTC base time is October 15, 1582
65 Unix UTC base time is January 1, 1970) */
66 #define UUID_TIMEOFFSET "01B21DD213814000"
67
68 /* IEEE 802 MAC address encoding/decoding bit fields */
69 #define IEEE_MAC_MCBIT BM_OCTET(0,0,0,0,0,0,0,1)
70 #define IEEE_MAC_LOBIT BM_OCTET(0,0,0,0,0,0,1,0)
71
72 /* IEEE 802 MAC address octet length */
73 #define IEEE_MAC_OCTETS 6
74
75 /* UUID binary representation according to UUID standards */
76 typedef struct {
77 uuid_uint32_t time_low; /* bits 0-31 of time field */
78 uuid_uint16_t time_mid; /* bits 32-47 of time field */
79 uuid_uint16_t time_hi_and_version; /* bits 48-59 of time field plus 4 bit version */
80 uuid_uint8_t clock_seq_hi_and_reserved; /* bits 8-13 of clock sequence field plus 2 bit variant */
81 uuid_uint8_t clock_seq_low; /* bits 0-7 of clock sequence field */
82 uuid_uint8_t node[IEEE_MAC_OCTETS]; /* bits 0-47 of node MAC address */
83 } uuid_obj_t;
84
85 /* abstract data type (ADT) of API */
86 struct uuid_st {
87 uuid_obj_t obj; /* inlined UUID object */
88 prng_t *prng; /* RPNG sub-object */
89 md5_t *md5; /* MD5 sub-object */
90 sha1_t *sha1; /* SHA-1 sub-object */
91 uuid_uint8_t mac[IEEE_MAC_OCTETS]; /* pre-determined MAC address */
92 struct timeval time_last; /* last retrieved timestamp */
93 unsigned long time_seq; /* last timestamp sequence counter */
94 };
95
96 /* create UUID object */
uuid_create(uuid_t ** uuid)97 uuid_rc_t uuid_create(uuid_t **uuid)
98 {
99 uuid_t *obj;
100
101 /* argument sanity check */
102 if (uuid == NULL)
103 return UUID_RC_ARG;
104
105 /* allocate UUID object */
106 if ((obj = (uuid_t *)malloc(sizeof(uuid_t))) == NULL)
107 return UUID_RC_MEM;
108
109 /* create PRNG, MD5 and SHA1 sub-objects */
110 if (prng_create(&obj->prng) != PRNG_RC_OK) {
111 free(obj);
112 return UUID_RC_INT;
113 }
114 if (md5_create(&obj->md5) != MD5_RC_OK) {
115 (void)prng_destroy(obj->prng);
116 free(obj);
117 return UUID_RC_INT;
118 }
119 if (sha1_create(&obj->sha1) != SHA1_RC_OK) {
120 (void)md5_destroy(obj->md5);
121 (void)prng_destroy(obj->prng);
122 free(obj);
123 return UUID_RC_INT;
124 }
125
126 /* set UUID object initially to "Nil UUID" */
127 if (uuid_load(obj, "nil") != UUID_RC_OK) {
128 (void)sha1_destroy(obj->sha1);
129 (void)md5_destroy(obj->md5);
130 (void)prng_destroy(obj->prng);
131 free(obj);
132 return UUID_RC_INT;
133 }
134
135 /* resolve MAC address for insertion into node field of UUIDs */
136 if (!mac_address((unsigned char *)(obj->mac), sizeof(obj->mac))) {
137 memset(obj->mac, 0, sizeof(obj->mac));
138 obj->mac[0] = BM_OCTET(1,0,0,0,0,0,0,0);
139 }
140
141 /* initialize time attributes */
142 obj->time_last.tv_sec = 0;
143 obj->time_last.tv_usec = 0;
144 obj->time_seq = 0;
145
146 /* store result object */
147 *uuid = obj;
148
149 return UUID_RC_OK;
150 }
151
152 /* destroy UUID object */
uuid_destroy(uuid_t * uuid)153 uuid_rc_t uuid_destroy(uuid_t *uuid)
154 {
155 /* argument sanity check */
156 if (uuid == NULL)
157 return UUID_RC_ARG;
158
159 /* destroy PRNG, MD5 and SHA-1 sub-objects */
160 (void)prng_destroy(uuid->prng);
161 (void)md5_destroy(uuid->md5);
162 (void)sha1_destroy(uuid->sha1);
163
164 /* free UUID object */
165 free(uuid);
166
167 return UUID_RC_OK;
168 }
169
170 /* clone UUID object */
uuid_clone(const uuid_t * uuid,uuid_t ** clone)171 uuid_rc_t uuid_clone(const uuid_t *uuid, uuid_t **clone)
172 {
173 uuid_t *obj;
174
175 /* argument sanity check */
176 if (uuid == NULL || uuid_clone == NULL)
177 return UUID_RC_ARG;
178
179 /* allocate UUID object */
180 if ((obj = (uuid_t *)malloc(sizeof(uuid_t))) == NULL)
181 return UUID_RC_MEM;
182
183 /* clone entire internal state */
184 memcpy(obj, uuid, sizeof(uuid_t));
185
186 /* re-initialize with new PRNG, MD5 and SHA1 sub-objects */
187 if (prng_create(&obj->prng) != PRNG_RC_OK) {
188 free(obj);
189 return UUID_RC_INT;
190 }
191 if (md5_create(&obj->md5) != MD5_RC_OK) {
192 (void)prng_destroy(obj->prng);
193 free(obj);
194 return UUID_RC_INT;
195 }
196 if (sha1_create(&obj->sha1) != SHA1_RC_OK) {
197 (void)md5_destroy(obj->md5);
198 (void)prng_destroy(obj->prng);
199 free(obj);
200 return UUID_RC_INT;
201 }
202
203 /* store result object */
204 *clone = obj;
205
206 return UUID_RC_OK;
207 }
208
209 /* check whether UUID object represents "Nil UUID" */
uuid_isnil(const uuid_t * uuid,int * result)210 uuid_rc_t uuid_isnil(const uuid_t *uuid, int *result)
211 {
212 const unsigned char *ucp;
213 int i;
214
215 /* sanity check argument(s) */
216 if (uuid == NULL || result == NULL)
217 return UUID_RC_ARG;
218
219 /* a "Nil UUID" is defined as all octets zero, so check for this case */
220 *result = UUID_TRUE;
221 for (i = 0, ucp = (unsigned char *)&(uuid->obj); i < UUID_LEN_BIN; i++) {
222 if (*ucp++ != (unsigned char)'\0') {
223 *result = UUID_FALSE;
224 break;
225 }
226 }
227
228 return UUID_RC_OK;
229 }
230
231 /* compare UUID objects */
uuid_compare(const uuid_t * uuid1,const uuid_t * uuid2,int * result)232 uuid_rc_t uuid_compare(const uuid_t *uuid1, const uuid_t *uuid2, int *result)
233 {
234 int r;
235
236 /* argument sanity check */
237 if (result == NULL)
238 return UUID_RC_ARG;
239
240 /* convenience macro for setting result */
241 #define RESULT(r) \
242 /*lint -save -e801 -e717*/ \
243 do { \
244 *result = (r); \
245 goto result_exit; \
246 } while (0) \
247 /*lint -restore*/
248
249 /* special cases: NULL or equal UUIDs */
250 if (uuid1 == uuid2)
251 RESULT(0);
252 if (uuid1 == NULL && uuid2 == NULL)
253 RESULT(0);
254 if (uuid1 == NULL)
255 RESULT((uuid_isnil(uuid2, &r) == UUID_RC_OK ? r : 0) ? 0 : -1);
256 if (uuid2 == NULL)
257 RESULT((uuid_isnil(uuid1, &r) == UUID_RC_OK ? r : 0) ? 0 : 1);
258
259 /* standard cases: regular different UUIDs */
260 if (uuid1->obj.time_low != uuid2->obj.time_low)
261 RESULT((uuid1->obj.time_low < uuid2->obj.time_low) ? -1 : 1);
262 if ((r = (int)uuid1->obj.time_mid
263 - (int)uuid2->obj.time_mid) != 0)
264 RESULT((r < 0) ? -1 : 1);
265 if ((r = (int)uuid1->obj.time_hi_and_version
266 - (int)uuid2->obj.time_hi_and_version) != 0)
267 RESULT((r < 0) ? -1 : 1);
268 if ((r = (int)uuid1->obj.clock_seq_hi_and_reserved
269 - (int)uuid2->obj.clock_seq_hi_and_reserved) != 0)
270 RESULT((r < 0) ? -1 : 1);
271 if ((r = (int)uuid1->obj.clock_seq_low
272 - (int)uuid2->obj.clock_seq_low) != 0)
273 RESULT((r < 0) ? -1 : 1);
274 if ((r = memcmp(uuid1->obj.node, uuid2->obj.node, sizeof(uuid1->obj.node))) != 0)
275 RESULT((r < 0) ? -1 : 1);
276
277 /* default case: the keys are equal */
278 *result = 0;
279
280 result_exit:
281 return UUID_RC_OK;
282 }
283
284 /* INTERNAL: unpack UUID binary presentation into UUID object
285 (allows in-place operation for internal efficiency!) */
uuid_import_bin(uuid_t * uuid,const void * data_ptr,size_t data_len)286 static uuid_rc_t uuid_import_bin(uuid_t *uuid, const void *data_ptr, size_t data_len)
287 {
288 const uuid_uint8_t *in;
289 uuid_uint32_t tmp32;
290 uuid_uint16_t tmp16;
291 unsigned int i;
292
293 /* sanity check argument(s) */
294 if (uuid == NULL || data_ptr == NULL || data_len < UUID_LEN_BIN)
295 return UUID_RC_ARG;
296
297 /* treat input data buffer as octet stream */
298 in = (const uuid_uint8_t *)data_ptr;
299
300 /* unpack "time_low" field */
301 tmp32 = (uuid_uint32_t)(*in++);
302 tmp32 = (tmp32 << 8) | (uuid_uint32_t)(*in++);
303 tmp32 = (tmp32 << 8) | (uuid_uint32_t)(*in++);
304 tmp32 = (tmp32 << 8) | (uuid_uint32_t)(*in++);
305 uuid->obj.time_low = tmp32;
306
307 /* unpack "time_mid" field */
308 tmp16 = (uuid_uint16_t)(*in++);
309 tmp16 = (uuid_uint16_t)(tmp16 << 8) | (uuid_uint16_t)(*in++);
310 uuid->obj.time_mid = tmp16;
311
312 /* unpack "time_hi_and_version" field */
313 tmp16 = (uuid_uint16_t)*in++;
314 tmp16 = (uuid_uint16_t)(tmp16 << 8) | (uuid_uint16_t)(*in++);
315 uuid->obj.time_hi_and_version = tmp16;
316
317 /* unpack "clock_seq_hi_and_reserved" field */
318 uuid->obj.clock_seq_hi_and_reserved = *in++;
319
320 /* unpack "clock_seq_low" field */
321 uuid->obj.clock_seq_low = *in++;
322
323 /* unpack "node" field */
324 for (i = 0; i < (unsigned int)sizeof(uuid->obj.node); i++)
325 uuid->obj.node[i] = *in++;
326
327 return UUID_RC_OK;
328 }
329
330 /* INTERNAL: pack UUID object into binary representation
331 (allows in-place operation for internal efficiency!) */
uuid_export_bin(const uuid_t * uuid,void * _data_ptr,size_t * data_len)332 static uuid_rc_t uuid_export_bin(const uuid_t *uuid, void *_data_ptr, size_t *data_len)
333 {
334 uuid_uint8_t **data_ptr;
335 uuid_uint8_t *out;
336 uuid_uint32_t tmp32;
337 uuid_uint16_t tmp16;
338 unsigned int i;
339
340 /* cast generic data pointer to particular pointer to pointer type */
341 data_ptr = (uuid_uint8_t **)_data_ptr;
342
343 /* sanity check argument(s) */
344 if (uuid == NULL || data_ptr == NULL)
345 return UUID_RC_ARG;
346
347 /* optionally allocate octet data buffer */
348 if (*data_ptr == NULL) {
349 if ((*data_ptr = (uuid_uint8_t *)malloc(sizeof(uuid_t))) == NULL)
350 return UUID_RC_MEM;
351 if (data_len != NULL)
352 *data_len = UUID_LEN_BIN;
353 }
354 else {
355 if (data_len == NULL)
356 return UUID_RC_ARG;
357 if (*data_len < UUID_LEN_BIN)
358 return UUID_RC_MEM;
359 *data_len = UUID_LEN_BIN;
360 }
361
362 /* treat output data buffer as octet stream */
363 out = *data_ptr;
364
365 /* pack "time_low" field */
366 tmp32 = uuid->obj.time_low;
367 out[3] = (uuid_uint8_t)(tmp32 & 0xff); tmp32 >>= 8;
368 out[2] = (uuid_uint8_t)(tmp32 & 0xff); tmp32 >>= 8;
369 out[1] = (uuid_uint8_t)(tmp32 & 0xff); tmp32 >>= 8;
370 out[0] = (uuid_uint8_t)(tmp32 & 0xff);
371
372 /* pack "time_mid" field */
373 tmp16 = uuid->obj.time_mid;
374 out[5] = (uuid_uint8_t)(tmp16 & 0xff); tmp16 >>= 8;
375 out[4] = (uuid_uint8_t)(tmp16 & 0xff);
376
377 /* pack "time_hi_and_version" field */
378 tmp16 = uuid->obj.time_hi_and_version;
379 out[7] = (uuid_uint8_t)(tmp16 & 0xff); tmp16 >>= 8;
380 out[6] = (uuid_uint8_t)(tmp16 & 0xff);
381
382 /* pack "clock_seq_hi_and_reserved" field */
383 out[8] = uuid->obj.clock_seq_hi_and_reserved;
384
385 /* pack "clock_seq_low" field */
386 out[9] = uuid->obj.clock_seq_low;
387
388 /* pack "node" field */
389 for (i = 0; i < (unsigned int)sizeof(uuid->obj.node); i++)
390 out[10+i] = uuid->obj.node[i];
391
392 return UUID_RC_OK;
393 }
394
395 /* INTERNAL: check for valid UUID string representation syntax */
uuid_isstr(const char * str,size_t str_len)396 static int uuid_isstr(const char *str, size_t str_len)
397 {
398 int i;
399 const char *cp;
400
401 /* example reference:
402 f81d4fae-7dec-11d0-a765-00a0c91e6bf6
403 012345678901234567890123456789012345
404 0 1 2 3 */
405 if (str == NULL)
406 return UUID_FALSE;
407 if (str_len == 0)
408 str_len = strlen(str);
409 if (str_len < UUID_LEN_STR)
410 return UUID_FALSE;
411 for (i = 0, cp = str; i < UUID_LEN_STR; i++, cp++) {
412 if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
413 if (*cp == '-')
414 continue;
415 else
416 return UUID_FALSE;
417 }
418 if (!isxdigit((int)(*cp)))
419 return UUID_FALSE;
420 }
421 return UUID_TRUE;
422 }
423
424 /* INTERNAL: import UUID object from string representation */
uuid_import_str(uuid_t * uuid,const void * data_ptr,size_t data_len)425 static uuid_rc_t uuid_import_str(uuid_t *uuid, const void *data_ptr, size_t data_len)
426 {
427 uuid_uint16_t tmp16;
428 const char *cp;
429 char hexbuf[3];
430 const char *str;
431 unsigned int i;
432
433 /* sanity check argument(s) */
434 if (uuid == NULL || data_ptr == NULL || data_len < UUID_LEN_STR)
435 return UUID_RC_ARG;
436
437 /* check for correct UUID string representation syntax */
438 str = (const char *)data_ptr;
439 if (!uuid_isstr(str, 0))
440 return UUID_RC_ARG;
441
442 /* parse hex values of "time" parts */
443 uuid->obj.time_low = (uuid_uint32_t)strtoul(str, NULL, 16);
444 uuid->obj.time_mid = (uuid_uint16_t)strtoul(str+9, NULL, 16);
445 uuid->obj.time_hi_and_version = (uuid_uint16_t)strtoul(str+14, NULL, 16);
446
447 /* parse hex values of "clock" parts */
448 tmp16 = (uuid_uint16_t)strtoul(str+19, NULL, 16);
449 uuid->obj.clock_seq_low = (uuid_uint8_t)(tmp16 & 0xff); tmp16 >>= 8;
450 uuid->obj.clock_seq_hi_and_reserved = (uuid_uint8_t)(tmp16 & 0xff);
451
452 /* parse hex values of "node" part */
453 cp = str+24;
454 hexbuf[2] = '\0';
455 for (i = 0; i < (unsigned int)sizeof(uuid->obj.node); i++) {
456 hexbuf[0] = *cp++;
457 hexbuf[1] = *cp++;
458 uuid->obj.node[i] = (uuid_uint8_t)strtoul(hexbuf, NULL, 16);
459 }
460
461 return UUID_RC_OK;
462 }
463
464 /* INTERNAL: import UUID object from single integer value representation */
uuid_import_siv(uuid_t * uuid,const void * data_ptr,size_t data_len)465 static uuid_rc_t uuid_import_siv(uuid_t *uuid, const void *data_ptr, size_t data_len)
466 {
467 const char *str;
468 uuid_uint8_t tmp_bin[UUID_LEN_BIN];
469 ui128_t ui, ui2;
470 uuid_rc_t rc;
471 int i;
472
473 /* sanity check argument(s) */
474 if (uuid == NULL || data_ptr == NULL || data_len < 1)
475 return UUID_RC_ARG;
476
477 /* check for correct UUID single integer value syntax */
478 str = (const char *)data_ptr;
479 for (i = 0; i < (int)data_len; i++)
480 if (!isdigit((int)str[i]))
481 return UUID_RC_ARG;
482
483 /* parse single integer value representation (SIV) */
484 ui = ui128_s2i(str, NULL, 10);
485
486 /* import octets into UUID binary representation */
487 for (i = 0; i < UUID_LEN_BIN; i++) {
488 ui = ui128_rol(ui, 8, &ui2);
489 tmp_bin[i] = (uuid_uint8_t)(ui128_i2n(ui2) & 0xff);
490 }
491
492 /* import into internal UUID representation */
493 if ((rc = uuid_import(uuid, UUID_FMT_BIN, (void *)&tmp_bin, UUID_LEN_BIN)) != UUID_RC_OK)
494 return rc;
495
496 return UUID_RC_OK;
497 }
498
499 /* INTERNAL: export UUID object to string representation */
uuid_export_str(const uuid_t * uuid,void * _data_ptr,size_t * data_len)500 static uuid_rc_t uuid_export_str(const uuid_t *uuid, void *_data_ptr, size_t *data_len)
501 {
502 char **data_ptr;
503 char *data_buf;
504
505 /* cast generic data pointer to particular pointer to pointer type */
506 data_ptr = (char **)_data_ptr;
507
508 /* sanity check argument(s) */
509 if (uuid == NULL || data_ptr == NULL)
510 return UUID_RC_ARG;
511
512 /* determine output buffer */
513 if (*data_ptr == NULL) {
514 if ((data_buf = (char *)malloc(UUID_LEN_STR+1)) == NULL)
515 return UUID_RC_MEM;
516 if (data_len != NULL)
517 *data_len = UUID_LEN_STR+1;
518 }
519 else {
520 data_buf = (char *)(*data_ptr);
521 if (data_len == NULL)
522 return UUID_RC_ARG;
523 if (*data_len < UUID_LEN_STR+1)
524 return UUID_RC_MEM;
525 *data_len = UUID_LEN_STR+1;
526 }
527
528 /* format UUID into string representation */
529 if (str_snprintf(data_buf, UUID_LEN_STR+1,
530 "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
531 (unsigned long)uuid->obj.time_low,
532 (unsigned int)uuid->obj.time_mid,
533 (unsigned int)uuid->obj.time_hi_and_version,
534 (unsigned int)uuid->obj.clock_seq_hi_and_reserved,
535 (unsigned int)uuid->obj.clock_seq_low,
536 (unsigned int)uuid->obj.node[0],
537 (unsigned int)uuid->obj.node[1],
538 (unsigned int)uuid->obj.node[2],
539 (unsigned int)uuid->obj.node[3],
540 (unsigned int)uuid->obj.node[4],
541 (unsigned int)uuid->obj.node[5]) != UUID_LEN_STR) {
542 if (*data_ptr == NULL)
543 free(data_buf);
544 return UUID_RC_INT;
545 }
546
547 /* pass back new buffer if locally allocated */
548 if (*data_ptr == NULL)
549 *data_ptr = data_buf;
550
551 return UUID_RC_OK;
552 }
553
554 /* INTERNAL: export UUID object to single integer value representation */
uuid_export_siv(const uuid_t * uuid,void * _data_ptr,size_t * data_len)555 static uuid_rc_t uuid_export_siv(const uuid_t *uuid, void *_data_ptr, size_t *data_len)
556 {
557 char **data_ptr;
558 char *data_buf;
559 void *tmp_ptr;
560 size_t tmp_len;
561 uuid_uint8_t tmp_bin[UUID_LEN_BIN];
562 ui128_t ui, ui2;
563 uuid_rc_t rc;
564 int i;
565
566 /* cast generic data pointer to particular pointer to pointer type */
567 data_ptr = (char **)_data_ptr;
568
569 /* sanity check argument(s) */
570 if (uuid == NULL || data_ptr == NULL)
571 return UUID_RC_ARG;
572
573 /* determine output buffer */
574 if (*data_ptr == NULL) {
575 if ((data_buf = (char *)malloc(UUID_LEN_SIV+1)) == NULL)
576 return UUID_RC_MEM;
577 if (data_len != NULL)
578 *data_len = UUID_LEN_SIV+1;
579 }
580 else {
581 data_buf = (char *)(*data_ptr);
582 if (data_len == NULL)
583 return UUID_RC_ARG;
584 if (*data_len < UUID_LEN_SIV+1)
585 return UUID_RC_MEM;
586 *data_len = UUID_LEN_SIV+1;
587 }
588
589 /* export into UUID binary representation */
590 tmp_ptr = (void *)&tmp_bin;
591 tmp_len = sizeof(tmp_bin);
592 if ((rc = uuid_export(uuid, UUID_FMT_BIN, &tmp_ptr, &tmp_len)) != UUID_RC_OK) {
593 if (*data_ptr == NULL)
594 free(data_buf);
595 return rc;
596 }
597
598 /* import from UUID binary representation */
599 ui = ui128_zero();
600 for (i = 0; i < UUID_LEN_BIN; i++) {
601 ui2 = ui128_n2i((unsigned long)tmp_bin[i]);
602 ui = ui128_rol(ui, 8, NULL);
603 ui = ui128_or(ui, ui2);
604 }
605
606 /* format into single integer value representation */
607 (void)ui128_i2s(ui, data_buf, UUID_LEN_SIV+1, 10);
608
609 /* pass back new buffer if locally allocated */
610 if (*data_ptr == NULL)
611 *data_ptr = data_buf;
612
613 return UUID_RC_OK;
614 }
615
616 /* decoding tables */
617 static struct {
618 uuid_uint8_t num;
619 const char *desc;
620 } uuid_dectab_variant[] = {
621 { (uuid_uint8_t)BM_OCTET(0,0,0,0,0,0,0,0), "reserved (NCS backward compatible)" },
622 { (uuid_uint8_t)BM_OCTET(1,0,0,0,0,0,0,0), "DCE 1.1, ISO/IEC 11578:1996" },
623 { (uuid_uint8_t)BM_OCTET(1,1,0,0,0,0,0,0), "reserved (Microsoft GUID)" },
624 { (uuid_uint8_t)BM_OCTET(1,1,1,0,0,0,0,0), "reserved (future use)" }
625 };
626 static struct {
627 int num;
628 const char *desc;
629 } uuid_dectab_version[] = {
630 { 1, "time and node based" },
631 { 3, "name based, MD5" },
632 { 4, "random data based" },
633 { 5, "name based, SHA-1" }
634 };
635
636 /* INTERNAL: dump UUID object as descriptive text */
uuid_export_txt(const uuid_t * uuid,void * _data_ptr,size_t * data_len)637 static uuid_rc_t uuid_export_txt(const uuid_t *uuid, void *_data_ptr, size_t *data_len)
638 {
639 char **data_ptr;
640 uuid_rc_t rc;
641 char **out;
642 char *out_ptr;
643 size_t out_len;
644 const char *version;
645 const char *variant;
646 char *content;
647 int isnil;
648 uuid_uint8_t tmp8;
649 uuid_uint16_t tmp16;
650 uuid_uint32_t tmp32;
651 uuid_uint8_t tmp_bin[UUID_LEN_BIN];
652 char tmp_str[UUID_LEN_STR+1];
653 char tmp_siv[UUID_LEN_SIV+1];
654 void *tmp_ptr;
655 size_t tmp_len;
656 ui64_t t;
657 ui64_t t_offset;
658 int t_nsec;
659 int t_usec;
660 time_t t_sec;
661 char t_buf[19+1]; /* YYYY-MM-DD HH:MM:SS */
662 struct tm *tm;
663 int i;
664
665 /* cast generic data pointer to particular pointer to pointer type */
666 data_ptr = (char **)_data_ptr;
667
668 /* sanity check argument(s) */
669 if (uuid == NULL || data_ptr == NULL)
670 return UUID_RC_ARG;
671
672 /* initialize output buffer */
673 out_ptr = NULL;
674 out = &out_ptr;
675
676 /* check for special case of "Nil UUID" */
677 if ((rc = uuid_isnil(uuid, &isnil)) != UUID_RC_OK)
678 return rc;
679
680 /* decode into various representations */
681 tmp_ptr = (void *)&tmp_str;
682 tmp_len = sizeof(tmp_str);
683 if ((rc = uuid_export(uuid, UUID_FMT_STR, &tmp_ptr, &tmp_len)) != UUID_RC_OK)
684 return rc;
685 tmp_ptr = (void *)&tmp_siv;
686 tmp_len = sizeof(tmp_siv);
687 if ((rc = uuid_export(uuid, UUID_FMT_SIV, &tmp_ptr, &tmp_len)) != UUID_RC_OK)
688 return rc;
689 (void)str_rsprintf(out, "encode: STR: %s\n", tmp_str);
690 (void)str_rsprintf(out, " SIV: %s\n", tmp_siv);
691
692 /* decode UUID variant */
693 tmp8 = uuid->obj.clock_seq_hi_and_reserved;
694 if (isnil)
695 variant = "n.a.";
696 else {
697 variant = "unknown";
698 for (i = 7; i >= 0; i--) {
699 if ((tmp8 & (uuid_uint8_t)BM_BIT(i,1)) == 0) {
700 tmp8 &= ~(uuid_uint8_t)BM_MASK(i,0);
701 break;
702 }
703 }
704 for (i = 0; i < (int)(sizeof(uuid_dectab_variant)/sizeof(uuid_dectab_variant[0])); i++) {
705 if (uuid_dectab_variant[i].num == tmp8) {
706 variant = uuid_dectab_variant[i].desc;
707 break;
708 }
709 }
710 }
711 (void)str_rsprintf(out, "decode: variant: %s\n", variant);
712
713 /* decode UUID version */
714 tmp16 = (BM_SHR(uuid->obj.time_hi_and_version, 12) & (uuid_uint16_t)BM_MASK(3,0));
715 if (isnil)
716 version = "n.a.";
717 else {
718 version = "unknown";
719 for (i = 0; i < (int)(sizeof(uuid_dectab_version)/sizeof(uuid_dectab_version[0])); i++) {
720 if (uuid_dectab_version[i].num == (int)tmp16) {
721 version = uuid_dectab_version[i].desc;
722 break;
723 }
724 }
725 }
726 str_rsprintf(out, " version: %d (%s)\n", (int)tmp16, version);
727
728 /*
729 * decode UUID content
730 */
731
732 if (tmp8 == BM_OCTET(1,0,0,0,0,0,0,0) && tmp16 == 1) {
733 /* decode DCE 1.1 version 1 UUID */
734
735 /* decode system time */
736 t = ui64_rol(ui64_n2i((unsigned long)(uuid->obj.time_hi_and_version & BM_MASK(11,0))), 48, NULL),
737 t = ui64_or(t, ui64_rol(ui64_n2i((unsigned long)(uuid->obj.time_mid)), 32, NULL));
738 t = ui64_or(t, ui64_n2i((unsigned long)(uuid->obj.time_low)));
739 t_offset = ui64_s2i(UUID_TIMEOFFSET, NULL, 16);
740 t = ui64_sub(t, t_offset, NULL);
741 t = ui64_divn(t, 10, &t_nsec);
742 t = ui64_divn(t, 1000000, &t_usec);
743 t_sec = (time_t)ui64_i2n(t);
744 tm = gmtime(&t_sec);
745 (void)strftime(t_buf, sizeof(t_buf), "%Y-%m-%d %H:%M:%S", tm);
746 (void)str_rsprintf(out, " content: time: %s.%06d.%d UTC\n", t_buf, t_usec, t_nsec);
747
748 /* decode clock sequence */
749 tmp32 = ((uuid->obj.clock_seq_hi_and_reserved & BM_MASK(5,0)) << 8)
750 + uuid->obj.clock_seq_low;
751 (void)str_rsprintf(out, " clock: %ld (usually random)\n", (long)tmp32);
752
753 /* decode node MAC address */
754 (void)str_rsprintf(out, " node: %02x:%02x:%02x:%02x:%02x:%02x (%s %s)\n",
755 (unsigned int)uuid->obj.node[0],
756 (unsigned int)uuid->obj.node[1],
757 (unsigned int)uuid->obj.node[2],
758 (unsigned int)uuid->obj.node[3],
759 (unsigned int)uuid->obj.node[4],
760 (unsigned int)uuid->obj.node[5],
761 (uuid->obj.node[0] & IEEE_MAC_LOBIT ? "local" : "global"),
762 (uuid->obj.node[0] & IEEE_MAC_MCBIT ? "multicast" : "unicast"));
763 }
764 else {
765 /* decode anything else as hexadecimal byte-string only */
766
767 /* determine annotational hint */
768 content = "not decipherable: unknown UUID version";
769 if (isnil)
770 content = "special case: DCE 1.1 Nil UUID";
771 else if (tmp16 == 3)
772 content = "not decipherable: MD5 message digest only";
773 else if (tmp16 == 4)
774 content = "no semantics: random data only";
775 else if (tmp16 == 5)
776 content = "not decipherable: truncated SHA-1 message digest only";
777
778 /* pack UUID into binary representation */
779 tmp_ptr = (void *)&tmp_bin;
780 tmp_len = sizeof(tmp_bin);
781 if ((rc = uuid_export(uuid, UUID_FMT_BIN, &tmp_ptr, &tmp_len)) != UUID_RC_OK)
782 return rc;
783
784 /* mask out version and variant parts */
785 tmp_bin[6] &= BM_MASK(3,0);
786 tmp_bin[8] &= BM_MASK(5,0);
787
788 /* dump as colon-seperated hexadecimal byte-string */
789 (void)str_rsprintf(out,
790 " content: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n"
791 " (%s)\n",
792 (unsigned int)tmp_bin[0], (unsigned int)tmp_bin[1], (unsigned int)tmp_bin[2],
793 (unsigned int)tmp_bin[3], (unsigned int)tmp_bin[4], (unsigned int)tmp_bin[5],
794 (unsigned int)tmp_bin[6], (unsigned int)tmp_bin[7], (unsigned int)tmp_bin[8],
795 (unsigned int)tmp_bin[9], (unsigned int)tmp_bin[10], (unsigned int)tmp_bin[11],
796 (unsigned int)tmp_bin[12], (unsigned int)tmp_bin[13], (unsigned int)tmp_bin[14],
797 (unsigned int)tmp_bin[15], content);
798 }
799
800 /* provide result */
801 out_len = strlen(out_ptr)+1;
802 if (*data_ptr == NULL) {
803 *data_ptr = (void *)out_ptr;
804 if (data_len != NULL)
805 *data_len = out_len;
806 }
807 else {
808 if (data_len == NULL)
809 return UUID_RC_ARG;
810 if (*data_len < out_len)
811 return UUID_RC_MEM;
812 memcpy(*data_ptr, out_ptr, out_len);
813 }
814
815 return UUID_RC_OK;
816 }
817
818 /* UUID importing */
uuid_import(uuid_t * uuid,uuid_fmt_t fmt,const void * data_ptr,size_t data_len)819 uuid_rc_t uuid_import(uuid_t *uuid, uuid_fmt_t fmt, const void *data_ptr, size_t data_len)
820 {
821 uuid_rc_t rc;
822
823 /* sanity check argument(s) */
824 if (uuid == NULL || data_ptr == NULL)
825 return UUID_RC_ARG;
826
827 /* dispatch into format-specific functions */
828 switch (fmt) {
829 case UUID_FMT_BIN: rc = uuid_import_bin(uuid, data_ptr, data_len); break;
830 case UUID_FMT_STR: rc = uuid_import_str(uuid, data_ptr, data_len); break;
831 case UUID_FMT_SIV: rc = uuid_import_siv(uuid, data_ptr, data_len); break;
832 case UUID_FMT_TXT: rc = UUID_RC_IMP; /* not implemented */ break;
833 default: rc = UUID_RC_ARG;
834 }
835
836 return rc;
837 }
838
839 /* UUID exporting */
uuid_export(const uuid_t * uuid,uuid_fmt_t fmt,void * data_ptr,size_t * data_len)840 uuid_rc_t uuid_export(const uuid_t *uuid, uuid_fmt_t fmt, void *data_ptr, size_t *data_len)
841 {
842 uuid_rc_t rc;
843
844 /* sanity check argument(s) */
845 if (uuid == NULL || data_ptr == NULL)
846 return UUID_RC_ARG;
847
848 /* dispatch into format-specific functions */
849 switch (fmt) {
850 case UUID_FMT_BIN: rc = uuid_export_bin(uuid, data_ptr, data_len); break;
851 case UUID_FMT_STR: rc = uuid_export_str(uuid, data_ptr, data_len); break;
852 case UUID_FMT_SIV: rc = uuid_export_siv(uuid, data_ptr, data_len); break;
853 case UUID_FMT_TXT: rc = uuid_export_txt(uuid, data_ptr, data_len); break;
854 default: rc = UUID_RC_ARG;
855 }
856
857 return rc;
858 }
859
860 /* INTERNAL: brand UUID with version and variant */
uuid_brand(uuid_t * uuid,unsigned int version)861 static void uuid_brand(uuid_t *uuid, unsigned int version)
862 {
863 /* set version (as given) */
864 uuid->obj.time_hi_and_version &= BM_MASK(11,0);
865 uuid->obj.time_hi_and_version |= (uuid_uint16_t)BM_SHL(version, 12);
866
867 /* set variant (always DCE 1.1 only) */
868 uuid->obj.clock_seq_hi_and_reserved &= BM_MASK(5,0);
869 uuid->obj.clock_seq_hi_and_reserved |= BM_SHL(0x02, 6);
870 return;
871 }
872
873 /* INTERNAL: generate UUID version 1: time, clock and node based */
uuid_make_v1(uuid_t * uuid,unsigned int mode,va_list ap)874 static uuid_rc_t uuid_make_v1(uuid_t *uuid, unsigned int mode, va_list ap)
875 {
876 struct timeval time_now;
877 ui64_t t;
878 ui64_t offset;
879 ui64_t ov;
880 uuid_uint16_t clck;
881
882 /*
883 * GENERATE TIME
884 */
885
886 /* determine current system time and sequence counter */
887 for (;;) {
888 /* determine current system time */
889 if (time_gettimeofday(&time_now) == -1)
890 return UUID_RC_SYS;
891
892 /* check whether system time changed since last retrieve */
893 if (!( time_now.tv_sec == uuid->time_last.tv_sec
894 && time_now.tv_usec == uuid->time_last.tv_usec)) {
895 /* reset time sequence counter and continue */
896 uuid->time_seq = 0;
897 break;
898 }
899
900 /* until we are out of UUIDs per tick, increment
901 the time/tick sequence counter and continue */
902 if (uuid->time_seq < UUIDS_PER_TICK) {
903 uuid->time_seq++;
904 break;
905 }
906
907 /* stall the UUID generation until the system clock (which
908 has a gettimeofday(2) resolution of 1us) catches up */
909 time_usleep(1);
910 }
911
912 /* convert from timeval (sec,usec) to OSSP ui64 (100*nsec) format */
913 t = ui64_n2i((unsigned long)time_now.tv_sec);
914 t = ui64_muln(t, 1000000, NULL);
915 t = ui64_addn(t, (int)time_now.tv_usec, NULL);
916 t = ui64_muln(t, 10, NULL);
917
918 /* adjust for offset between UUID and Unix Epoch time */
919 offset = ui64_s2i(UUID_TIMEOFFSET, NULL, 16);
920 t = ui64_add(t, offset, NULL);
921
922 /* compensate for low resolution system clock by adding
923 the time/tick sequence counter */
924 if (uuid->time_seq > 0)
925 t = ui64_addn(t, (int)uuid->time_seq, NULL);
926
927 /* store the 60 LSB of the time in the UUID */
928 t = ui64_rol(t, 16, &ov);
929 uuid->obj.time_hi_and_version =
930 (uuid_uint16_t)(ui64_i2n(ov) & 0x00000fff); /* 12 of 16 bit only! */
931 t = ui64_rol(t, 16, &ov);
932 uuid->obj.time_mid =
933 (uuid_uint16_t)(ui64_i2n(ov) & 0x0000ffff); /* all 16 bit */
934 t = ui64_rol(t, 32, &ov);
935 uuid->obj.time_low =
936 (uuid_uint32_t)(ui64_i2n(ov) & 0xffffffff); /* all 32 bit */
937
938 /*
939 * GENERATE CLOCK
940 */
941
942 /* retrieve current clock sequence */
943 clck = ((uuid->obj.clock_seq_hi_and_reserved & BM_MASK(5,0)) << 8)
944 + uuid->obj.clock_seq_low;
945
946 /* generate new random clock sequence (initially or if the
947 time has stepped backwards) or else just increase it */
948 if ( clck == 0
949 || ( time_now.tv_sec < uuid->time_last.tv_sec
950 || ( time_now.tv_sec == uuid->time_last.tv_sec
951 && time_now.tv_usec < uuid->time_last.tv_usec))) {
952 if (prng_data(uuid->prng, (void *)&clck, sizeof(clck)) != PRNG_RC_OK)
953 return UUID_RC_INT;
954 }
955 else
956 clck++;
957 clck %= BM_POW2(14);
958
959 /* store back new clock sequence */
960 uuid->obj.clock_seq_hi_and_reserved =
961 (uuid->obj.clock_seq_hi_and_reserved & BM_MASK(7,6))
962 | (uuid_uint8_t)((clck >> 8) & 0xff);
963 uuid->obj.clock_seq_low =
964 (uuid_uint8_t)(clck & 0xff);
965
966 /*
967 * GENERATE NODE
968 */
969
970 if ((mode & UUID_MAKE_MC) || (uuid->mac[0] & BM_OCTET(1,0,0,0,0,0,0,0))) {
971 /* generate random IEEE 802 local multicast MAC address */
972 if (prng_data(uuid->prng, (void *)&(uuid->obj.node), sizeof(uuid->obj.node)) != PRNG_RC_OK)
973 return UUID_RC_INT;
974 uuid->obj.node[0] |= IEEE_MAC_MCBIT;
975 uuid->obj.node[0] |= IEEE_MAC_LOBIT;
976 }
977 else {
978 /* use real regular MAC address */
979 memcpy(uuid->obj.node, uuid->mac, sizeof(uuid->mac));
980 }
981
982 /*
983 * FINISH
984 */
985
986 /* remember current system time for next iteration */
987 uuid->time_last.tv_sec = time_now.tv_sec;
988 uuid->time_last.tv_usec = time_now.tv_usec;
989
990 /* brand with version and variant */
991 uuid_brand(uuid, 1);
992
993 return UUID_RC_OK;
994 }
995
996 /* INTERNAL: pre-defined UUID values.
997 (defined as network byte ordered octet stream) */
998 #define UUID_MAKE(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16) \
999 { (uuid_uint8_t)(a1), (uuid_uint8_t)(a2), (uuid_uint8_t)(a3), (uuid_uint8_t)(a4), \
1000 (uuid_uint8_t)(a5), (uuid_uint8_t)(a6), (uuid_uint8_t)(a7), (uuid_uint8_t)(a8), \
1001 (uuid_uint8_t)(a9), (uuid_uint8_t)(a10), (uuid_uint8_t)(a11), (uuid_uint8_t)(a12), \
1002 (uuid_uint8_t)(a13), (uuid_uint8_t)(a14), (uuid_uint8_t)(a15), (uuid_uint8_t)(a16) }
1003 static struct {
1004 char *name;
1005 uuid_uint8_t uuid[UUID_LEN_BIN];
1006 } uuid_value_table[] = {
1007 { "nil", /* 00000000-0000-0000-0000-000000000000 ("Nil UUID") */
1008 UUID_MAKE(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00) },
1009 { "ns:DNS", /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 (see RFC 4122) */
1010 UUID_MAKE(0x6b,0xa7,0xb8,0x10,0x9d,0xad,0x11,0xd1,0x80,0xb4,0x00,0xc0,0x4f,0xd4,0x30,0xc8) },
1011 { "ns:URL", /* 6ba7b811-9dad-11d1-80b4-00c04fd430c8 (see RFC 4122) */
1012 UUID_MAKE(0x6b,0xa7,0xb8,0x11,0x9d,0xad,0x11,0xd1,0x80,0xb4,0x00,0xc0,0x4f,0xd4,0x30,0xc8) },
1013 { "ns:OID", /* 6ba7b812-9dad-11d1-80b4-00c04fd430c8 (see RFC 4122) */
1014 UUID_MAKE(0x6b,0xa7,0xb8,0x12,0x9d,0xad,0x11,0xd1,0x80,0xb4,0x00,0xc0,0x4f,0xd4,0x30,0xc8) },
1015 { "ns:X500", /* 6ba7b814-9dad-11d1-80b4-00c04fd430c8 (see RFC 4122) */
1016 UUID_MAKE(0x6b,0xa7,0xb8,0x14,0x9d,0xad,0x11,0xd1,0x80,0xb4,0x00,0xc0,0x4f,0xd4,0x30,0xc8) }
1017 };
1018
1019 /* load UUID object with pre-defined value */
uuid_load(uuid_t * uuid,const char * name)1020 uuid_rc_t uuid_load(uuid_t *uuid, const char *name)
1021 {
1022 uuid_uint8_t *uuid_octets;
1023 uuid_rc_t rc;
1024 unsigned int i;
1025
1026 /* sanity check argument(s) */
1027 if (uuid == NULL || name == NULL)
1028 return UUID_RC_ARG;
1029
1030 /* search for UUID in table */
1031 uuid_octets = NULL;
1032 for (i = 0; i < (unsigned int)sizeof(uuid_value_table)/sizeof(uuid_value_table[0]); i++) {
1033 if (strcmp(uuid_value_table[i].name, name) == 0) {
1034 uuid_octets = uuid_value_table[i].uuid;
1035 break;
1036 }
1037 }
1038 if (uuid_octets == NULL)
1039 return UUID_RC_ARG;
1040
1041 /* import value into UUID object */
1042 if ((rc = uuid_import(uuid, UUID_FMT_BIN, uuid_octets, UUID_LEN_BIN)) != UUID_RC_OK)
1043 return rc;
1044
1045 return UUID_RC_OK;
1046 }
1047
1048 /* INTERNAL: generate UUID version 3: name based with MD5 */
uuid_make_v3(uuid_t * uuid,unsigned int mode,va_list ap)1049 static uuid_rc_t uuid_make_v3(uuid_t *uuid, unsigned int mode, va_list ap)
1050 {
1051 char *str;
1052 uuid_t *uuid_ns;
1053 uuid_uint8_t uuid_buf[UUID_LEN_BIN];
1054 void *uuid_ptr;
1055 size_t uuid_len;
1056 uuid_rc_t rc;
1057
1058 /* determine namespace UUID and name string arguments */
1059 if ((uuid_ns = (uuid_t *)va_arg(ap, void *)) == NULL)
1060 return UUID_RC_ARG;
1061 if ((str = (char *)va_arg(ap, char *)) == NULL)
1062 return UUID_RC_ARG;
1063
1064 /* initialize MD5 context */
1065 if (md5_init(uuid->md5) != MD5_RC_OK)
1066 return UUID_RC_MEM;
1067
1068 /* load the namespace UUID into MD5 context */
1069 uuid_ptr = (void *)&uuid_buf;
1070 uuid_len = sizeof(uuid_buf);
1071 if ((rc = uuid_export(uuid_ns, UUID_FMT_BIN, &uuid_ptr, &uuid_len)) != UUID_RC_OK)
1072 return rc;
1073 if (md5_update(uuid->md5, uuid_buf, uuid_len) != MD5_RC_OK)
1074 return UUID_RC_INT;
1075
1076 /* load the argument name string into MD5 context */
1077 if (md5_update(uuid->md5, str, strlen(str)) != MD5_RC_OK)
1078 return UUID_RC_INT;
1079
1080 /* store MD5 result into UUID
1081 (requires MD5_LEN_BIN space, UUID_LEN_BIN space is available,
1082 and both are equal in size, so we are safe!) */
1083 uuid_ptr = (void *)&(uuid->obj);
1084 if (md5_store(uuid->md5, &uuid_ptr, NULL) != MD5_RC_OK)
1085 return UUID_RC_INT;
1086
1087 /* fulfill requirement of standard and convert UUID data into
1088 local/host byte order (this uses fact that uuid_import_bin() is
1089 able to operate in-place!) */
1090 if ((rc = uuid_import(uuid, UUID_FMT_BIN, (void *)&(uuid->obj), UUID_LEN_BIN)) != UUID_RC_OK)
1091 return rc;
1092
1093 /* brand UUID with version and variant */
1094 uuid_brand(uuid, 3);
1095
1096 return UUID_RC_OK;
1097 }
1098
1099 /* INTERNAL: generate UUID version 4: random number based */
uuid_make_v4(uuid_t * uuid,unsigned int mode,va_list ap)1100 static uuid_rc_t uuid_make_v4(uuid_t *uuid, unsigned int mode, va_list ap)
1101 {
1102 /* fill UUID with random data */
1103 if (prng_data(uuid->prng, (void *)&(uuid->obj), sizeof(uuid->obj)) != PRNG_RC_OK)
1104 return UUID_RC_INT;
1105
1106 /* brand UUID with version and variant */
1107 uuid_brand(uuid, 4);
1108
1109 return UUID_RC_OK;
1110 }
1111
1112 /* INTERNAL: generate UUID version 5: name based with SHA-1 */
uuid_make_v5(uuid_t * uuid,unsigned int mode,va_list ap)1113 static uuid_rc_t uuid_make_v5(uuid_t *uuid, unsigned int mode, va_list ap)
1114 {
1115 char *str;
1116 uuid_t *uuid_ns;
1117 uuid_uint8_t uuid_buf[UUID_LEN_BIN];
1118 void *uuid_ptr;
1119 size_t uuid_len;
1120 uuid_uint8_t sha1_buf[SHA1_LEN_BIN];
1121 void *sha1_ptr;
1122 uuid_rc_t rc;
1123
1124 /* determine namespace UUID and name string arguments */
1125 if ((uuid_ns = (uuid_t *)va_arg(ap, void *)) == NULL)
1126 return UUID_RC_ARG;
1127 if ((str = (char *)va_arg(ap, char *)) == NULL)
1128 return UUID_RC_ARG;
1129
1130 /* initialize SHA-1 context */
1131 if (sha1_init(uuid->sha1) != SHA1_RC_OK)
1132 return UUID_RC_INT;
1133
1134 /* load the namespace UUID into SHA-1 context */
1135 uuid_ptr = (void *)&uuid_buf;
1136 uuid_len = sizeof(uuid_buf);
1137 if ((rc = uuid_export(uuid_ns, UUID_FMT_BIN, &uuid_ptr, &uuid_len)) != UUID_RC_OK)
1138 return rc;
1139 if (sha1_update(uuid->sha1, uuid_buf, uuid_len) != SHA1_RC_OK)
1140 return UUID_RC_INT;
1141
1142 /* load the argument name string into SHA-1 context */
1143 if (sha1_update(uuid->sha1, str, strlen(str)) != SHA1_RC_OK)
1144 return UUID_RC_INT;
1145
1146 /* store SHA-1 result into UUID
1147 (requires SHA1_LEN_BIN space, but UUID_LEN_BIN space is available
1148 only, so use a temporary buffer to store SHA-1 results and then
1149 use lower part only according to standard */
1150 sha1_ptr = (void *)sha1_buf;
1151 if (sha1_store(uuid->sha1, &sha1_ptr, NULL) != SHA1_RC_OK)
1152 return UUID_RC_INT;
1153 uuid_ptr = (void *)&(uuid->obj);
1154 memcpy(uuid_ptr, sha1_ptr, UUID_LEN_BIN);
1155
1156 /* fulfill requirement of standard and convert UUID data into
1157 local/host byte order (this uses fact that uuid_import_bin() is
1158 able to operate in-place!) */
1159 if ((rc = uuid_import(uuid, UUID_FMT_BIN, (void *)&(uuid->obj), UUID_LEN_BIN)) != UUID_RC_OK)
1160 return rc;
1161
1162 /* brand UUID with version and variant */
1163 uuid_brand(uuid, 5);
1164
1165 return UUID_RC_OK;
1166 }
1167
1168 /* generate UUID */
uuid_make(uuid_t * uuid,unsigned int mode,...)1169 uuid_rc_t uuid_make(uuid_t *uuid, unsigned int mode, ...)
1170 {
1171 va_list ap;
1172 uuid_rc_t rc;
1173
1174 /* sanity check argument(s) */
1175 if (uuid == NULL)
1176 return UUID_RC_ARG;
1177
1178 /* dispatch into version dependent generation functions */
1179 va_start(ap, mode);
1180 if (mode & UUID_MAKE_V1)
1181 rc = uuid_make_v1(uuid, mode, ap);
1182 else if (mode & UUID_MAKE_V3)
1183 rc = uuid_make_v3(uuid, mode, ap);
1184 else if (mode & UUID_MAKE_V4)
1185 rc = uuid_make_v4(uuid, mode, ap);
1186 else if (mode & UUID_MAKE_V5)
1187 rc = uuid_make_v5(uuid, mode, ap);
1188 else
1189 rc = UUID_RC_ARG;
1190 va_end(ap);
1191
1192 return rc;
1193 }
1194
1195 /* translate UUID API error code into corresponding error string */
uuid_error(uuid_rc_t rc)1196 char *uuid_error(uuid_rc_t rc)
1197 {
1198 char *str;
1199
1200 switch (rc) {
1201 case UUID_RC_OK: str = "everything ok"; break;
1202 case UUID_RC_ARG: str = "invalid argument"; break;
1203 case UUID_RC_MEM: str = "out of memory"; break;
1204 case UUID_RC_SYS: str = "system error"; break;
1205 case UUID_RC_INT: str = "internal error"; break;
1206 case UUID_RC_IMP: str = "not implemented"; break;
1207 default: str = NULL; break;
1208 }
1209 return str;
1210 }
1211
1212 /* OSSP uuid version (link-time information) */
uuid_version(void)1213 unsigned long uuid_version(void)
1214 {
1215 return (unsigned long)(_UUID_VERSION);
1216 }
1217
1218