1/* uuid.c -- Universally Unique Identifier routines */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 2000-2011 The OpenLDAP Foundation. 6 * Portions Copyright 2000-2003 Kurt D. Zeilenga. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 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>. 16 */ 17/* Portions Copyright 2000, John E. Schimmel, All rights reserved. 18 * This software is not subject to any license of Mirapoint, Inc. 19 * 20 * This is free software; you can redistribute and use it 21 * under the same terms as OpenLDAP itself. 22 */ 23/* This work was initially developed by John E. Schimmel and adapted 24 * for inclusion in OpenLDAP Software by Kurt D. Zeilenga. 25 */ 26 27/* 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 31 * in string form. 32 */ 33#include "portable.h" 34 35#include <limits.h> 36#include <stdio.h> 37#include <sys/types.h> 38 39#include <ac/stdlib.h> 40#include <ac/string.h> /* get memcmp() */ 41 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 ) 47# include <rpc.h> 48#else 49# include <ac/socket.h> 50# include <ac/time.h> 51# ifdef HAVE_SYS_SYSCTL_H 52# include <net/if.h> 53# include <sys/sysctl.h> 54# include <net/route.h> 55# endif 56#endif 57 58#include <lutil.h> 59 60/* not needed for Windows */ 61#if !defined(HAVE_UUID_TO_STR) && !defined(HAVE_UUID_GENERATE) && !defined(_WIN32) 62static unsigned char * 63lutil_eaddr( void ) 64{ 65 static unsigned char zero[6]; 66 static unsigned char eaddr[6]; 67 68#ifdef HAVE_SYS_SYSCTL_H 69 size_t needed; 70 int mib[6]; 71 char *buf, *next, *lim; 72 struct if_msghdr *ifm; 73 struct sockaddr_dl *sdl; 74 75 if (memcmp(eaddr, zero, sizeof(eaddr))) { 76 return eaddr; 77 } 78 79 mib[0] = CTL_NET; 80 mib[1] = PF_ROUTE; 81 mib[3] = 0; 82 mib[3] = 0; 83 mib[4] = NET_RT_IFLIST; 84 mib[5] = 0; 85 86 if (sysctl(mib, sizeof(mib), NULL, &needed, NULL, 0) < 0) { 87 return NULL; 88 } 89 90 buf = malloc(needed); 91 if( buf == NULL ) return NULL; 92 93 if (sysctl(mib, sizeof(mib), buf, &needed, NULL, 0) < 0) { 94 free(buf); 95 return NULL; 96 } 97 98 lim = buf + needed; 99 for (next = buf; next < lim; next += ifm->ifm_msglen) { 100 ifm = (struct if_msghdr *)next; 101 sdl = (struct sockaddr_dl *)(ifm + 1); 102 103 if ( sdl->sdl_family != AF_LINK || sdl->sdl_alen == 6 ) { 104 AC_MEMCPY(eaddr, 105 (unsigned char *)sdl->sdl_data + sdl->sdl_nlen, 106 sizeof(eaddr)); 107 free(buf); 108 return eaddr; 109 } 110 } 111 112 free(buf); 113 return NULL; 114 115#elif defined( SIOCGIFADDR ) && defined( AFLINK ) 116 char buf[sizeof(struct ifreq) * 32]; 117 struct ifconf ifc; 118 struct ifreq *ifr; 119 struct sockaddr *sa; 120 struct sockaddr_dl *sdl; 121 unsigned char *p; 122 int s, i; 123 124 if (memcmp(eaddr, zero, sizeof(eaddr))) { 125 return eaddr; 126 } 127 128 s = socket( AF_INET, SOCK_DGRAM, 0 ); 129 if ( s < 0 ) { 130 return NULL; 131 } 132 133 ifc.ifc_len = sizeof( buf ); 134 ifc.ifc_buf = buf; 135 memset( buf, 0, sizeof( buf ) ); 136 137 i = ioctl( s, SIOCGIFCONF, (char *)&ifc ); 138 close( s ); 139 140 if( i < 0 ) { 141 return NULL; 142 } 143 144 for ( i = 0; i < ifc.ifc_len; ) { 145 ifr = (struct ifreq *)&ifc.ifc_buf[i]; 146 sa = &ifr->ifr_addr; 147 148 if ( sa->sa_len > sizeof( ifr->ifr_addr ) ) { 149 i += sizeof( ifr->ifr_name ) + sa->sa_len; 150 } else { 151 i += sizeof( *ifr ); 152 } 153 154 if ( sa->sa_family != AF_LINK ) { 155 continue; 156 } 157 158 sdl = (struct sockaddr_dl *)sa; 159 160 if ( sdl->sdl_alen == 6 ) { 161 AC_MEMCPY(eaddr, 162 (unsigned char *)sdl->sdl_data + sdl->sdl_nlen, 163 sizeof(eaddr)); 164 return eaddr; 165 } 166 } 167 168 return NULL; 169 170#else 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 */ 175 } 176 177 return eaddr; 178#endif 179} 180 181#if (ULONG_MAX >> 31 >> 31) > 1 || defined HAVE_LONG_LONG 182 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 187#else 188 typedef unsigned long long UI64; 189# define UUID_TPLUS 0x01B21DD2138140ull 190#endif 191 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)) 197 198#else /* ! (ULONG_MAX >= 64 bits || HAVE_LONG_LONG) */ 199 200typedef struct { 201 unsigned long high, low; 202} UI64; 203 204static const UI64 UUID_TPLUS = { 0x01B21Dul, 0xD2138140ul }; 205 206#define high32(i) ((i).high) 207#define low32(i) ((i).low) 208 209/* res += ui64 */ 210#define set_add64(res, ui64) \ 211{ \ 212 res.high += ui64.high; \ 213 res.low = (res.low + ui64.low) & 0xFFFFFFFFul; \ 214 if (res.low < ui64.low) res.high++; \ 215} 216 217/* res += ul32 */ 218#define set_add64l(res, ul32) \ 219{ \ 220 res.low = (res.low + ul32) & 0xFFFFFFFFul; \ 221 if (res.low < ul32) res.high++; \ 222} 223 224/* compute i1 * i2 */ 225static UI64 226mul64ll(unsigned long i1, unsigned long i2) 227{ 228 const unsigned int high1 = (i1 >> 16), low1 = (i1 & 0xffff); 229 const unsigned int high2 = (i2 >> 16), low2 = (i2 & 0xffff); 230 231 UI64 res; 232 unsigned long tmp; 233 234 res.high = (unsigned long) high1 * high2; 235 res.low = (unsigned long) low1 * low2; 236 237 tmp = (unsigned long) low1 * high2; 238 res.high += (tmp >> 16); 239 tmp = (tmp << 16) & 0xFFFFFFFFul; 240 res.low = (res.low + tmp) & 0xFFFFFFFFul; 241 if (res.low < tmp) 242 res.high++; 243 244 tmp = (unsigned long) low2 * high1; 245 res.high += (tmp >> 16); 246 tmp = (tmp << 16) & 0xFFFFFFFFul; 247 res.low = (res.low + tmp) & 0xFFFFFFFFul; 248 if (res.low < tmp) 249 res.high++; 250 251 return res; 252} 253 254#endif /* ULONG_MAX >= 64 bits || HAVE_LONG_LONG */ 255 256#endif /* !HAVE_UUID_TO_STR && !HAVE_UUID_GENERATE && !_WIN32 */ 257 258/* 259** All we really care about is an ISO UUID string. The format of a UUID is: 260** field octet note 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 264** version number 265** clock_seq_hi_and_resv 8 high field of clock sequence 266** and variant 267** clock_seq_low 9 low field of clock sequence 268** node 10-15 spacially unique identifier 269** 270** We use DCE version one, and the DCE variant. Our unique identifier is 271** the first ethernet address on the system. 272*/ 273size_t 274lutil_uuidstr( char *buf, size_t len ) 275{ 276#ifdef HAVE_UUID_TO_STR 277 uuid_t uu = {0}; 278 unsigned rc; 279 char *s; 280 size_t l; 281 282 uuid_create( &uu, &rc ); 283 if ( rc != uuid_s_ok ) { 284 return 0; 285 } 286 287 uuid_to_str( &uu, &s, &rc ); 288 if ( rc != uuid_s_ok ) { 289 return 0; 290 } 291 292 l = strlen( s ); 293 if ( l >= len ) { 294 free( s ); 295 return 0; 296 } 297 298 strncpy( buf, s, len ); 299 free( s ); 300 301 return l; 302 303#elif defined( HAVE_UUID_GENERATE ) 304 uuid_t uu; 305 306 uuid_generate( uu ); 307 uuid_unparse_lower( uu, buf ); 308 return strlen( buf ); 309 310#elif defined( _WIN32 ) 311 UUID uuid; 312 unsigned char *uuidstr; 313 size_t uuidlen; 314 315 if( UuidCreate( &uuid ) != RPC_S_OK ) { 316 return 0; 317 } 318 319 if( UuidToString( &uuid, &uuidstr ) != RPC_S_OK ) { 320 return 0; 321 } 322 323 uuidlen = strlen( uuidstr ); 324 if( uuidlen >= len ) { 325 return 0; 326 } 327 328 strncpy( buf, uuidstr, len ); 329 RpcStringFree( &uuidstr ); 330 331 return uuidlen; 332 333#else 334 struct timeval tv; 335 UI64 tl; 336 unsigned char *nl; 337 unsigned short t2, t3, s1; 338 unsigned long t1, tl_high; 339 unsigned int rc; 340 341 /* 342 * Theoretically we should delay if seq wraps within 100usec but for now 343 * systems are not fast enough to worry about it. 344 */ 345 static int inited = 0; 346 static unsigned short seq; 347 348 if (!inited) { 349 lutil_entropy( (unsigned char *) &seq, sizeof(seq) ); 350 inited++; 351 } 352 353#ifdef HAVE_GETTIMEOFDAY 354 gettimeofday( &tv, 0 ); 355#else 356 time( &tv.tv_sec ); 357 tv.tv_usec = 0; 358#endif 359 360 tl = mul64ll(tv.tv_sec, 10000000UL); 361 set_add64l(tl, tv.tv_usec * 10UL); 362 set_add64(tl, UUID_TPLUS); 363 364 nl = lutil_eaddr(); 365 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 */ 371 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] ); 378 379 return rc < len ? rc : 0; 380#endif 381} 382 383int 384lutil_uuidstr_from_normalized( 385 char *uuid, 386 size_t uuidlen, 387 char *buf, 388 size_t buflen ) 389{ 390 unsigned char nibble; 391 int i, d = 0; 392 393 assert( uuid != NULL ); 394 assert( buf != NULL ); 395 396 if ( uuidlen != 16 ) return -1; 397 if ( buflen < 36 ) return -1; 398 399 for ( i = 0; i < 16; i++ ) { 400 if ( i == 4 || i == 6 || i == 8 || i == 10 ) { 401 buf[(i<<1)+d] = '-'; 402 d += 1; 403 } 404 405 nibble = (uuid[i] >> 4) & 0xF; 406 if ( nibble < 10 ) { 407 buf[(i<<1)+d] = nibble + '0'; 408 } else { 409 buf[(i<<1)+d] = nibble - 10 + 'a'; 410 } 411 412 nibble = (uuid[i]) & 0xF; 413 if ( nibble < 10 ) { 414 buf[(i<<1)+d+1] = nibble + '0'; 415 } else { 416 buf[(i<<1)+d+1] = nibble - 10 + 'a'; 417 } 418 } 419 420 if ( buflen > 36 ) buf[36] = '\0'; 421 return 36; 422} 423 424#ifdef TEST 425int 426main(int argc, char **argv) 427{ 428 char buf1[8], buf2[64]; 429 430#ifndef HAVE_UUID_TO_STR 431 unsigned char *p = lutil_eaddr(); 432 433 if( p ) { 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]); 437 } 438#endif 439 440 if ( lutil_uuidstr( buf1, sizeof( buf1 ) ) ) { 441 printf( "UUID: %s\n", buf1 ); 442 } else { 443 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf1 ) ); 444 } 445 446 if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) { 447 printf( "UUID: %s\n", buf2 ); 448 } else { 449 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) ); 450 } 451 452 if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) { 453 printf( "UUID: %s\n", buf2 ); 454 } else { 455 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) ); 456 } 457 458 return 0; 459} 460#endif 461