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