Kannel: Open Source WAP and SMS gateway  svn-r5335
gw_uuid.c
Go to the documentation of this file.
1 /*
2  * clear.c -- Clear a UUID
3  *
4  * Copyright (C) 1996, 1997 Theodore Ts'o.
5  *
6  * %Begin-Header%
7  * This file may be redistributed under the terms of the GNU
8  * Library General Public License.
9  * %End-Header%
10  */
11 
12 /*
13  * Force inclusion of SVID stuff since we need it if we're compiling in
14  * gcc-wall wall mode
15  */
16 #ifndef _SVID_SOURCE
17 #define _SVID_SOURCE
18 #endif
19 
20 #include "gw-config.h"
21 
22 #ifdef HAVE_UNISTD_H
23 #include <unistd.h>
24 #endif
25 #ifdef HAVE_STDLIB_H
26 #include <stdlib.h>
27 #endif
28 #include <string.h>
29 #include <ctype.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <sys/time.h>
34 #include <sys/stat.h>
35 #include <sys/file.h>
36 #ifdef HAVE_SYS_IOCTL_H
37 #include <sys/ioctl.h>
38 #endif
39 #ifdef HAVE_SYS_SOCKET_H
40 #include <sys/socket.h>
41 #endif
42 #ifdef HAVE_SYS_SOCKIO_H
43 #include <sys/sockio.h>
44 #endif
45 #ifdef HAVE_NET_IF_H
46 #include <net/if.h>
47 #endif
48 #ifdef HAVE_NETINET_IN_H
49 #include <netinet/in.h>
50 #endif
51 #include <stdio.h>
52 
53 #include "gwlib/gw_uuid_types.h"
54 #include "gwlib/gw_uuid.h"
55 
56 /*
57  * Offset between 15-Oct-1582 and 1-Jan-70
58  */
59 #define TIME_OFFSET_HIGH 0x01B21DD2
60 #define TIME_OFFSET_LOW 0x13814000
61 
62 struct uuid {
63  __u32 time_low;
64  __u16 time_mid;
66  __u16 clock_seq;
67  __u8 node[6];
68 };
69 
70 
71 /*
72  * prototypes
73  */
74 static void uuid_pack(const struct uuid *uu, uuid_t ptr);
75 static void uuid_unpack(const uuid_t in, struct uuid *uu);
76 static int get_random_fd(void);
77 
78 
79 #ifdef HAVE_SRANDOM
80 #define srand(x) srandom(x)
81 #define rand() random()
82 #endif
83 
84 
85 
86 void uuid_init(void)
87 {
88  /*
89  * open random device if any.
90  * We should do it here because otherwise it's
91  * possible that we open device twice.
92  */
93  get_random_fd();
94 }
95 
96 
97 void uuid_shutdown(void)
98 {
99  int fd = get_random_fd();
100 
101  if (fd > 0)
102  close(fd);
103 }
104 
106 {
107  memset(uu, 0, 16);
108 }
109 
110 /*
111  * compare.c --- compare whether or not two UUID's are the same
112  *
113  * Returns an integer less than, equal to, or greater than zero if
114  * uu1 respectively, to be less than, to match, or be greater than
115  * uu2.
116  *
117  * Copyright (C) 1996, 1997 Theodore Ts'o.
118  *
119  * %Begin-Header%
120  * This file may be redistributed under the terms of the GNU
121  * Library General Public License.
122  * %End-Header%
123  */
124 #define UUCMP(u1,u2) if (u1 != u2) return((u1 < u2) ? -1 : 1);
125 
126 int uuid_compare(const uuid_t uu1, const uuid_t uu2)
127 {
128  struct uuid uuid1, uuid2;
129 
130  uuid_unpack(uu1, &uuid1);
131  uuid_unpack(uu2, &uuid2);
132 
133  UUCMP(uuid1.time_low, uuid2.time_low);
134  UUCMP(uuid1.time_mid, uuid2.time_mid);
136  UUCMP(uuid1.clock_seq, uuid2.clock_seq);
137  return memcmp(uuid1.node, uuid2.node, 6);
138 }
139 
140 /*
141  * copy.c --- copy UUIDs
142  *
143  * Copyright (C) 1996, 1997 Theodore Ts'o.
144  *
145  * %Begin-Header%
146  * This file may be redistributed under the terms of the GNU
147  * Library General Public License.
148  * %End-Header%
149  */
150 void uuid_copy(uuid_t dst, const uuid_t src)
151 {
152  unsigned char *cp1;
153  const unsigned char *cp2;
154  int i;
155 
156  for (i=0, cp1 = dst, cp2 = src; i < 16; i++)
157  *cp1++ = *cp2++;
158 }
159 
160 
161 /*
162  * gen_uuid.c --- generate a DCE-compatible uuid
163  *
164  * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o.
165  *
166  * %Begin-Header%
167  * This file may be redistributed under the terms of the GNU
168  * Library General Public License.
169  * %End-Header%
170  */
171 static int get_random_fd(void)
172 {
173  struct timeval tv;
174  static int fd = -2;
175  int i;
176 
177  if (fd == -2) {
178  gettimeofday(&tv, 0);
179  fd = open("/dev/urandom", O_RDONLY);
180  if (fd == -1)
181  fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
182  srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec);
183  }
184  /* Crank the random number generator a few times */
185  gettimeofday(&tv, 0);
186  for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--)
187  rand();
188 
189  return fd;
190 }
191 
192 
193 /*
194  * Generate a series of random bytes. Use /dev/urandom if possible,
195  * and if not, use srandom/random.
196  */
197 static void get_random_bytes(void *buf, int nbytes)
198 {
199  int i, n = nbytes, fd = get_random_fd();
200  int lose_counter = 0;
201  unsigned char *cp = (unsigned char *) buf;
202 
203  if (fd >= 0) {
204  while (n > 0) {
205  i = read(fd, cp, n);
206  if (i <= 0) {
207  if (lose_counter++ > 16)
208  break;
209  continue;
210  }
211  n -= i;
212  cp += i;
213  lose_counter = 0;
214  }
215  }
216 
217  /*
218  * We do this all the time, but this is the only source of
219  * randomness if /dev/random/urandom is out to lunch.
220  */
221  for (cp = buf, i = 0; i < nbytes; i++)
222  *cp++ ^= (rand() >> 7) & 0xFF;
223  return;
224 }
225 
226 /*
227  * Get the ethernet hardware address, if we can find it...
228  */
229 static int get_node_id(unsigned char *node_id)
230 {
231 #ifdef HAVE_NET_IF_H
232  int sd;
233  struct ifreq ifr, *ifrp;
234  struct ifconf ifc;
235  char buf[1024];
236  int n, i;
237  unsigned char *a;
238 
239 /*
240  * BSD 4.4 defines the size of an ifreq to be
241  * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
242  * However, under earlier systems, sa_len isn't present, so the size is
243  * just sizeof(struct ifreq)
244  */
245 #ifdef HAVE_SA_LEN
246 #ifndef max
247 #define max(a,b) ((a) > (b) ? (a) : (b))
248 #endif
249 #define ifreq_size(i) max(sizeof(struct ifreq),\
250  sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
251 #else
252 #define ifreq_size(i) sizeof(struct ifreq)
253 #endif /* HAVE_SA_LEN*/
254 
255  sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
256  if (sd < 0) {
257  return -1;
258  }
259  memset(buf, 0, sizeof(buf));
260  ifc.ifc_len = sizeof(buf);
261  ifc.ifc_buf = buf;
262  if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
263  close(sd);
264  return -1;
265  }
266  n = ifc.ifc_len;
267  for (i = 0; i < n; i+= ifreq_size(*ifr) ) {
268  ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
269  strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
270  /* Solaris 11 defines SIOCGIFHWADDR, but has no ifr_hwaddr member */
271 #if defined(SIOCGIFHWADDR) && !defined(__sun__)
272  if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
273  continue;
274  a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
275 #else
276 #ifdef SIOCGENADDR
277  if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
278  continue;
279  a = (unsigned char *) ifr.ifr_enaddr;
280 #else
281  /*
282  * XXX we don't have a way of getting the hardware
283  * address
284  */
285  close(sd);
286  return 0;
287 #endif /* SIOCGENADDR */
288 #endif /* SIOCGIFHWADDR */
289  if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
290  continue;
291  if (node_id) {
292  memcpy(node_id, a, 6);
293  close(sd);
294  return 1;
295  }
296  }
297  close(sd);
298 #endif
299  return 0;
300 }
301 
302 /* Assume that the gettimeofday() has microsecond granularity */
303 #define MAX_ADJUSTMENT 10
304 
305 static int get_clock(__u32 *clock_high, __u32 *clock_low, __u16 *ret_clock_seq)
306 {
307  static int adjustment = 0;
308  static struct timeval last = {0, 0};
309  static __u16 clock_seq;
310  struct timeval tv;
311  unsigned long long clock_reg;
312 
313 try_again:
314  gettimeofday(&tv, 0);
315  if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
316  get_random_bytes(&clock_seq, sizeof(clock_seq));
317  clock_seq &= 0x1FFF;
318  last = tv;
319  last.tv_sec--;
320  }
321  if ((tv.tv_sec < last.tv_sec) ||
322  ((tv.tv_sec == last.tv_sec) &&
323  (tv.tv_usec < last.tv_usec))) {
324  clock_seq = (clock_seq+1) & 0x1FFF;
325  adjustment = 0;
326  last = tv;
327  } else if ((tv.tv_sec == last.tv_sec) &&
328  (tv.tv_usec == last.tv_usec)) {
329  if (adjustment >= MAX_ADJUSTMENT)
330  goto try_again;
331  adjustment++;
332  } else {
333  adjustment = 0;
334  last = tv;
335  }
336 
337  clock_reg = tv.tv_usec*10 + adjustment;
338  clock_reg += ((unsigned long long) tv.tv_sec)*10000000;
339  clock_reg += (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000;
340 
341  *clock_high = clock_reg >> 32;
342  *clock_low = clock_reg;
343  *ret_clock_seq = clock_seq;
344  return 0;
345 }
346 
348 {
349  static unsigned char node_id[6];
350  static int has_init = 0;
351  struct uuid uu;
352  __u32 clock_mid;
353 
354  if (!has_init) {
355  if (get_node_id(node_id) <= 0) {
356  get_random_bytes(node_id, 6);
357  /*
358  * Set multicast bit, to prevent conflicts
359  * with IEEE 802 addresses obtained from
360  * network cards
361  */
362  node_id[0] |= 0x80;
363  }
364  has_init = 1;
365  }
366  get_clock(&clock_mid, &uu.time_low, &uu.clock_seq);
367  uu.clock_seq |= 0x8000;
368  uu.time_mid = (__u16) clock_mid;
369  uu.time_hi_and_version = (clock_mid >> 16) | 0x1000;
370  memcpy(uu.node, node_id, 6);
371  uuid_pack(&uu, out);
372 }
373 
375 {
376  uuid_t buf;
377  struct uuid uu;
378 
379  get_random_bytes(buf, sizeof(buf));
380  uuid_unpack(buf, &uu);
381 
382  uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
383  uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000;
384  uuid_pack(&uu, out);
385 }
386 
387 /*
388  * This is the generic front-end to uuid_generate_random and
389  * uuid_generate_time. It uses uuid_generate_random only if
390  * /dev/urandom is available, since otherwise we won't have
391  * high-quality randomness.
392  */
394 {
395  if (get_random_fd() >= 0) {
397  }
398  else
399  uuid_generate_time(out);
400 }
401 
402 /*
403  * isnull.c --- Check whether or not the UUID is null
404  *
405  * Copyright (C) 1996, 1997 Theodore Ts'o.
406  *
407  * %Begin-Header%
408  * This file may be redistributed under the terms of the GNU
409  * Library General Public License.
410  * %End-Header%
411  */
412 /* Returns 1 if the uuid is the NULL uuid */
413 int uuid_is_null(const uuid_t uu)
414 {
415  const unsigned char *cp;
416  int i;
417 
418  for (i=0, cp = uu; i < 16; i++)
419  if (*cp++)
420  return 0;
421  return 1;
422 }
423 
424 /*
425  * Internal routine for packing UUID's
426  *
427  * Copyright (C) 1996, 1997 Theodore Ts'o.
428  *
429  * %Begin-Header%
430  * This file may be redistributed under the terms of the GNU
431  * Library General Public License.
432  * %End-Header%
433  */
434 void uuid_pack(const struct uuid *uu, uuid_t ptr)
435 {
436  __u32 tmp;
437  unsigned char *out = ptr;
438 
439  tmp = uu->time_low;
440  out[3] = (unsigned char) tmp;
441  tmp >>= 8;
442  out[2] = (unsigned char) tmp;
443  tmp >>= 8;
444  out[1] = (unsigned char) tmp;
445  tmp >>= 8;
446  out[0] = (unsigned char) tmp;
447 
448  tmp = uu->time_mid;
449  out[5] = (unsigned char) tmp;
450  tmp >>= 8;
451  out[4] = (unsigned char) tmp;
452 
453  tmp = uu->time_hi_and_version;
454  out[7] = (unsigned char) tmp;
455  tmp >>= 8;
456  out[6] = (unsigned char) tmp;
457 
458  tmp = uu->clock_seq;
459  out[9] = (unsigned char) tmp;
460  tmp >>= 8;
461  out[8] = (unsigned char) tmp;
462 
463  memcpy(out+10, uu->node, 6);
464 }
465 
466 /*
467  * parse.c --- UUID parsing
468  *
469  * Copyright (C) 1996, 1997 Theodore Ts'o.
470  *
471  * %Begin-Header%
472  * This file may be redistributed under the terms of the GNU
473  * Library General Public License.
474  * %End-Header%
475  */
476 int uuid_parse(const char *in, uuid_t uu)
477 {
478  struct uuid uuid;
479  int i;
480  const char *cp;
481  char buf[3];
482 
483  if (strlen(in) != 36)
484  return -1;
485  for (i=0, cp = in; i <= 36; i++,cp++) {
486  if ((i == 8) || (i == 13) || (i == 18) ||
487  (i == 23)) {
488  if (*cp == '-')
489  continue;
490  else
491  return -1;
492  }
493  if (i== 36)
494  if (*cp == 0)
495  continue;
496  if (!isxdigit(*cp))
497  return -1;
498  }
499  uuid.time_low = strtoul(in, NULL, 16);
500  uuid.time_mid = strtoul(in+9, NULL, 16);
501  uuid.time_hi_and_version = strtoul(in+14, NULL, 16);
502  uuid.clock_seq = strtoul(in+19, NULL, 16);
503  cp = in+24;
504  buf[2] = 0;
505  for (i=0; i < 6; i++) {
506  buf[0] = *cp++;
507  buf[1] = *cp++;
508  uuid.node[i] = strtoul(buf, NULL, 16);
509  }
510 
511  uuid_pack(&uuid, uu);
512  return 0;
513 }
514 
515 
516 /*
517  * Internal routine for unpacking UUID
518  *
519  * Copyright (C) 1996, 1997 Theodore Ts'o.
520  *
521  * %Begin-Header%
522  * This file may be redistributed under the terms of the GNU
523  * Library General Public License.
524  * %End-Header%
525  */
526 void uuid_unpack(const uuid_t in, struct uuid *uu)
527 {
528  const __u8 *ptr = in;
529  __u32 tmp;
530 
531  tmp = *ptr++;
532  tmp = (tmp << 8) | *ptr++;
533  tmp = (tmp << 8) | *ptr++;
534  tmp = (tmp << 8) | *ptr++;
535  uu->time_low = tmp;
536 
537  tmp = *ptr++;
538  tmp = (tmp << 8) | *ptr++;
539  uu->time_mid = tmp;
540 
541  tmp = *ptr++;
542  tmp = (tmp << 8) | *ptr++;
543  uu->time_hi_and_version = tmp;
544 
545  tmp = *ptr++;
546  tmp = (tmp << 8) | *ptr++;
547  uu->clock_seq = tmp;
548 
549  memcpy(uu->node, ptr, 6);
550 }
551 
552 /*
553  * unparse.c -- convert a UUID to string
554  *
555  * Copyright (C) 1996, 1997 Theodore Ts'o.
556  *
557  * %Begin-Header%
558  * This file may be redistributed under the terms of the GNU
559  * Library General Public License.
560  * %End-Header%
561  */
562 void uuid_unparse(const uuid_t uu, char *out)
563 {
564  struct uuid uuid;
565 
566  uuid_unpack(uu, &uuid);
567  sprintf(out,
568  "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
570  uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
571  uuid.node[0], uuid.node[1], uuid.node[2],
572  uuid.node[3], uuid.node[4], uuid.node[5]);
573 }
574 
575 /*
576  * uuid_time.c --- Interpret the time field from a uuid. This program
577  * violates the UUID abstraction barrier by reaching into the guts
578  * of a UUID and interpreting it.
579  *
580  * Copyright (C) 1998, 1999 Theodore Ts'o.
581  *
582  * %Begin-Header%
583  * This file may be redistributed under the terms of the GNU
584  * Library General Public License.
585  * %End-Header%
586  */
587 time_t uuid_time(const uuid_t uu, struct timeval *ret_tv)
588 {
589  struct uuid uuid;
590  __u32 high;
591  struct timeval tv;
592  unsigned long long clock_reg;
593 
594  uuid_unpack(uu, &uuid);
595 
596  high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
597  clock_reg = uuid.time_low | ((unsigned long long) high << 32);
598 
599  clock_reg -= (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000;
600  tv.tv_sec = clock_reg / 10000000;
601  tv.tv_usec = (clock_reg % 10000000) / 10;
602 
603  if (ret_tv)
604  *ret_tv = tv;
605 
606  return tv.tv_sec;
607 }
608 
609 int uuid_type(const uuid_t uu)
610 {
611  struct uuid uuid;
612 
613  uuid_unpack(uu, &uuid);
614  return ((uuid.time_hi_and_version >> 12) & 0xF);
615 }
616 
617 int uuid_variant(const uuid_t uu)
618 {
619  struct uuid uuid;
620  int var;
621 
622  uuid_unpack(uu, &uuid);
623  var = uuid.clock_seq;
624 
625  if ((var & 0x8000) == 0)
626  return UUID_VARIANT_NCS;
627  if ((var & 0x4000) == 0)
628  return UUID_VARIANT_DCE;
629  if ((var & 0x2000) == 0)
630  return UUID_VARIANT_MICROSOFT;
631  return UUID_VARIANT_OTHER;
632 }
633 
#define MAX_ADJUSTMENT
Definition: gw_uuid.c:303
void uuid_generate_time(uuid_t out)
Definition: gw_uuid.c:347
__u16 clock_seq
Definition: gw_uuid.c:66
int uuid_type(const uuid_t uu)
Definition: gw_uuid.c:609
static int get_clock(__u32 *clock_high, __u32 *clock_low, __u16 *ret_clock_seq)
Definition: gw_uuid.c:305
int uuid_variant(const uuid_t uu)
Definition: gw_uuid.c:617
void uuid_unparse(const uuid_t uu, char *out)
Definition: gw_uuid.c:562
void uuid_generate(uuid_t out)
Definition: gw_uuid.c:393
__u16 time_mid
Definition: gw_uuid.c:64
void uuid_init(void)
Definition: gw_uuid.c:86
__u8 node[6]
Definition: gw_uuid.c:67
static int get_node_id(unsigned char *node_id)
Definition: gw_uuid.c:229
__u16 time_hi_and_version
Definition: gw_uuid.c:65
static void uuid_unpack(const uuid_t in, struct uuid *uu)
Definition: gw_uuid.c:526
int uuid_parse(const char *in, uuid_t uu)
Definition: gw_uuid.c:476
__u32 time_low
Definition: gw_uuid.c:63
Definition: gw_uuid.c:62
#define UUID_VARIANT_DCE
Definition: gw_uuid.h:38
#define UUID_VARIANT_MICROSOFT
Definition: gw_uuid.h:39
static void get_random_bytes(void *buf, int nbytes)
Definition: gw_uuid.c:197
int uuid_is_null(const uuid_t uu)
Definition: gw_uuid.c:413
#define UUID_VARIANT_NCS
Definition: gw_uuid.h:37
void uuid_copy(uuid_t dst, const uuid_t src)
Definition: gw_uuid.c:150
int uuid_compare(const uuid_t uu1, const uuid_t uu2)
Definition: gw_uuid.c:126
void uuid_shutdown(void)
Definition: gw_uuid.c:97
static int get_random_fd(void)
Definition: gw_uuid.c:171
time_t uuid_time(const uuid_t uu, struct timeval *ret_tv)
Definition: gw_uuid.c:587
void uuid_generate_random(uuid_t out)
Definition: gw_uuid.c:374
#define rand()
Definition: protected.h:100
static void uuid_pack(const struct uuid *uu, uuid_t ptr)
Definition: gw_uuid.c:434
#define UUID_VARIANT_OTHER
Definition: gw_uuid.h:40
unsigned char uuid_t[16]
Definition: gw_uuid.h:32
#define UUCMP(u1, u2)
Definition: gw_uuid.c:124
void uuid_clear(uuid_t uu)
Definition: gw_uuid.c:105
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.