1 /* uuid.c -- Universally Unique Identifier routines */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2000-2018 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( HAVE_UUID_GENERATE )
45 # include <uuid/uuid.h>
46 #elif defined( _WIN32 )
49 # include <ac/socket.h>
51 # ifdef HAVE_SYS_SYSCTL_H
53 # include <sys/sysctl.h>
54 # include <net/route.h>
60 /* not needed for Windows */
61 #if !defined(HAVE_UUID_TO_STR) && !defined(HAVE_UUID_GENERATE) && !defined(_WIN32)
62 static unsigned char *
65 static unsigned char zero[6];
66 static unsigned char eaddr[6];
68 #ifdef HAVE_SYS_SYSCTL_H
71 char *buf, *next, *lim;
72 struct if_msghdr *ifm;
73 struct sockaddr_dl *sdl;
75 if (memcmp(eaddr, zero, sizeof(eaddr))) {
83 mib[4] = NET_RT_IFLIST;
86 if (sysctl(mib, sizeof(mib), NULL, &needed, NULL, 0) < 0) {
91 if( buf == NULL ) return NULL;
93 if (sysctl(mib, sizeof(mib), buf, &needed, NULL, 0) < 0) {
99 for (next = buf; next < lim; next += ifm->ifm_msglen) {
100 ifm = (struct if_msghdr *)next;
101 sdl = (struct sockaddr_dl *)(ifm + 1);
103 if ( sdl->sdl_family != AF_LINK || sdl->sdl_alen == 6 ) {
105 (unsigned char *)sdl->sdl_data + sdl->sdl_nlen,
115 #elif defined( SIOCGIFADDR ) && defined( AFLINK )
116 char buf[sizeof(struct ifreq) * 32];
120 struct sockaddr_dl *sdl;
124 if (memcmp(eaddr, zero, sizeof(eaddr))) {
128 s = socket( AF_INET, SOCK_DGRAM, 0 );
133 ifc.ifc_len = sizeof( buf );
135 memset( buf, 0, sizeof( buf ) );
137 i = ioctl( s, SIOCGIFCONF, (char *)&ifc );
144 for ( i = 0; i < ifc.ifc_len; ) {
145 ifr = (struct ifreq *)&ifc.ifc_buf[i];
148 if ( sa->sa_len > sizeof( ifr->ifr_addr ) ) {
149 i += sizeof( ifr->ifr_name ) + sa->sa_len;
154 if ( sa->sa_family != AF_LINK ) {
158 sdl = (struct sockaddr_dl *)sa;
160 if ( sdl->sdl_alen == 6 ) {
162 (unsigned char *)sdl->sdl_data + sdl->sdl_nlen,
171 if (memcmp(eaddr, zero, sizeof(eaddr)) == 0) {
172 /* XXX - who knows? */
173 lutil_entropy( eaddr, sizeof(eaddr) );
174 eaddr[0] |= 0x01; /* turn it into a multicast address */
181 #if (ULONG_MAX >> 31 >> 31) > 1 || defined HAVE_LONG_LONG
183 #if (ULONG_MAX >> 31 >> 31) > 1
184 typedef unsigned long UI64;
185 /* 100 usec intervals from 10/10/1582 to 1/1/1970 */
186 # define UUID_TPLUS 0x01B21DD2138140ul
188 typedef unsigned long long UI64;
189 # define UUID_TPLUS 0x01B21DD2138140ull
192 #define high32(i) ((unsigned long) ((i) >> 32))
193 #define low32(i) ((unsigned long) (i) & 0xFFFFFFFFul)
194 #define set_add64(res, i) ((res) += (i))
195 #define set_add64l(res, i) ((res) += (i))
196 #define mul64ll(i1, i2) ((UI64) (i1) * (i2))
198 #else /* ! (ULONG_MAX >= 64 bits || HAVE_LONG_LONG) */
201 unsigned long high, low;
204 static const UI64 UUID_TPLUS = { 0x01B21Dul, 0xD2138140ul };
206 #define high32(i) ((i).high)
207 #define low32(i) ((i).low)
210 #define set_add64(res, ui64) \
212 res.high += ui64.high; \
213 res.low = (res.low + ui64.low) & 0xFFFFFFFFul; \
214 if (res.low < ui64.low) res.high++; \
218 #define set_add64l(res, ul32) \
220 res.low = (res.low + ul32) & 0xFFFFFFFFul; \
221 if (res.low < ul32) res.high++; \
224 /* compute i1 * i2 */
226 mul64ll(unsigned long i1, unsigned long i2)
228 const unsigned int high1 = (i1 >> 16), low1 = (i1 & 0xffff);
229 const unsigned int high2 = (i2 >> 16), low2 = (i2 & 0xffff);
234 res.high = (unsigned long) high1 * high2;
235 res.low = (unsigned long) low1 * low2;
237 tmp = (unsigned long) low1 * high2;
238 res.high += (tmp >> 16);
239 tmp = (tmp << 16) & 0xFFFFFFFFul;
240 res.low = (res.low + tmp) & 0xFFFFFFFFul;
244 tmp = (unsigned long) low2 * high1;
245 res.high += (tmp >> 16);
246 tmp = (tmp << 16) & 0xFFFFFFFFul;
247 res.low = (res.low + tmp) & 0xFFFFFFFFul;
254 #endif /* ULONG_MAX >= 64 bits || HAVE_LONG_LONG */
256 #endif /* !HAVE_UUID_TO_STR && !HAVE_UUID_GENERATE && !_WIN32 */
259 ** All we really care about is an ISO UUID string. The format of a UUID is:
261 ** time_low 0-3 low field of the timestamp
262 ** time_mid 4-5 middle field of timestamp
263 ** time_hi_and_version 6-7 high field of timestamp and
265 ** clock_seq_hi_and_resv 8 high field of clock sequence
267 ** clock_seq_low 9 low field of clock sequence
268 ** node 10-15 spacially unique identifier
270 ** We use DCE version one, and the DCE variant. Our unique identifier is
271 ** the first ethernet address on the system.
274 lutil_uuidstr( char *buf, size_t len )
276 #ifdef HAVE_UUID_TO_STR
282 uuid_create( &uu, &rc );
283 if ( rc != uuid_s_ok ) {
287 uuid_to_str( &uu, &s, &rc );
288 if ( rc != uuid_s_ok ) {
298 strncpy( buf, s, len );
303 #elif defined( HAVE_UUID_GENERATE )
307 uuid_unparse_lower( uu, buf );
308 return strlen( buf );
310 #elif defined( _WIN32 )
312 unsigned char *uuidstr;
315 if( UuidCreate( &uuid ) != RPC_S_OK ) {
319 if( UuidToString( &uuid, &uuidstr ) != RPC_S_OK ) {
323 uuidlen = strlen( uuidstr );
324 if( uuidlen >= len ) {
328 strncpy( buf, uuidstr, len );
329 RpcStringFree( &uuidstr );
337 unsigned short t2, t3, s1;
338 unsigned long t1, tl_high;
342 * Theoretically we should delay if seq wraps within 100usec but for now
343 * systems are not fast enough to worry about it.
345 static int inited = 0;
346 static unsigned short seq;
349 lutil_entropy( (unsigned char *) &seq, sizeof(seq) );
353 #ifdef HAVE_GETTIMEOFDAY
354 gettimeofday( &tv, 0 );
360 tl = mul64ll(tv.tv_sec, 10000000UL);
361 set_add64l(tl, tv.tv_usec * 10UL);
362 set_add64(tl, UUID_TPLUS);
366 t1 = low32(tl); /* time_low */
367 tl_high = high32(tl);
368 t2 = tl_high & 0xffff; /* time_mid */
369 t3 = ((tl_high >> 16) & 0x0fff) | 0x1000; /* time_hi_and_version */
370 s1 = ( ++seq & 0x1fff ) | 0x8000; /* clock_seq_and_reserved */
372 rc = snprintf( buf, len,
373 "%08lx-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
374 t1, (unsigned) t2, (unsigned) t3, (unsigned) s1,
375 (unsigned) nl[0], (unsigned) nl[1],
376 (unsigned) nl[2], (unsigned) nl[3],
377 (unsigned) nl[4], (unsigned) nl[5] );
379 return rc < len ? rc : 0;
384 lutil_uuidstr_from_normalized(
390 unsigned char nibble;
393 assert( uuid != NULL );
394 assert( buf != NULL );
396 if ( uuidlen != 16 ) return -1;
397 if ( buflen < 36 ) return -1;
399 for ( i = 0; i < 16; i++ ) {
400 if ( i == 4 || i == 6 || i == 8 || i == 10 ) {
405 nibble = (uuid[i] >> 4) & 0xF;
407 buf[(i<<1)+d] = nibble + '0';
409 buf[(i<<1)+d] = nibble - 10 + 'a';
412 nibble = (uuid[i]) & 0xF;
414 buf[(i<<1)+d+1] = nibble + '0';
416 buf[(i<<1)+d+1] = nibble - 10 + 'a';
420 if ( buflen > 36 ) buf[36] = '\0';
426 main(int argc, char **argv)
428 char buf1[8], buf2[64];
430 #ifndef HAVE_UUID_TO_STR
431 unsigned char *p = lutil_eaddr();
434 printf( "Ethernet Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
435 (unsigned) p[0], (unsigned) p[1], (unsigned) p[2],
436 (unsigned) p[3], (unsigned) p[4], (unsigned) p[5]);
440 if ( lutil_uuidstr( buf1, sizeof( buf1 ) ) ) {
441 printf( "UUID: %s\n", buf1 );
443 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf1 ) );
446 if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) {
447 printf( "UUID: %s\n", buf2 );
449 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) );
452 if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) {
453 printf( "UUID: %s\n", buf2 );
455 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) );