xref: /netbsd-src/external/bsd/openldap/dist/libraries/liblutil/uuid.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
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