2 * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
3 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6 * Copyright 2000, John E. Schimmel, All rights reserved.
7 * This software is not subject to any license of Mirapoint, Inc.
9 * This is free software; you can redistribute and use it
10 * under the same terms as OpenLDAP itself.
13 * Sorry this file is so scary, but it needs to run on a wide range of
14 * platforms. The only exported routine is lutil_uuidstr() which is all
15 * that LDAP cares about. It generates a new uuid and returns it in
21 #include <sys/types.h>
23 #include <ac/stdlib.h>
24 #include <ac/string.h> /* get memcmp() */
26 #ifdef HAVE_UUID_TO_STR
27 # include <sys/uuid.h>
28 #elif defined( _WIN32 )
31 # include <ac/socket.h>
34 /* 100 usec intervals from 10/10/1582 to 1/1/1970 */
35 # define UUID_TPLUS 0x01B21DD2138140LL
37 # ifdef HAVE_SYS_SYSCTL_H
39 # include <sys/sysctl.h>
40 # include <net/route.h>
46 /* not needed for Windows */
47 #if !defined(HAVE_UUID_TO_STR) && !defined(_WIN32)
48 static unsigned char *
51 static unsigned char zero[6];
52 static unsigned char eaddr[6];
54 #ifdef HAVE_SYS_SYSCTL_H
57 char *buf, *next, *lim;
58 struct if_msghdr *ifm;
59 struct sockaddr_dl *sdl;
61 if (memcmp(eaddr, zero, sizeof(eaddr))) {
69 mib[4] = NET_RT_IFLIST;
72 if (sysctl(mib, sizeof(mib), NULL, &needed, NULL, 0) < 0) {
77 if( buf == NULL ) return NULL;
79 if (sysctl(mib, sizeof(mib), buf, &needed, NULL, 0) < 0) {
85 for (next = buf; next < lim; next += ifm->ifm_msglen) {
86 ifm = (struct if_msghdr *)next;
87 sdl = (struct sockaddr_dl *)(ifm + 1);
89 if ( sdl->sdl_family != AF_LINK || sdl->sdl_alen == 6 ) {
91 (unsigned char *)sdl->sdl_data + sdl->sdl_nlen,
101 #elif defined( SIOCGIFADDR ) && defined( AFLINK )
102 char buf[sizeof(struct ifreq) * 32];
106 struct sockaddr_dl *sdl;
110 if (memcmp(eaddr, zero, sizeof(eaddr))) {
114 s = socket( AF_INET, SOCK_DGRAM, 0 );
119 ifc.ifc_len = sizeof( buf );
121 memset( buf, 0, sizeof( buf ) );
123 i = ioctl( s, SIOCGIFCONF, (char *)&ifc );
130 for ( i = 0; i < ifc.ifc_len; ) {
131 ifr = (struct ifreq *)&ifc.ifc_buf[i];
134 if ( sa->sa_len > sizeof( ifr->ifr_addr ) ) {
135 i += sizeof( ifr->ifr_name ) + sa->sa_len;
140 if ( sa->sa_family != AF_LINK ) {
144 sdl = (struct sockaddr_dl *)sa;
146 if ( sdl->sdl_alen == 6 ) {
148 (unsigned char *)sdl->sdl_data + sdl->sdl_nlen,
157 if (memcmp(eaddr, zero, sizeof(eaddr)) == 0) {
158 /* XXX - who knows? */
159 lutil_entropy( eaddr, sizeof(eaddr) );
160 eaddr[0] |= 0x80; /* turn it into a multicast address */
169 ** All we really care about is an ISO UUID string. The format of a UUID is:
171 ** time_low 0-3 low field of the timestamp
172 ** time_mid 4-5 middle field of timestamp
173 ** time_hi_and_version 6-7 high field of timestamp and
175 ** clock_seq_hi_and_resv 8 high field of clock sequence
177 ** clock_seq_low 9 low field of clock sequence
178 ** node 10-15 spacially unique identifier
180 ** We use DCE version one, and the DCE variant. Our unique identifier is
181 ** the first ethernet address on the system.
184 lutil_uuidstr( char *buf, size_t len )
186 #ifdef HAVE_UUID_TO_STR
192 uuid_create( &uu, &rc );
193 if ( rc != uuid_s_ok ) {
197 uuid_to_str( &uu, &s, &rc );
198 if ( rc != uuid_s_ok ) {
208 strncpy( buf, s, len );
213 #elif defined( _WIN32 )
215 unsigned char *uuidstr;
218 if( UuidCreate( &uuid ) != RPC_S_OK ) {
222 if( UuidToString( &uuid, &uuidstr ) != RPC_S_OK ) {
226 uuidlen = strlen( uuidstr );
227 if( uuidlen >= len ) {
231 strncpy( buf, uuidstr, len );
232 RpcStringFree( &uuidstr );
238 unsigned long long tl;
240 unsigned short t2, t3, s1;
244 * Theoretically we should delay if seq wraps within 100usec but for now
245 * systems are not fast enough to worry about it.
247 static int inited = 0;
248 static unsigned short seq;
251 lutil_entropy( (unsigned char *) &seq, sizeof(seq) );
255 #ifdef HAVE_GETTIMEOFDAY
256 gettimeofday( &tv, 0 );
262 tl = ( tv.tv_sec * 10000000LL ) + ( tv.tv_usec * 10LL ) + UUID_TPLUS;
265 t1 = tl & 0xffffffff; /* time_low */
266 t2 = ( tl >> 32 ) & 0xffff; /* time_mid */
267 t3 = ( ( tl >> 48 ) & 0x0fff ) | 0x1000; /* time_hi_and_version */
268 s1 = ( ++seq & 0x1fff ) | 0x8000; /* clock_seq_and_reserved */
270 t1 = snprintf( buf, len,
271 "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
272 t1, (unsigned) t2, (unsigned) t3, (unsigned) s1,
273 (unsigned) nl[0], (unsigned) nl[1],
274 (unsigned) nl[2], (unsigned) nl[3],
275 (unsigned) nl[4], (unsigned) nl[5] );
277 return (0 < t1 && t1 < len) ? t1 : 0;
283 main(int argc, char **argv)
285 char buf1[8], buf2[64];
287 #ifndef HAVE_UUID_TO_STR
288 unsigned char *p = lutil_eaddr();
291 printf( "Ethernet Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
292 (unsigned) p[0], (unsigned) p[1], (unsigned) p[2],
293 (unsigned) p[3], (unsigned) p[4], (unsigned) p[5]);
297 if ( lutil_uuidstr( buf1, sizeof( buf1 ) ) ) {
298 printf( "UUID: %s\n", buf1 );
300 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf1 ) );
303 if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) {
304 printf( "UUID: %s\n", buf2 );
306 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) );
309 if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) {
310 printf( "UUID: %s\n", buf2 );
312 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) );