xref: /netbsd-src/external/bsd/openldap/dist/libraries/liblutil/uuid.c (revision 271138cb3a6de667c600b54c1d0896e7b41a929b)
1 /* uuid.c -- Universally Unique Identifier routines */
2 /* $OpenLDAP: pkg/ldap/libraries/liblutil/uuid.c,v 1.28.2.3 2008/02/11 23:26:42 kurt Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2008 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)
62 static unsigned char *
63 lutil_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 
200 typedef struct {
201 	unsigned long high, low;
202 } UI64;
203 
204 static 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 */
225 static UI64
226 mul64ll(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 */
273 size_t
274 lutil_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 
383 int
384 lutil_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
425 int
426 main(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