1 /* $NetBSD: uuid.c,v 1.3 2021/08/14 16:14:58 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-2021 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.3 2021/08/14 16:14:58 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 *
lutil_eaddr(void)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
mul64ll(unsigned long i1,unsigned long i2)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
lutil_uuidstr(char * buf,size_t len)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
lutil_uuidstr_from_normalized(char * uuid,size_t uuidlen,char * buf,size_t buflen)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
main(int argc,char ** argv)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