]> git.sur5r.net Git - openldap/commitdiff
Add UUID code from John E. Schimmel
authorKurt Zeilenga <kurt@openldap.org>
Wed, 5 Dec 2001 05:39:34 +0000 (05:39 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Wed, 5 Dec 2001 05:39:34 +0000 (05:39 +0000)
libraries/liblutil/Makefile.in
libraries/liblutil/uuid.c [new file with mode: 0644]

index f40e04c54c58c874b76d8cfadc7a94e98ee6b8d7..374d893e07e2cd50302ba3763f815db12afbd5d9 100644 (file)
@@ -14,11 +14,11 @@ UNIX_SRCS = detach.c
 UNIX_OBJS = detach.o
 
 SRCS   = base64.c debug.c entropy.c sasl.c signal.c hash.c \
-       md5.c passwd.c sha1.c getpass.c lockf.c utils.c sockpair.c \
+       md5.c passwd.c sha1.c getpass.c lockf.c utils.c uuid.c sockpair.c \
        @LIBSRCS@ $(@PLAT@_SRCS)
 
 OBJS   = base64.o debug.o entropy.o sasl.o signal.o hash.o \
-       md5.o passwd.o sha1.o getpass.o lockf.o utils.o sockpair.o \
+       md5.o passwd.o sha1.o getpass.o lockf.o utils.o uuid.o sockpair.o \
        @LIBOBJS@ $(@PLAT@_OBJS)
 
 LDAP_INCDIR= ../../include       
diff --git a/libraries/liblutil/uuid.c b/libraries/liblutil/uuid.c
new file mode 100644 (file)
index 0000000..22dc216
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+/* Portions
+ * Copyright 2000, John E. Schimmel, All rights reserved.
+ * This software is not subject to any license of Mirapoint, Inc.
+ *
+ * This is free software; you can redistribute and use it
+ * under the same terms as OpenLDAP itself.
+ */
+/* Adapted for incorporatation into OpenLDAP by Kurt Zeilenga */
+
+/*
+** Sorry this file is so scary, but it needs to run on a wide range of
+** platforms.  The only exported routine is lutil_uuidstr() which is all
+** that LDAP cares about.  It generates a new uuid and returns it in
+** in string form.
+*/
+#include "portable.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_UUID_H
+#  include <sys/uuid.h>
+#else
+#  include <ac/socket.h>
+#  include <sys/sockio.h>
+#  include <net/if_types.h>
+#  include <net/if.h>
+#  include <net/if_dl.h>
+#  ifdef HAVE_SYS_SYSCTL_H
+#    include <sys/sysctl.h>
+#    include <net/route.h>
+#  endif
+#endif
+
+/* 100 usec intervals from 10/10/1582 to 1/1/1970 */
+#define UUID_TPLUS     0x01B21DD2138140LL
+
+#ifndef HAVE_SYS_UUID_H
+static unsigned char *
+lutil_eaddr( void )
+{
+       static unsigned char zero[6];
+       static unsigned char eaddr[6];
+
+#ifdef HAVE_SYS_SYSCTL_H
+       size_t needed;
+       int mib[6];
+       char *buf, *next, *lim;
+       struct if_msghdr *ifm;
+       struct sockaddr_dl *sdl;
+
+       if (memcmp(eaddr, zero, sizeof(eaddr))) {
+               return eaddr;
+       }
+
+       mib[0] = CTL_NET;
+       mib[1] = PF_ROUTE;
+       mib[3] = 0;
+       mib[3] = 0;
+       mib[4] = NET_RT_IFLIST;
+       mib[5] = 0;
+
+       if (sysctl(mib, sizeof(mib), NULL, &needed, NULL, 0) < 0) {
+               return NULL;
+       }
+
+       buf = malloc(needed);
+       if( buf == NULL ) return NULL;
+
+       if (sysctl(mib, sizeof(mib), buf, &needed, NULL, 0) < 0) {
+               free(buf);
+               return NULL;
+       }
+
+       lim = buf + needed;
+       for (next = buf; next < lim; next += ifm->ifm_msglen) {
+               ifm = (struct if_msghdr *)next;
+               sdl = (struct sockaddr_dl *)(ifm + 1);
+
+               if ( sdl->sdl_family != AF_LINK || sdl->sdl_alen == 6 ) {
+                       memcpy(eaddr,
+                               (unsigned char *)sdl->sdl_data + sdl->sdl_nlen,
+                               sizeof(eaddr));
+                       free(buf);
+                       return eaddr;
+               }
+       }
+
+       free(buf);
+       return NULL;
+
+#elif defined (SIOCGIFADDR)
+       char buf[sizeof(struct ifreq) * 32];
+       struct ifconf ifc;
+       struct ifreq *ifr;
+       struct sockaddr *sa;
+       struct sockaddr_dl *sdl;
+       unsigned char *p;
+       int s, i;
+
+       if (memcmp(eaddr, zero, sizeof(eaddr))) {
+               return eaddr;
+       }
+
+       s = socket( AF_INET, SOCK_DGRAM, 0 );
+       if ( s < 0 ) {
+               return NULL;
+       }
+
+       ifc.ifc_len = sizeof( buf );
+       ifc.ifc_buf = buf;
+       memset( buf, 0, sizeof( buf ) );
+
+       i = ioctl( s, SIOCGIFCONF, (char *)&ifc );
+       close( s );
+
+       if( i < 0 ) {
+               return NULL;
+       }
+
+       for ( i = 0; i < ifc.ifc_len; ) {
+               ifr = (struct ifreq *)&ifc.ifc_buf[i];
+               sa = &ifr->ifr_addr;
+
+               if ( sa->sa_len > sizeof( ifr->ifr_addr ) ) {
+                       i += sizeof( ifr->ifr_name ) + sa->sa_len;
+               } else {
+                       i += sizeof( *ifr );
+               }
+
+               if ( sa->sa_family != AF_LINK ) {
+                       continue;
+               }
+
+               sdl = (struct sockaddr_dl *)sa;
+
+               if ( sdl->sdl_alen == 6 ) {
+                       memcpy(eaddr,
+                               (unsigned char *)sdl->sdl_data + sdl->sdl_nlen,
+                               sizeof(eaddr));
+                       return eaddr;
+               }
+       }
+
+       return NULL;
+
+#else
+       if (memcmp(eaddr, zero, sizeof(eaddr)) == 0) {
+               /* XXX - who knows? */
+               lutil_entropy( eaddr, sizeof(eaddr) );
+       }
+
+       return eaddr;
+#endif
+}
+#endif
+
+/*
+** All we really care about is an ISO UUID string.  The format of a UUID is:
+**     field                   octet           note
+**     time_low                0-3             low field of the timestamp
+**     time_mid                4-5             middle field of timestamp
+**     time_hi_and_version     6-7             high field of timestamp and
+**                                             version number
+**     clock_seq_hi_and_resv   8               high field of clock sequence
+**                                             and variant
+**     clock_seq_low           9               low field of clock sequence
+**     node                    10-15           spacially unique identifier
+**
+** We use DCE version one, and the DCE variant.  Our unique identifier is
+** the first ethernet address on the system.
+*/
+int
+lutil_uuidstr( char *buf, size_t len )
+{
+#ifdef HAVE_SYS_UUID_H
+       uuid_t uu = {0};
+       unsigned rc;
+       char *s;
+
+       uuid_create( &uu, &rc );
+       if ( rc != uuid_s_ok ) {
+               return 0;
+       }
+
+       uuid_to_str( &uu, &s, &rc );
+       if ( rc != uuid_s_ok ) {
+               return 0;
+       }
+       if ( strlen( s ) >= len ) {
+               free( s );
+               return 0;
+       }
+
+       strncpy( buf, s, len );
+       free( s );
+
+       return 1;
+
+#else
+       struct timeval tv;
+       unsigned long long tl;
+       unsigned char *nl;
+       unsigned short sq, t2, t3, s1, n1, n2, n3;
+       unsigned int t1;
+
+       /*
+        * Theoretically we should delay if seq wraps within 100usec but for now
+        * systems are not fast enough to worry about it.
+        */
+       static unsigned short seq = 0;
+
+#ifdef HAVE_GETTIMEOFDAY
+       gettimeofday( &tv, 0 );
+#else
+       time( &tv.tv_sec );
+       tv.tv_usec = 0;
+#endif
+
+       tl = ( tv.tv_sec * 10000000LL ) + ( tv.tv_usec * 10LL ) + UUID_TPLUS;
+       nl = lutil_eaddr();
+
+       if (! seq) {
+               lutil_entropy( &seq, sizeof(seq) );
+       }
+       sq = ++seq;
+
+       t1 = tl & 0xffffffff;                                   /* time_low */
+       t2 = ( tl >> 32 ) & 0xffff;                             /* time_mid */
+       t3 = ( tl >> 48 ) & 0x0fff | 0x1000;    /* time_hi_and_version */
+       s1 = (sq & 0x1fff ) | 0x8000;                   /* clock_seq_and_reserved */
+
+       t1 = snprintf( buf, len,
+               "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
+           t1, (unsigned) t2, (unsigned) t3, (unsigned) s1,
+               (unsigned) nl[0], (unsigned) nl[1],
+               (unsigned) nl[2], (unsigned) nl[3],
+               (unsigned) nl[4], (unsigned) nl[5] );
+
+       return (t1 < len) ? 1 : 0;
+#endif
+}
+
+#ifdef TEST
+int
+main(int argc, char **argv)
+{
+       char buf1[8], buf2[64];
+
+#ifndef HAVE_SYS_UUID_H
+       unsigned char *p = lutil_eaddr();
+
+       if( p ) {
+               printf( "Ethernet Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+                       (unsigned) p[0], (unsigned) p[1], (unsigned) p[2],
+                       (unsigned) p[3], (unsigned) p[4], (unsigned) p[5]);
+       }
+#endif
+
+       if ( lutil_uuidstr( buf1, sizeof( buf1 ) ) ) {
+               printf( "UUID: %s\n", buf1 );
+       } else {
+               fprintf( stderr, "too short: %ld\n", (long) sizeof( buf1 ) );
+       }
+
+       if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) {
+               printf( "UUID: %s\n", buf2 );
+       } else {
+               fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) );
+       }
+
+       if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) {
+               printf( "UUID: %s\n", buf2 );
+       } else {
+               fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) );
+       }
+
+       return 0;
+}
+#endif