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