2 * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
3 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6 * Copyright 2000, John E. Schimmel, All rights reserved.
7 * This software is not subject to any license of Mirapoint, Inc.
9 * This is free software; you can redistribute and use it
10 * under the same terms as OpenLDAP itself.
13 * Sorry this file is so scary, but it needs to run on a wide range of
14 * platforms. The only exported routine is lutil_uuidstr() which is all
15 * that LDAP cares about. It generates a new uuid and returns it in
22 #include <sys/types.h>
24 #include <ac/stdlib.h>
25 #include <ac/string.h> /* get memcmp() */
27 #ifdef HAVE_UUID_TO_STR
28 # include <sys/uuid.h>
29 #elif defined( _WIN32 )
32 # include <ac/socket.h>
34 # ifdef HAVE_SYS_SYSCTL_H
36 # include <sys/sysctl.h>
37 # include <net/route.h>
43 /* not needed for Windows */
44 #if !defined(HAVE_UUID_TO_STR) && !defined(_WIN32)
45 static unsigned char *
48 static unsigned char zero[6];
49 static unsigned char eaddr[6];
51 #ifdef HAVE_SYS_SYSCTL_H
54 char *buf, *next, *lim;
55 struct if_msghdr *ifm;
56 struct sockaddr_dl *sdl;
58 if (memcmp(eaddr, zero, sizeof(eaddr))) {
66 mib[4] = NET_RT_IFLIST;
69 if (sysctl(mib, sizeof(mib), NULL, &needed, NULL, 0) < 0) {
74 if( buf == NULL ) return NULL;
76 if (sysctl(mib, sizeof(mib), buf, &needed, NULL, 0) < 0) {
82 for (next = buf; next < lim; next += ifm->ifm_msglen) {
83 ifm = (struct if_msghdr *)next;
84 sdl = (struct sockaddr_dl *)(ifm + 1);
86 if ( sdl->sdl_family != AF_LINK || sdl->sdl_alen == 6 ) {
88 (unsigned char *)sdl->sdl_data + sdl->sdl_nlen,
98 #elif defined( SIOCGIFADDR ) && defined( AFLINK )
99 char buf[sizeof(struct ifreq) * 32];
103 struct sockaddr_dl *sdl;
107 if (memcmp(eaddr, zero, sizeof(eaddr))) {
111 s = socket( AF_INET, SOCK_DGRAM, 0 );
116 ifc.ifc_len = sizeof( buf );
118 memset( buf, 0, sizeof( buf ) );
120 i = ioctl( s, SIOCGIFCONF, (char *)&ifc );
127 for ( i = 0; i < ifc.ifc_len; ) {
128 ifr = (struct ifreq *)&ifc.ifc_buf[i];
131 if ( sa->sa_len > sizeof( ifr->ifr_addr ) ) {
132 i += sizeof( ifr->ifr_name ) + sa->sa_len;
137 if ( sa->sa_family != AF_LINK ) {
141 sdl = (struct sockaddr_dl *)sa;
143 if ( sdl->sdl_alen == 6 ) {
145 (unsigned char *)sdl->sdl_data + sdl->sdl_nlen,
154 if (memcmp(eaddr, zero, sizeof(eaddr)) == 0) {
155 /* XXX - who knows? */
156 lutil_entropy( eaddr, sizeof(eaddr) );
157 eaddr[0] |= 0x80; /* turn it into a multicast address */
164 #if (ULONG_MAX >> 31 >> 31) > 1 || defined HAVE_LONG_LONG
166 #if (ULONG_MAX >> 31 >> 31) > 1
167 typedef unsigned long UI64;
168 /* 100 usec intervals from 10/10/1582 to 1/1/1970 */
169 # define UUID_TPLUS 0x01B21DD2138140ul
171 typedef unsigned long long UI64;
172 # define UUID_TPLUS 0x01B21DD2138140ull
175 #define high32(i) ((unsigned long) ((i) >> 32))
176 #define low32(i) ((unsigned long) (i) & 0xFFFFFFFFul)
177 #define set_add64(res, i) ((res) += (i))
178 #define set_add64l(res, i) ((res) += (i))
179 #define mul64ll(i1, i2) ((UI64) (i1) * (i2))
181 #else /* ! (ULONG_MAX >= 64 bits || HAVE_LONG_LONG) */
184 unsigned long high, low;
187 static const UI64 UUID_TPLUS = { 0x01B21Dul, 0xD2138140ul };
189 #define high32(i) ((i).high)
190 #define low32(i) ((i).low)
193 #define set_add64(res, ui64) \
195 res.high += ui64.high; \
196 res.low = (res.low + ui64.low) & 0xFFFFFFFFul; \
197 if (res.low < ui64.low) res.high++; \
201 #define set_add64l(res, ul32) \
203 res.low = (res.low + ul32) & 0xFFFFFFFFul; \
204 if (res.low < ul32) res.high++; \
207 /* compute i1 * i2 */
209 mul64ll(unsigned long i1, unsigned long i2)
211 const unsigned int high1 = (i1 >> 16), low1 = (i1 & 0xffff);
212 const unsigned int high2 = (i2 >> 16), low2 = (i2 & 0xffff);
217 res.high = (unsigned long) high1 * high2;
218 res.low = (unsigned long) low1 * low2;
220 tmp = (unsigned long) low1 * high2;
221 res.high += (tmp >> 16);
222 tmp = (tmp << 16) & 0xFFFFFFFFul;
223 res.low = (res.low + tmp) & 0xFFFFFFFFul;
227 tmp = (unsigned long) low2 * high1;
228 res.high += (tmp >> 16);
229 tmp = (tmp << 16) & 0xFFFFFFFFul;
230 res.low = (res.low + tmp) & 0xFFFFFFFFul;
237 #endif /* ULONG_MAX >= 64 bits || HAVE_LONG_LONG */
239 #endif /* !HAVE_UUID_TO_STR && !_WIN32 */
242 ** All we really care about is an ISO UUID string. The format of a UUID is:
244 ** time_low 0-3 low field of the timestamp
245 ** time_mid 4-5 middle field of timestamp
246 ** time_hi_and_version 6-7 high field of timestamp and
248 ** clock_seq_hi_and_resv 8 high field of clock sequence
250 ** clock_seq_low 9 low field of clock sequence
251 ** node 10-15 spacially unique identifier
253 ** We use DCE version one, and the DCE variant. Our unique identifier is
254 ** the first ethernet address on the system.
257 lutil_uuidstr( char *buf, size_t len )
259 #ifdef HAVE_UUID_TO_STR
265 uuid_create( &uu, &rc );
266 if ( rc != uuid_s_ok ) {
270 uuid_to_str( &uu, &s, &rc );
271 if ( rc != uuid_s_ok ) {
281 strncpy( buf, s, len );
286 #elif defined( _WIN32 )
288 unsigned char *uuidstr;
291 if( UuidCreate( &uuid ) != RPC_S_OK ) {
295 if( UuidToString( &uuid, &uuidstr ) != RPC_S_OK ) {
299 uuidlen = strlen( uuidstr );
300 if( uuidlen >= len ) {
304 strncpy( buf, uuidstr, len );
305 RpcStringFree( &uuidstr );
313 unsigned short t2, t3, s1;
314 unsigned long t1, tl_high;
318 * Theoretically we should delay if seq wraps within 100usec but for now
319 * systems are not fast enough to worry about it.
321 static int inited = 0;
322 static unsigned short seq;
325 lutil_entropy( (unsigned char *) &seq, sizeof(seq) );
329 #ifdef HAVE_GETTIMEOFDAY
330 gettimeofday( &tv, 0 );
336 tl = mul64ll(tv.tv_sec, 10000000UL);
337 set_add64l(tl, tv.tv_usec * 10UL);
338 set_add64(tl, UUID_TPLUS);
342 t1 = low32(tl); /* time_low */
343 tl_high = high32(tl);
344 t2 = tl_high & 0xffff; /* time_mid */
345 t3 = ((tl_high >> 16) & 0x0fff) | 0x1000; /* time_hi_and_version */
346 s1 = ( ++seq & 0x1fff ) | 0x8000; /* clock_seq_and_reserved */
348 rc = snprintf( buf, len,
349 "%08lx-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
350 t1, (unsigned) t2, (unsigned) t3, (unsigned) s1,
351 (unsigned) nl[0], (unsigned) nl[1],
352 (unsigned) nl[2], (unsigned) nl[3],
353 (unsigned) nl[4], (unsigned) nl[5] );
355 return rc < len ? rc : 0;
361 main(int argc, char **argv)
363 char buf1[8], buf2[64];
365 #ifndef HAVE_UUID_TO_STR
366 unsigned char *p = lutil_eaddr();
369 printf( "Ethernet Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
370 (unsigned) p[0], (unsigned) p[1], (unsigned) p[2],
371 (unsigned) p[3], (unsigned) p[4], (unsigned) p[5]);
375 if ( lutil_uuidstr( buf1, sizeof( buf1 ) ) ) {
376 printf( "UUID: %s\n", buf1 );
378 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf1 ) );
381 if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) {
382 printf( "UUID: %s\n", buf2 );
384 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) );
387 if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) {
388 printf( "UUID: %s\n", buf2 );
390 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) );