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