1 /* uuid.c -- Universally Unique Identifier routines */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2000-2005 The OpenLDAP Foundation.
6 * Portions Copyright 2000-2003 Kurt D. Zeilenga.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
17 /* Portions Copyright 2000, John E. Schimmel, All rights reserved.
18 * This software is not subject to any license of Mirapoint, Inc.
20 * This is free software; you can redistribute and use it
21 * under the same terms as OpenLDAP itself.
23 /* This work was initially developed by John E. Schimmel and adapted
24 * for inclusion in OpenLDAP Software by Kurt D. Zeilenga.
28 * Sorry this file is so scary, but it needs to run on a wide range of
29 * platforms. The only exported routine is lutil_uuidstr() which is all
30 * that LDAP cares about. It generates a new uuid and returns it in
37 #include <sys/types.h>
39 #include <ac/stdlib.h>
40 #include <ac/string.h> /* get memcmp() */
42 #ifdef HAVE_UUID_TO_STR
43 # include <sys/uuid.h>
44 #elif defined( _WIN32 )
47 # include <ac/socket.h>
49 # ifdef HAVE_SYS_SYSCTL_H
51 # include <sys/sysctl.h>
52 # include <net/route.h>
58 /* not needed for Windows */
59 #if !defined(HAVE_UUID_TO_STR) && !defined(_WIN32)
60 static unsigned char *
63 static unsigned char zero[6];
64 static unsigned char eaddr[6];
66 #ifdef HAVE_SYS_SYSCTL_H
69 char *buf, *next, *lim;
70 struct if_msghdr *ifm;
71 struct sockaddr_dl *sdl;
73 if (memcmp(eaddr, zero, sizeof(eaddr))) {
81 mib[4] = NET_RT_IFLIST;
84 if (sysctl(mib, sizeof(mib), NULL, &needed, NULL, 0) < 0) {
89 if( buf == NULL ) return NULL;
91 if (sysctl(mib, sizeof(mib), buf, &needed, NULL, 0) < 0) {
97 for (next = buf; next < lim; next += ifm->ifm_msglen) {
98 ifm = (struct if_msghdr *)next;
99 sdl = (struct sockaddr_dl *)(ifm + 1);
101 if ( sdl->sdl_family != AF_LINK || sdl->sdl_alen == 6 ) {
103 (unsigned char *)sdl->sdl_data + sdl->sdl_nlen,
113 #elif defined( SIOCGIFADDR ) && defined( AFLINK )
114 char buf[sizeof(struct ifreq) * 32];
118 struct sockaddr_dl *sdl;
122 if (memcmp(eaddr, zero, sizeof(eaddr))) {
126 s = socket( AF_INET, SOCK_DGRAM, 0 );
131 ifc.ifc_len = sizeof( buf );
133 memset( buf, 0, sizeof( buf ) );
135 i = ioctl( s, SIOCGIFCONF, (char *)&ifc );
142 for ( i = 0; i < ifc.ifc_len; ) {
143 ifr = (struct ifreq *)&ifc.ifc_buf[i];
146 if ( sa->sa_len > sizeof( ifr->ifr_addr ) ) {
147 i += sizeof( ifr->ifr_name ) + sa->sa_len;
152 if ( sa->sa_family != AF_LINK ) {
156 sdl = (struct sockaddr_dl *)sa;
158 if ( sdl->sdl_alen == 6 ) {
160 (unsigned char *)sdl->sdl_data + sdl->sdl_nlen,
169 if (memcmp(eaddr, zero, sizeof(eaddr)) == 0) {
170 /* XXX - who knows? */
171 lutil_entropy( eaddr, sizeof(eaddr) );
172 eaddr[0] |= 0x01; /* turn it into a multicast address */
179 #if (ULONG_MAX >> 31 >> 31) > 1 || defined HAVE_LONG_LONG
181 #if (ULONG_MAX >> 31 >> 31) > 1
182 typedef unsigned long UI64;
183 /* 100 usec intervals from 10/10/1582 to 1/1/1970 */
184 # define UUID_TPLUS 0x01B21DD2138140ul
186 typedef unsigned long long UI64;
187 # define UUID_TPLUS 0x01B21DD2138140ull
190 #define high32(i) ((unsigned long) ((i) >> 32))
191 #define low32(i) ((unsigned long) (i) & 0xFFFFFFFFul)
192 #define set_add64(res, i) ((res) += (i))
193 #define set_add64l(res, i) ((res) += (i))
194 #define mul64ll(i1, i2) ((UI64) (i1) * (i2))
196 #else /* ! (ULONG_MAX >= 64 bits || HAVE_LONG_LONG) */
199 unsigned long high, low;
202 static const UI64 UUID_TPLUS = { 0x01B21Dul, 0xD2138140ul };
204 #define high32(i) ((i).high)
205 #define low32(i) ((i).low)
208 #define set_add64(res, ui64) \
210 res.high += ui64.high; \
211 res.low = (res.low + ui64.low) & 0xFFFFFFFFul; \
212 if (res.low < ui64.low) res.high++; \
216 #define set_add64l(res, ul32) \
218 res.low = (res.low + ul32) & 0xFFFFFFFFul; \
219 if (res.low < ul32) res.high++; \
222 /* compute i1 * i2 */
224 mul64ll(unsigned long i1, unsigned long i2)
226 const unsigned int high1 = (i1 >> 16), low1 = (i1 & 0xffff);
227 const unsigned int high2 = (i2 >> 16), low2 = (i2 & 0xffff);
232 res.high = (unsigned long) high1 * high2;
233 res.low = (unsigned long) low1 * low2;
235 tmp = (unsigned long) low1 * high2;
236 res.high += (tmp >> 16);
237 tmp = (tmp << 16) & 0xFFFFFFFFul;
238 res.low = (res.low + tmp) & 0xFFFFFFFFul;
242 tmp = (unsigned long) low2 * high1;
243 res.high += (tmp >> 16);
244 tmp = (tmp << 16) & 0xFFFFFFFFul;
245 res.low = (res.low + tmp) & 0xFFFFFFFFul;
252 #endif /* ULONG_MAX >= 64 bits || HAVE_LONG_LONG */
254 #endif /* !HAVE_UUID_TO_STR && !_WIN32 */
257 ** All we really care about is an ISO UUID string. The format of a UUID is:
259 ** time_low 0-3 low field of the timestamp
260 ** time_mid 4-5 middle field of timestamp
261 ** time_hi_and_version 6-7 high field of timestamp and
263 ** clock_seq_hi_and_resv 8 high field of clock sequence
265 ** clock_seq_low 9 low field of clock sequence
266 ** node 10-15 spacially unique identifier
268 ** We use DCE version one, and the DCE variant. Our unique identifier is
269 ** the first ethernet address on the system.
272 lutil_uuidstr( char *buf, size_t len )
274 #ifdef HAVE_UUID_TO_STR
280 uuid_create( &uu, &rc );
281 if ( rc != uuid_s_ok ) {
285 uuid_to_str( &uu, &s, &rc );
286 if ( rc != uuid_s_ok ) {
296 strncpy( buf, s, len );
301 #elif defined( _WIN32 )
303 unsigned char *uuidstr;
306 if( UuidCreate( &uuid ) != RPC_S_OK ) {
310 if( UuidToString( &uuid, &uuidstr ) != RPC_S_OK ) {
314 uuidlen = strlen( uuidstr );
315 if( uuidlen >= len ) {
319 strncpy( buf, uuidstr, len );
320 RpcStringFree( &uuidstr );
328 unsigned short t2, t3, s1;
329 unsigned long t1, tl_high;
333 * Theoretically we should delay if seq wraps within 100usec but for now
334 * systems are not fast enough to worry about it.
336 static int inited = 0;
337 static unsigned short seq;
340 lutil_entropy( (unsigned char *) &seq, sizeof(seq) );
344 #ifdef HAVE_GETTIMEOFDAY
345 gettimeofday( &tv, 0 );
351 tl = mul64ll(tv.tv_sec, 10000000UL);
352 set_add64l(tl, tv.tv_usec * 10UL);
353 set_add64(tl, UUID_TPLUS);
357 t1 = low32(tl); /* time_low */
358 tl_high = high32(tl);
359 t2 = tl_high & 0xffff; /* time_mid */
360 t3 = ((tl_high >> 16) & 0x0fff) | 0x1000; /* time_hi_and_version */
361 s1 = ( ++seq & 0x1fff ) | 0x8000; /* clock_seq_and_reserved */
363 rc = snprintf( buf, len,
364 "%08lx-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
365 t1, (unsigned) t2, (unsigned) t3, (unsigned) s1,
366 (unsigned) nl[0], (unsigned) nl[1],
367 (unsigned) nl[2], (unsigned) nl[3],
368 (unsigned) nl[4], (unsigned) nl[5] );
370 return rc < len ? rc : 0;
376 main(int argc, char **argv)
378 char buf1[8], buf2[64];
380 #ifndef HAVE_UUID_TO_STR
381 unsigned char *p = lutil_eaddr();
384 printf( "Ethernet Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
385 (unsigned) p[0], (unsigned) p[1], (unsigned) p[2],
386 (unsigned) p[3], (unsigned) p[4], (unsigned) p[5]);
390 if ( lutil_uuidstr( buf1, sizeof( buf1 ) ) ) {
391 printf( "UUID: %s\n", buf1 );
393 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf1 ) );
396 if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) {
397 printf( "UUID: %s\n", buf2 );
399 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) );
402 if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) {
403 printf( "UUID: %s\n", buf2 );
405 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) );