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