Back to index

openldap  2.4.31
uuid.c
Go to the documentation of this file.
00001 /* uuid.c -- Universally Unique Identifier routines */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2000-2012 The OpenLDAP Foundation.
00006  * Portions Copyright 2000-2003 Kurt D. Zeilenga.
00007  * All rights reserved.
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted only as authorized by the OpenLDAP
00011  * Public License.
00012  *
00013  * A copy of this license is available in the file LICENSE in the
00014  * top-level directory of the distribution or, alternatively, at
00015  * <http://www.OpenLDAP.org/license.html>.
00016  */
00017 /* Portions Copyright 2000, John E. Schimmel, All rights reserved.
00018  * This software is not subject to any license of Mirapoint, Inc.
00019  *
00020  * This is free software; you can redistribute and use it
00021  * under the same terms as OpenLDAP itself.
00022  */
00023 /* This work was initially developed by John E. Schimmel and adapted
00024  * for inclusion in OpenLDAP Software by Kurt D. Zeilenga.
00025  */
00026 
00027 /*
00028  * Sorry this file is so scary, but it needs to run on a wide range of
00029  * platforms.  The only exported routine is lutil_uuidstr() which is all
00030  * that LDAP cares about.  It generates a new uuid and returns it in
00031  * in string form.
00032  */
00033 #include "portable.h"
00034 
00035 #include <limits.h>
00036 #include <stdio.h>
00037 #include <sys/types.h>
00038 
00039 #include <ac/stdlib.h>
00040 #include <ac/string.h>      /* get memcmp() */
00041 
00042 #ifdef HAVE_UUID_TO_STR
00043 #  include <sys/uuid.h>
00044 #elif defined( HAVE_UUID_GENERATE )
00045 #  include <uuid/uuid.h>
00046 #elif defined( _WIN32 )
00047 #  include <rpc.h>
00048 #else
00049 #  include <ac/socket.h>
00050 #  include <ac/time.h>
00051 #  ifdef HAVE_SYS_SYSCTL_H
00052 #    include <net/if.h>
00053 #    include <sys/sysctl.h>
00054 #    include <net/route.h>
00055 #  endif
00056 #endif
00057 
00058 #include <lutil.h>
00059 
00060 /* not needed for Windows */
00061 #if !defined(HAVE_UUID_TO_STR) && !defined(HAVE_UUID_GENERATE) && !defined(_WIN32)
00062 static unsigned char *
00063 lutil_eaddr( void )
00064 {
00065        static unsigned char zero[6];
00066        static unsigned char eaddr[6];
00067 
00068 #ifdef HAVE_SYS_SYSCTL_H
00069        size_t needed;
00070        int mib[6];
00071        char *buf, *next, *lim;
00072        struct if_msghdr *ifm;
00073        struct sockaddr_dl *sdl;
00074 
00075        if (memcmp(eaddr, zero, sizeof(eaddr))) {
00076               return eaddr;
00077        }
00078 
00079        mib[0] = CTL_NET;
00080        mib[1] = PF_ROUTE;
00081        mib[3] = 0;
00082        mib[3] = 0;
00083        mib[4] = NET_RT_IFLIST;
00084        mib[5] = 0;
00085 
00086        if (sysctl(mib, sizeof(mib), NULL, &needed, NULL, 0) < 0) {
00087               return NULL;
00088        }
00089 
00090        buf = malloc(needed);
00091        if( buf == NULL ) return NULL;
00092 
00093        if (sysctl(mib, sizeof(mib), buf, &needed, NULL, 0) < 0) {
00094               free(buf);
00095               return NULL;
00096        }
00097 
00098        lim = buf + needed;
00099        for (next = buf; next < lim; next += ifm->ifm_msglen) {
00100               ifm = (struct if_msghdr *)next;
00101               sdl = (struct sockaddr_dl *)(ifm + 1);
00102 
00103               if ( sdl->sdl_family != AF_LINK || sdl->sdl_alen == 6 ) {
00104                      AC_MEMCPY(eaddr,
00105                             (unsigned char *)sdl->sdl_data + sdl->sdl_nlen,
00106                             sizeof(eaddr));
00107                      free(buf);
00108                      return eaddr;
00109               }
00110        }
00111 
00112        free(buf);
00113        return NULL;
00114 
00115 #elif defined( SIOCGIFADDR ) && defined( AFLINK )
00116        char buf[sizeof(struct ifreq) * 32];
00117        struct ifconf ifc;
00118        struct ifreq *ifr;
00119        struct sockaddr *sa;
00120        struct sockaddr_dl *sdl;
00121        unsigned char *p;
00122        int s, i;
00123 
00124        if (memcmp(eaddr, zero, sizeof(eaddr))) {
00125               return eaddr;
00126        }
00127 
00128        s = socket( AF_INET, SOCK_DGRAM, 0 );
00129        if ( s < 0 ) {
00130               return NULL;
00131        }
00132 
00133        ifc.ifc_len = sizeof( buf );
00134        ifc.ifc_buf = buf;
00135        memset( buf, 0, sizeof( buf ) );
00136 
00137        i = ioctl( s, SIOCGIFCONF, (char *)&ifc );
00138        close( s );
00139 
00140        if( i < 0 ) {
00141               return NULL;
00142        }
00143 
00144        for ( i = 0; i < ifc.ifc_len; ) {
00145               ifr = (struct ifreq *)&ifc.ifc_buf[i];
00146               sa = &ifr->ifr_addr;
00147 
00148               if ( sa->sa_len > sizeof( ifr->ifr_addr ) ) {
00149                      i += sizeof( ifr->ifr_name ) + sa->sa_len;
00150               } else {
00151                      i += sizeof( *ifr );
00152               }
00153 
00154               if ( sa->sa_family != AF_LINK ) {
00155                      continue;
00156               }
00157 
00158               sdl = (struct sockaddr_dl *)sa;
00159 
00160               if ( sdl->sdl_alen == 6 ) {
00161                      AC_MEMCPY(eaddr,
00162                             (unsigned char *)sdl->sdl_data + sdl->sdl_nlen,
00163                             sizeof(eaddr));
00164                      return eaddr;
00165               }
00166        }
00167 
00168        return NULL;
00169 
00170 #else
00171        if (memcmp(eaddr, zero, sizeof(eaddr)) == 0) {
00172               /* XXX - who knows? */
00173               lutil_entropy( eaddr, sizeof(eaddr) );
00174               eaddr[0] |= 0x01; /* turn it into a multicast address */
00175        }
00176 
00177        return eaddr;
00178 #endif
00179 }
00180 
00181 #if (ULONG_MAX >> 31 >> 31) > 1 || defined HAVE_LONG_LONG
00182 
00183 #if (ULONG_MAX >> 31 >> 31) > 1
00184     typedef unsigned long       UI64;
00185        /* 100 usec intervals from 10/10/1582 to 1/1/1970 */
00186 #   define UUID_TPLUS           0x01B21DD2138140ul
00187 #else
00188     typedef unsigned long long  UI64;
00189 #   define UUID_TPLUS           0x01B21DD2138140ull
00190 #endif
00191 
00192 #define high32(i)           ((unsigned long) ((i) >> 32))
00193 #define low32(i)            ((unsigned long) (i) & 0xFFFFFFFFul)
00194 #define set_add64(res, i)   ((res) += (i))
00195 #define set_add64l(res, i)  ((res) += (i))
00196 #define mul64ll(i1, i2)     ((UI64) (i1) * (i2))
00197 
00198 #else /* ! (ULONG_MAX >= 64 bits || HAVE_LONG_LONG) */
00199 
00200 typedef struct {
00201        unsigned long high, low;
00202 } UI64;
00203 
00204 static const UI64 UUID_TPLUS = { 0x01B21Dul, 0xD2138140ul };
00205 
00206 #define high32(i)                   ((i).high)
00207 #define low32(i)                    ((i).low)
00208 
00209 /* res += ui64 */
00210 #define set_add64(res, ui64) \
00211 { \
00212        res.high += ui64.high; \
00213        res.low        = (res.low + ui64.low) & 0xFFFFFFFFul; \
00214        if (res.low < ui64.low) res.high++; \
00215 }
00216 
00217 /* res += ul32 */
00218 #define set_add64l(res, ul32) \
00219 { \
00220        res.low       = (res.low + ul32) & 0xFFFFFFFFul; \
00221        if (res.low < ul32) res.high++; \
00222 }
00223 
00224 /* compute i1 * i2 */
00225 static UI64
00226 mul64ll(unsigned long i1, unsigned long i2)
00227 {
00228        const unsigned int high1 = (i1 >> 16), low1 = (i1 & 0xffff);
00229        const unsigned int high2 = (i2 >> 16), low2 = (i2 & 0xffff);
00230 
00231        UI64 res;
00232        unsigned long tmp;
00233 
00234        res.high = (unsigned long) high1 * high2;
00235        res.low        = (unsigned long) low1      * low2;
00236 
00237        tmp = (unsigned long) low1 * high2;
00238        res.high += (tmp >> 16);
00239        tmp = (tmp << 16) & 0xFFFFFFFFul;
00240        res.low = (res.low + tmp) & 0xFFFFFFFFul;
00241        if (res.low < tmp)
00242               res.high++;
00243 
00244        tmp = (unsigned long) low2 * high1;
00245        res.high += (tmp >> 16);
00246        tmp = (tmp << 16) & 0xFFFFFFFFul;
00247        res.low = (res.low + tmp) & 0xFFFFFFFFul;
00248        if (res.low < tmp)
00249               res.high++;
00250 
00251        return res;
00252 }
00253 
00254 #endif /* ULONG_MAX >= 64 bits || HAVE_LONG_LONG */
00255 
00256 #endif /* !HAVE_UUID_TO_STR && !HAVE_UUID_GENERATE && !_WIN32 */
00257 
00258 /*
00259 ** All we really care about is an ISO UUID string.  The format of a UUID is:
00260 **     field                octet         note
00261 **     time_low             0-3           low field of the timestamp
00262 **     time_mid             4-5           middle field of timestamp
00263 **     time_hi_and_version  6-7           high field of timestamp and
00264 **                                        version number
00265 **     clock_seq_hi_and_resv       8             high field of clock sequence
00266 **                                        and variant
00267 **     clock_seq_low        9             low field of clock sequence
00268 **     node                 10-15         spacially unique identifier
00269 **
00270 ** We use DCE version one, and the DCE variant.  Our unique identifier is
00271 ** the first ethernet address on the system.
00272 */
00273 size_t
00274 lutil_uuidstr( char *buf, size_t len )
00275 {
00276 #ifdef HAVE_UUID_TO_STR
00277        uuid_t uu = {0};
00278        unsigned rc;
00279        char *s;
00280        size_t l;
00281 
00282        uuid_create( &uu, &rc );
00283        if ( rc != uuid_s_ok ) {
00284               return 0;
00285        }
00286 
00287        uuid_to_str( &uu, &s, &rc );
00288        if ( rc != uuid_s_ok ) {
00289               return 0;
00290        }
00291 
00292        l = strlen( s );
00293        if ( l >= len ) {
00294               free( s );
00295               return 0;
00296        }
00297 
00298        strncpy( buf, s, len );
00299        free( s );
00300 
00301        return l;
00302 
00303 #elif defined( HAVE_UUID_GENERATE )
00304        uuid_t uu;
00305 
00306        uuid_generate( uu );
00307        uuid_unparse_lower( uu, buf );
00308        return strlen( buf );
00309        
00310 #elif defined( _WIN32 )
00311        UUID uuid;
00312        unsigned char *uuidstr;
00313        size_t uuidlen;
00314 
00315        if( UuidCreate( &uuid ) != RPC_S_OK ) {
00316               return 0;
00317        }
00318  
00319        if( UuidToString( &uuid, &uuidstr ) !=  RPC_S_OK ) {
00320               return 0;
00321        }
00322 
00323        uuidlen = strlen( uuidstr );
00324        if( uuidlen >= len ) {
00325               return 0;
00326        }
00327 
00328        strncpy( buf, uuidstr, len );
00329        RpcStringFree( &uuidstr );
00330 
00331        return uuidlen;
00332  
00333 #else
00334        struct timeval tv;
00335        UI64 tl;
00336        unsigned char *nl;
00337        unsigned short t2, t3, s1;
00338        unsigned long t1, tl_high;
00339        unsigned int rc;
00340 
00341        /*
00342         * Theoretically we should delay if seq wraps within 100usec but for now
00343         * systems are not fast enough to worry about it.
00344         */
00345        static int inited = 0;
00346        static unsigned short seq;
00347        
00348        if (!inited) {
00349               lutil_entropy( (unsigned char *) &seq, sizeof(seq) );
00350               inited++;
00351        }
00352 
00353 #ifdef HAVE_GETTIMEOFDAY
00354        gettimeofday( &tv, 0 );
00355 #else
00356        time( &tv.tv_sec );
00357        tv.tv_usec = 0;
00358 #endif
00359 
00360        tl = mul64ll(tv.tv_sec, 10000000UL);
00361        set_add64l(tl, tv.tv_usec * 10UL);
00362        set_add64(tl, UUID_TPLUS);
00363 
00364        nl = lutil_eaddr();
00365 
00366        t1 = low32(tl);                           /* time_low */
00367        tl_high = high32(tl);
00368        t2 = tl_high & 0xffff;             /* time_mid */
00369        t3 = ((tl_high >> 16) & 0x0fff) | 0x1000; /* time_hi_and_version */
00370        s1 = ( ++seq & 0x1fff ) | 0x8000;         /* clock_seq_and_reserved */
00371 
00372        rc = snprintf( buf, len,
00373               "%08lx-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
00374               t1, (unsigned) t2, (unsigned) t3, (unsigned) s1,
00375               (unsigned) nl[0], (unsigned) nl[1],
00376               (unsigned) nl[2], (unsigned) nl[3],
00377               (unsigned) nl[4], (unsigned) nl[5] );
00378 
00379        return rc < len ? rc : 0;
00380 #endif
00381 }
00382 
00383 int
00384 lutil_uuidstr_from_normalized(
00385        char          *uuid,
00386        size_t        uuidlen,
00387        char          *buf,
00388        size_t        buflen )
00389 {
00390        unsigned char nibble;
00391        int i, d = 0;
00392 
00393        assert( uuid != NULL );
00394        assert( buf != NULL );
00395 
00396        if ( uuidlen != 16 ) return -1;
00397        if ( buflen < 36 ) return -1;
00398 
00399        for ( i = 0; i < 16; i++ ) {
00400               if ( i == 4 || i == 6 || i == 8 || i == 10 ) {
00401                      buf[(i<<1)+d] = '-';
00402                      d += 1;
00403               }
00404 
00405               nibble = (uuid[i] >> 4) & 0xF;
00406               if ( nibble < 10 ) {
00407                      buf[(i<<1)+d] = nibble + '0';
00408               } else {
00409                      buf[(i<<1)+d] = nibble - 10 + 'a';
00410               }
00411 
00412               nibble = (uuid[i]) & 0xF;
00413               if ( nibble < 10 ) {
00414                      buf[(i<<1)+d+1] = nibble + '0';
00415               } else {
00416                      buf[(i<<1)+d+1] = nibble - 10 + 'a';
00417               }
00418        }
00419 
00420        if ( buflen > 36 ) buf[36] = '\0';
00421        return 36;
00422 }
00423 
00424 #ifdef TEST
00425 int
00426 main(int argc, char **argv)
00427 {
00428        char buf1[8], buf2[64];
00429 
00430 #ifndef HAVE_UUID_TO_STR
00431        unsigned char *p = lutil_eaddr();
00432 
00433        if( p ) {
00434               printf( "Ethernet Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
00435                      (unsigned) p[0], (unsigned) p[1], (unsigned) p[2],
00436                      (unsigned) p[3], (unsigned) p[4], (unsigned) p[5]);
00437        }
00438 #endif
00439 
00440        if ( lutil_uuidstr( buf1, sizeof( buf1 ) ) ) {
00441               printf( "UUID: %s\n", buf1 );
00442        } else {
00443               fprintf( stderr, "too short: %ld\n", (long) sizeof( buf1 ) );
00444        }
00445 
00446        if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) {
00447               printf( "UUID: %s\n", buf2 );
00448        } else {
00449               fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) );
00450        }
00451 
00452        if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) {
00453               printf( "UUID: %s\n", buf2 );
00454        } else {
00455               fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) );
00456        }
00457 
00458        return 0;
00459 }
00460 #endif