1/* uuid.c -- Universally Unique Identifier routines */
2/* $OpenLDAP$ */
3/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 2000-2011 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)
62static unsigned char *
63lutil_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
200typedef struct {
201	unsigned long high, low;
202} UI64;
203
204static 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 */
225static UI64
226mul64ll(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*/
273size_t
274lutil_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
383int
384lutil_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
425int
426main(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