1 /*
2  * uuid: emulation of e2fsprogs interface if implementation lacking.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  * Original uuid implementation: copyright (C) Theodore Ts'o
19  *
20  * This importation into heartbeat:
21  *	Copyright (C) 2004 David Lee <t.d.lee@durham.ac.uk>
22  *
23  */
24 
25 #include <crm_internal.h>
26 #include <stdio.h>
27 #ifdef HAVE_UNISTD_H
28 #  include <unistd.h>
29 #endif
30 #ifdef HAVE_STDLIB_H
31 #  include <stdlib.h>
32 #endif
33 #include <string.h>
34 #include <ctype.h>
35 
36 #include <replace_uuid.h>
37 
38 /*
39  * Local "replace" implementation of uuid functions.
40  */
41 
42 #include <sys/types.h>
43 #include <sys/time.h>
44 #include <time.h>
45 
46 /* UUID Variant definitions */
47 #define UUID_VARIANT_NCS	0
48 #define UUID_VARIANT_DCE	1
49 #define UUID_VARIANT_MICROSOFT	2
50 #define UUID_VARIANT_OTHER	3
51 
52 /* UUID Type definitions */
53 #define UUID_TYPE_DCE_TIME	1
54 #define UUID_TYPE_DCE_RANDOM	4
55 
56 /* For uuid_compare() */
57 #define UUCMP(u1,u2) if (u1 != u2) return((u1 < u2) ? -1 : 1);
58 
59 /************************************
60  * Private types
61  ************************************/
62 
63 #define longlong long long
64 
65 /*
66  * Offset between 15-Oct-1582 and 1-Jan-70
67  */
68 #define TIME_OFFSET_HIGH 0x01B21DD2
69 #define TIME_OFFSET_LOW  0x13814000
70 
71 #if (SIZEOF_INT == 4)
72 typedef unsigned int __u32;
73 #elif (SIZEOF_LONG == 4)
74 typedef unsigned long __u32;
75 #endif
76 
77 #if (SIZEOF_INT == 2)
78 typedef int __s16;
79 typedef unsigned int __u16;
80 #elif (SIZEOF_SHORT == 2)
81 typedef short __s16;
82 typedef unsigned short __u16;
83 #endif
84 
85 typedef unsigned char __u8;
86 
87 struct uuid {
88     __u32 time_low;
89     __u16 time_mid;
90     __u16 time_hi_and_version;
91     __u16 clock_seq;
92     __u8 node[6];
93 };
94 
95 /************************************
96  * internal routines
97  ************************************/
98 static void
uuid_pack(const struct uuid * uu,uuid_t ptr)99 uuid_pack(const struct uuid *uu, uuid_t ptr)
100 {
101     __u32 tmp;
102     unsigned char *out = ptr;
103 
104     tmp = uu->time_low;
105     out[3] = (unsigned char)tmp;
106     tmp >>= 8;
107     out[2] = (unsigned char)tmp;
108     tmp >>= 8;
109     out[1] = (unsigned char)tmp;
110     tmp >>= 8;
111     out[0] = (unsigned char)tmp;
112 
113     tmp = uu->time_mid;
114     out[5] = (unsigned char)tmp;
115     tmp >>= 8;
116     out[4] = (unsigned char)tmp;
117 
118     tmp = uu->time_hi_and_version;
119     out[7] = (unsigned char)tmp;
120     tmp >>= 8;
121     out[6] = (unsigned char)tmp;
122 
123     tmp = uu->clock_seq;
124     out[9] = (unsigned char)tmp;
125     tmp >>= 8;
126     out[8] = (unsigned char)tmp;
127 
128     memcpy(out + 10, uu->node, 6);
129 }
130 
131 static void
uuid_unpack(const uuid_t in,struct uuid * uu)132 uuid_unpack(const uuid_t in, struct uuid *uu)
133 {
134     const __u8 *ptr = in;
135     __u32 tmp;
136 
137     tmp = *ptr++;
138     tmp = (tmp << 8) | *ptr++;
139     tmp = (tmp << 8) | *ptr++;
140     tmp = (tmp << 8) | *ptr++;
141     uu->time_low = tmp;
142 
143     tmp = *ptr++;
144     tmp = (tmp << 8) | *ptr++;
145     uu->time_mid = tmp;
146 
147     tmp = *ptr++;
148     tmp = (tmp << 8) | *ptr++;
149     uu->time_hi_and_version = tmp;
150 
151     tmp = *ptr++;
152     tmp = (tmp << 8) | *ptr++;
153     uu->clock_seq = tmp;
154 
155     memcpy(uu->node, ptr, 6);
156 }
157 
158 /************************************
159  * Main routines, except uuid_generate*()
160  ************************************/
161 void
uuid_clear(uuid_t uu)162 uuid_clear(uuid_t uu)
163 {
164     memset(uu, 0, 16);
165 }
166 
167 int
uuid_compare(const uuid_t uu1,const uuid_t uu2)168 uuid_compare(const uuid_t uu1, const uuid_t uu2)
169 {
170     struct uuid uuid1, uuid2;
171 
172     uuid_unpack(uu1, &uuid1);
173     uuid_unpack(uu2, &uuid2);
174 
175     UUCMP(uuid1.time_low, uuid2.time_low);
176     UUCMP(uuid1.time_mid, uuid2.time_mid);
177     UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version);
178     UUCMP(uuid1.clock_seq, uuid2.clock_seq);
179     return memcmp(uuid1.node, uuid2.node, 6);
180 }
181 
182 void
uuid_copy(uuid_t dst,const uuid_t src)183 uuid_copy(uuid_t dst, const uuid_t src)
184 {
185     unsigned char *cp1;
186     const unsigned char *cp2;
187     int i;
188 
189     for (i = 0, cp1 = dst, cp2 = src; i < 16; i++)
190         *cp1++ = *cp2++;
191 }
192 
193 /* if uu is the null uuid, return 1 else 0 */
194 int
uuid_is_null(const uuid_t uu)195 uuid_is_null(const uuid_t uu)
196 {
197     const unsigned char *cp;
198     int i;
199 
200     for (i = 0, cp = uu; i < 16; i++)
201         if (*cp++)
202             return 0;
203     return 1;
204 }
205 
206 /* 36byte-string=>uuid */
207 int
uuid_parse(const char * in,uuid_t uu)208 uuid_parse(const char *in, uuid_t uu)
209 {
210     struct uuid uuid;
211     int i;
212     const char *cp;
213     char buf[3];
214 
215     if (strlen(in) != 36)
216         return -1;
217     for (i = 0, cp = in; i <= 36; i++, cp++) {
218         if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
219             if (*cp == '-')
220                 continue;
221             else
222                 return -1;
223         }
224         if (i == 36)
225             if (*cp == 0)
226                 continue;
227         if (!isxdigit((int)*cp))
228             return -1;
229     }
230     uuid.time_low = strtoul(in, NULL, 16);
231     uuid.time_mid = strtoul(in + 9, NULL, 16);
232     uuid.time_hi_and_version = strtoul(in + 14, NULL, 16);
233     uuid.clock_seq = strtoul(in + 19, NULL, 16);
234     cp = in + 24;
235     buf[2] = 0;
236     for (i = 0; i < 6; i++) {
237         buf[0] = *cp++;
238         buf[1] = *cp++;
239         uuid.node[i] = strtoul(buf, NULL, 16);
240     }
241 
242     uuid_pack(&uuid, uu);
243     return 0;
244 }
245 
246 /* uuid=>36byte-string-with-null */
247 void
uuid_unparse(const uuid_t uu,char * out)248 uuid_unparse(const uuid_t uu, char *out)
249 {
250     struct uuid uuid;
251 
252     uuid_unpack(uu, &uuid);
253     sprintf(out,
254             "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
255             uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
256             uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
257             uuid.node[0], uuid.node[1], uuid.node[2], uuid.node[3], uuid.node[4], uuid.node[5]);
258 }
259 
260 /************************************
261  * Main routines: uuid_generate*()
262  ************************************/
263 
264 #include <fcntl.h>
265 #include <sys/types.h>
266 #include <sys/stat.h>
267 
268 #ifdef HAVE_SYS_IOCTL_H
269 #  include <sys/ioctl.h>
270 #endif
271 #ifdef HAVE_SYS_SOCKET_H
272 #  include <sys/socket.h>
273 #endif
274 #ifdef HAVE_SYS_SOCKIO_H
275 #  include <sys/sockio.h>
276 #endif
277 #ifdef HAVE_NET_IF_H
278 #  include <net/if.h>
279 #endif
280 #ifdef HAVE_NETINET_IN_H
281 #  include <netinet/in.h>
282 #endif
283 
284 #ifdef HAVE_SRANDOM
285 #  define srand(x) 	srandom(x)
286 #  define rand() 		random()
287 #endif
288 
289 static int
get_random_fd(void)290 get_random_fd(void)
291 {
292     struct timeval tv;
293     static int fd = -2;
294     int i;
295 
296     if (fd == -2) {
297         gettimeofday(&tv, 0);
298         fd = open("/dev/urandom", O_RDONLY);
299         if (fd == -1)
300             fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
301         srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec);
302     }
303     /* Crank the random number generator a few times */
304     gettimeofday(&tv, 0);
305     for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--)
306         rand();
307     return fd;
308 }
309 
310 /*
311  * Generate a series of random bytes.  Use /dev/urandom if possible,
312  * and if not, use srandom/random.
313  */
314 static void
get_random_bytes(void * buf,int nbytes)315 get_random_bytes(void *buf, int nbytes)
316 {
317     int i, n = nbytes, fd = get_random_fd();
318     int lose_counter = 0;
319     unsigned char *cp = (unsigned char *)buf;
320 
321     if (fd >= 0) {
322         while (n > 0) {
323             i = read(fd, cp, n);
324             if (i <= 0) {
325                 if (lose_counter++ > 16)
326                     break;
327                 continue;
328             }
329             n -= i;
330             cp += i;
331             lose_counter = 0;
332         }
333     }
334 
335     /*
336      * We do this all the time, but this is the only source of
337      * randomness if /dev/random/urandom is out to lunch.
338      */
339     for (cp = buf, i = 0; i < nbytes; i++)
340         *cp++ ^= (rand() >> 7) & 0xFF;
341     return;
342 }
343 
344 /*
345  * Get the ethernet hardware address, if we can find it...
346  */
347 static int
get_node_id(unsigned char * node_id)348 get_node_id(unsigned char *node_id)
349 {
350 #ifdef HAVE_NET_IF_H
351     int sd;
352     struct ifreq ifr, *ifrp;
353     struct ifconf ifc;
354     char buf[1024];
355     int n, i;
356     unsigned char *a;
357 
358 /*
359  * BSD 4.4 defines the size of an ifreq to be
360  * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
361  * However, under earlier systems, sa_len isn't present, so the size is
362  * just sizeof(struct ifreq)
363  */
364 #  ifdef HAVE_SA_LEN
365 #    ifndef max
366 #      define max(a,b) ((a) > (b) ? (a) : (b))
367 #    endif
368 #    define ifreq_size(i) max(sizeof(struct ifreq),\
369      sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
370 #  else
371 #    define ifreq_size(i) sizeof(struct ifreq)
372 #  endif                        /* HAVE_SA_LEN */
373 
374     sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
375     if (sd < 0) {
376         return -1;
377     }
378     memset(buf, 0, sizeof(buf));
379     ifc.ifc_len = sizeof(buf);
380     ifc.ifc_buf = buf;
381     if (ioctl(sd, SIOCGIFCONF, (char *)&ifc) < 0) {
382         close(sd);
383         return -1;
384     }
385     n = ifc.ifc_len;
386     for (i = 0; i < n; i += ifreq_size(*ifr)) {
387         ifrp = (struct ifreq *)((char *)ifc.ifc_buf + i);
388         strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
389 #  ifdef SIOCGIFHWADDR
390         if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
391             continue;
392         a = (unsigned char *)&ifr.ifr_hwaddr.sa_data;
393 #  else
394 #    ifdef SIOCGENADDR
395         if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
396             continue;
397         a = (unsigned char *)ifr.ifr_enaddr;
398 #    else
399         /*
400          * XXX we don't have a way of getting the hardware
401          * address
402          */
403         close(sd);
404         return 0;
405 #    endif                      /* SIOCGENADDR */
406 #  endif                        /* SIOCGIFHWADDR */
407         if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
408             continue;
409         if (node_id) {
410             memcpy(node_id, a, 6);
411             close(sd);
412             return 1;
413         }
414     }
415     close(sd);
416 #endif
417     return 0;
418 }
419 
420 /* Assume that the gettimeofday() has microsecond granularity */
421 #define MAX_ADJUSTMENT 10
422 
423 static int
get_clock(__u32 * clock_high,__u32 * clock_low,__u16 * ret_clock_seq)424 get_clock(__u32 * clock_high, __u32 * clock_low, __u16 * ret_clock_seq)
425 {
426     static int adjustment = 0;
427     static struct timeval last = { 0, 0 };
428     static __u16 clock_seq;
429     struct timeval tv;
430     unsigned longlong clock_reg;
431 
432   try_again:
433     gettimeofday(&tv, 0);
434     if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
435         get_random_bytes(&clock_seq, sizeof(clock_seq));
436         clock_seq &= 0x1FFF;
437         last = tv;
438         last.tv_sec--;
439     }
440     if ((tv.tv_sec < last.tv_sec) || ((tv.tv_sec == last.tv_sec) && (tv.tv_usec < last.tv_usec))) {
441         clock_seq = (clock_seq + 1) & 0x1FFF;
442         adjustment = 0;
443         last = tv;
444     } else if ((tv.tv_sec == last.tv_sec) && (tv.tv_usec == last.tv_usec)) {
445         if (adjustment >= MAX_ADJUSTMENT)
446             goto try_again;
447         adjustment++;
448     } else {
449         adjustment = 0;
450         last = tv;
451     }
452 
453     clock_reg = tv.tv_usec * 10 + adjustment;
454     clock_reg += ((unsigned longlong)tv.tv_sec) * 10000000;
455     clock_reg += (((unsigned longlong)0x01B21DD2) << 32) + 0x13814000;
456 
457     *clock_high = clock_reg >> 32;
458     *clock_low = clock_reg;
459     *ret_clock_seq = clock_seq;
460     return 0;
461 }
462 
463 /* create a new uuid, based on randomness */
464 void
uuid_generate_random(uuid_t out)465 uuid_generate_random(uuid_t out)
466 {
467     uuid_t buf;
468     struct uuid uu;
469 
470     get_random_bytes(buf, sizeof(buf));
471     uuid_unpack(buf, &uu);
472 
473     uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
474     uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000;
475     uuid_pack(&uu, out);
476 }
477 
478 /* create a new uuid, based on time */
479 static void
uuid_generate_time(uuid_t out)480 uuid_generate_time(uuid_t out)
481 {
482     static unsigned char node_id[6];
483     static int has_init = 0;
484     struct uuid uu;
485     __u32 clock_mid;
486 
487     if (!has_init) {
488         if (get_node_id(node_id) <= 0) {
489             get_random_bytes(node_id, 6);
490             /*
491              * Set multicast bit, to prevent conflicts
492              * with IEEE 802 addresses obtained from
493              * network cards
494              */
495             node_id[0] |= 0x80;
496         }
497         has_init = 1;
498     }
499     get_clock(&clock_mid, &uu.time_low, &uu.clock_seq);
500     uu.clock_seq |= 0x8000;
501     uu.time_mid = (__u16) clock_mid;
502     uu.time_hi_and_version = (clock_mid >> 16) | 0x1000;
503     memcpy(uu.node, node_id, 6);
504     uuid_pack(&uu, out);
505 }
506 
507 void
uuid_generate(uuid_t out)508 uuid_generate(uuid_t out)
509 {
510     if (get_random_fd() >= 0) {
511         uuid_generate_random(out);
512     } else {
513         uuid_generate_time(out);
514     }
515 }
516