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