1/* 2 * gen_uuid.c --- generate a DCE-compatible uuid 3 * 4 * Copyright (C) 1996, 1997, 1998, 1999 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#define _SVID_SOURCE 17 18#ifdef HAVE_UNISTD_H 19#include <unistd.h> 20#endif 21#ifdef HAVE_STDLIB_H 22#include <stdlib.h> 23#endif 24#include <string.h> 25#include <fcntl.h> 26#include <errno.h> 27#include <sys/types.h> 28#include <sys/time.h> 29#include <sys/stat.h> 30#include <sys/file.h> 31#ifdef HAVE_SYS_IOCTL_H 32#include <sys/ioctl.h> 33#endif 34#ifdef HAVE_SYS_SOCKET_H 35#include <sys/socket.h> 36#endif 37#ifdef HAVE_SYS_SOCKIO_H 38#include <sys/sockio.h> 39#endif 40#ifdef HAVE_NET_IF_H 41#include <net/if.h> 42#endif 43#ifdef HAVE_NETINET_IN_H 44#include <netinet/in.h> 45#endif 46 47#include "uuidP.h" 48//#include "uuid.h" 49#ifdef HAVE_SRANDOM 50#define srand(x) srandom(x) 51#define rand() random() 52#endif 53 54static int get_random_fd(void) 55{ 56 struct timeval tv; 57 static int fd = -2; 58 int i; 59 60 if (fd == -2) { 61 gettimeofday(&tv, 0); 62 fd = open("/dev/urandom", O_RDONLY); 63 if (fd == -1) 64 fd = open("/dev/random", O_RDONLY | O_NONBLOCK); 65 srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); 66 } 67 /* Crank the random number generator a few times */ 68 gettimeofday(&tv, 0); 69 for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) 70 rand(); 71 return fd; 72} 73 74 75/* 76 * Generate a series of random bytes. Use /dev/urandom if possible, 77 * and if not, use srandom/random. 78 */ 79static void get_random_bytes(void *buf, int nbytes) 80{ 81 int i, n = nbytes, fd = get_random_fd(); 82 int lose_counter = 0; 83 unsigned char *cp = (unsigned char *) buf; 84 85 if (fd >= 0) { 86 while (n > 0) { 87 i = read(fd, cp, n); 88 if (i <= 0) { 89 if (lose_counter++ > 16) 90 break; 91 continue; 92 } 93 n -= i; 94 cp += i; 95 lose_counter = 0; 96 } 97 } 98 99 /* 100 * We do this all the time, but this is the only source of 101 * randomness if /dev/random/urandom is out to lunch. 102 */ 103 for (cp = buf, i = 0; i < nbytes; i++) 104 *cp++ ^= (rand() >> 7) & 0xFF; 105 return; 106} 107 108/* 109 * Get the ethernet hardware address, if we can find it... 110 */ 111static int get_node_id(unsigned char *node_id) 112{ 113#ifdef HAVE_NET_IF_H 114 int sd; 115 struct ifreq ifr, *ifrp; 116 struct ifconf ifc; 117 char buf[1024]; 118 int n, i; 119 unsigned char *a; 120 121/* 122 * BSD 4.4 defines the size of an ifreq to be 123 * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len 124 * However, under earlier systems, sa_len isn't present, so the size is 125 * just sizeof(struct ifreq) 126 */ 127#ifdef HAVE_SA_LEN 128#ifndef max 129#define max(a,b) ((a) > (b) ? (a) : (b)) 130#endif 131#define ifreq_size(i) max(sizeof(struct ifreq),\ 132 sizeof((i).ifr_name)+(i).ifr_addr.sa_len) 133#else 134#define ifreq_size(i) sizeof(struct ifreq) 135#endif /* HAVE_SA_LEN*/ 136 137 sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); 138 if (sd < 0) { 139 return -1; 140 } 141 memset(buf, 0, sizeof(buf)); 142 ifc.ifc_len = sizeof(buf); 143 ifc.ifc_buf = buf; 144 if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) { 145 close(sd); 146 return -1; 147 } 148 n = ifc.ifc_len; 149 for (i = 0; i < n; i+= ifreq_size(*ifr) ) { 150 ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i); 151 strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); 152#ifdef SIOCGIFHWADDR 153 if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) 154 continue; 155 a = (unsigned char *) &ifr.ifr_hwaddr.sa_data; 156#else 157#ifdef SIOCGENADDR 158 if (ioctl(sd, SIOCGENADDR, &ifr) < 0) 159 continue; 160 a = (unsigned char *) ifr.ifr_enaddr; 161#else 162 /* 163 * XXX we don't have a way of getting the hardware 164 * address 165 */ 166 close(sd); 167 return 0; 168#endif /* SIOCGENADDR */ 169#endif /* SIOCGIFHWADDR */ 170 if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) 171 continue; 172 if (node_id) { 173 memcpy(node_id, a, 6); 174 close(sd); 175 return 1; 176 } 177 } 178 close(sd); 179#endif 180 return 0; 181} 182 183/* Assume that the gettimeofday() has microsecond granularity */ 184#define MAX_ADJUSTMENT 10 185 186static int get_clock(__u32 *clock_high, __u32 *clock_low, __u16 *ret_clock_seq) 187{ 188 static int adjustment = 0; 189 static struct timeval last = {0, 0}; 190 static __u16 clock_seq; 191 struct timeval tv; 192 unsigned long long clock_reg; 193 194try_again: 195 gettimeofday(&tv, 0); 196 if ((last.tv_sec == 0) && (last.tv_usec == 0)) { 197 get_random_bytes(&clock_seq, sizeof(clock_seq)); 198 clock_seq &= 0x1FFF; 199 last = tv; 200 last.tv_sec--; 201 } 202 if ((tv.tv_sec < last.tv_sec) || 203 ((tv.tv_sec == last.tv_sec) && 204 (tv.tv_usec < last.tv_usec))) { 205 clock_seq = (clock_seq+1) & 0x1FFF; 206 adjustment = 0; 207 last = tv; 208 } else if ((tv.tv_sec == last.tv_sec) && 209 (tv.tv_usec == last.tv_usec)) { 210 if (adjustment >= MAX_ADJUSTMENT) 211 goto try_again; 212 adjustment++; 213 } else { 214 adjustment = 0; 215 last = tv; 216 } 217 218 clock_reg = tv.tv_usec*10 + adjustment; 219 clock_reg += ((unsigned long long) tv.tv_sec)*10000000; 220 clock_reg += (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000; 221 222 *clock_high = clock_reg >> 32; 223 *clock_low = clock_reg; 224 *ret_clock_seq = clock_seq; 225 return 0; 226} 227 228void uuid_generate_time(uuid_t out) 229{ 230 static unsigned char node_id[6]; 231 static int has_init = 0; 232 struct uuid uu; 233 __u32 clock_mid; 234 235 if (!has_init) { 236 if (get_node_id(node_id) <= 0) { 237 get_random_bytes(node_id, 6); 238 /* 239 * Set multicast bit, to prevent conflicts 240 * with IEEE 802 addresses obtained from 241 * network cards 242 */ 243 node_id[0] |= 0x80; 244 } 245 has_init = 1; 246 } 247 get_clock(&clock_mid, &uu.time_low, &uu.clock_seq); 248 uu.clock_seq |= 0x8000; 249 uu.time_mid = (__u16) clock_mid; 250 uu.time_hi_and_version = (clock_mid >> 16) | 0x1000; 251 memcpy(uu.node, node_id, 6); 252 uuid_pack(&uu, out); 253} 254 255void uuid_generate_random(uuid_t out) 256{ 257 uuid_t buf; 258 struct uuid uu; 259 260 get_random_bytes(buf, sizeof(buf)); 261 uuid_unpack(buf, &uu); 262 263 uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000; 264 uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000; 265 uuid_pack(&uu, out); 266} 267 268/* 269 * This is the generic front-end to uuid_generate_random and 270 * uuid_generate_time. It uses uuid_generate_random only if 271 * /dev/urandom is available, since otherwise we won't have 272 * high-quality randomness. 273 */ 274void uuid_generate(uuid_t out) 275{ 276 if (get_random_fd() >= 0) 277 uuid_generate_random(out); 278 else 279 uuid_generate_time(out); 280} 281