]> git.sur5r.net Git - openldap/blob - libraries/liblutil/uuid.c
Import some lint removal
[openldap] / libraries / liblutil / uuid.c
1 /*
2  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
3  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
4  */
5 /* Portions
6  * Copyright 2000, John E. Schimmel, All rights reserved.
7  * This software is not subject to any license of Mirapoint, Inc.
8  *
9  * This is free software; you can redistribute and use it
10  * under the same terms as OpenLDAP itself.
11  */
12 /*
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
16  * in string form.
17  */
18 #include "portable.h"
19
20 #include <stdio.h>
21 #include <sys/types.h>
22
23 #include <ac/stdlib.h>
24 #include <ac/string.h>  /* get memcmp() */
25
26 #ifdef HAVE_UUID_TO_STR
27 #  include <sys/uuid.h>
28 #elif defined( _WIN32 )
29 #  include <rpc.h>
30 #else
31 #  include <ac/socket.h>
32 #  include <ac/time.h>
33
34         /* 100 usec intervals from 10/10/1582 to 1/1/1970 */
35 #       define UUID_TPLUS       0x01B21DD2138140LL
36
37 #  ifdef HAVE_SYS_SYSCTL_H
38 #    include <net/if.h>
39 #    include <sys/sysctl.h>
40 #    include <net/route.h>
41 #  endif
42 #endif
43
44 #include <lutil.h>
45
46 /* not needed for Windows */
47 #if !defined(HAVE_UUID_TO_STR) && !defined(_WIN32)
48 static unsigned char *
49 lutil_eaddr( void )
50 {
51         static unsigned char zero[6];
52         static unsigned char eaddr[6];
53
54 #ifdef HAVE_SYS_SYSCTL_H
55         size_t needed;
56         int mib[6];
57         char *buf, *next, *lim;
58         struct if_msghdr *ifm;
59         struct sockaddr_dl *sdl;
60
61         if (memcmp(eaddr, zero, sizeof(eaddr))) {
62                 return eaddr;
63         }
64
65         mib[0] = CTL_NET;
66         mib[1] = PF_ROUTE;
67         mib[3] = 0;
68         mib[3] = 0;
69         mib[4] = NET_RT_IFLIST;
70         mib[5] = 0;
71
72         if (sysctl(mib, sizeof(mib), NULL, &needed, NULL, 0) < 0) {
73                 return NULL;
74         }
75
76         buf = malloc(needed);
77         if( buf == NULL ) return NULL;
78
79         if (sysctl(mib, sizeof(mib), buf, &needed, NULL, 0) < 0) {
80                 free(buf);
81                 return NULL;
82         }
83
84         lim = buf + needed;
85         for (next = buf; next < lim; next += ifm->ifm_msglen) {
86                 ifm = (struct if_msghdr *)next;
87                 sdl = (struct sockaddr_dl *)(ifm + 1);
88
89                 if ( sdl->sdl_family != AF_LINK || sdl->sdl_alen == 6 ) {
90                         AC_MEMCPY(eaddr,
91                                 (unsigned char *)sdl->sdl_data + sdl->sdl_nlen,
92                                 sizeof(eaddr));
93                         free(buf);
94                         return eaddr;
95                 }
96         }
97
98         free(buf);
99         return NULL;
100
101 #elif defined( SIOCGIFADDR ) && defined( AFLINK )
102         char buf[sizeof(struct ifreq) * 32];
103         struct ifconf ifc;
104         struct ifreq *ifr;
105         struct sockaddr *sa;
106         struct sockaddr_dl *sdl;
107         unsigned char *p;
108         int s, i;
109
110         if (memcmp(eaddr, zero, sizeof(eaddr))) {
111                 return eaddr;
112         }
113
114         s = socket( AF_INET, SOCK_DGRAM, 0 );
115         if ( s < 0 ) {
116                 return NULL;
117         }
118
119         ifc.ifc_len = sizeof( buf );
120         ifc.ifc_buf = buf;
121         memset( buf, 0, sizeof( buf ) );
122
123         i = ioctl( s, SIOCGIFCONF, (char *)&ifc );
124         close( s );
125
126         if( i < 0 ) {
127                 return NULL;
128         }
129
130         for ( i = 0; i < ifc.ifc_len; ) {
131                 ifr = (struct ifreq *)&ifc.ifc_buf[i];
132                 sa = &ifr->ifr_addr;
133
134                 if ( sa->sa_len > sizeof( ifr->ifr_addr ) ) {
135                         i += sizeof( ifr->ifr_name ) + sa->sa_len;
136                 } else {
137                         i += sizeof( *ifr );
138                 }
139
140                 if ( sa->sa_family != AF_LINK ) {
141                         continue;
142                 }
143
144                 sdl = (struct sockaddr_dl *)sa;
145
146                 if ( sdl->sdl_alen == 6 ) {
147                         AC_MEMCPY(eaddr,
148                                 (unsigned char *)sdl->sdl_data + sdl->sdl_nlen,
149                                 sizeof(eaddr));
150                         return eaddr;
151                 }
152         }
153
154         return NULL;
155
156 #else
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 */
161         }
162
163         return eaddr;
164 #endif
165 }
166 #endif
167
168 /*
169 ** All we really care about is an ISO UUID string.  The format of a UUID is:
170 **      field                   octet           note
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
174 **                                              version number
175 **      clock_seq_hi_and_resv   8               high field of clock sequence
176 **                                              and variant
177 **      clock_seq_low           9               low field of clock sequence
178 **      node                    10-15           spacially unique identifier
179 **
180 ** We use DCE version one, and the DCE variant.  Our unique identifier is
181 ** the first ethernet address on the system.
182 */
183 size_t
184 lutil_uuidstr( char *buf, size_t len )
185 {
186 #ifdef HAVE_UUID_TO_STR
187         uuid_t uu = {0};
188         unsigned rc;
189         char *s;
190         size_t l;
191
192         uuid_create( &uu, &rc );
193         if ( rc != uuid_s_ok ) {
194                 return 0;
195         }
196
197         uuid_to_str( &uu, &s, &rc );
198         if ( rc != uuid_s_ok ) {
199                 return 0;
200         }
201
202         l = strlen( s );
203         if ( l >= len ) {
204                 free( s );
205                 return 0;
206         }
207
208         strncpy( buf, s, len );
209         free( s );
210
211         return l;
212
213 #elif defined( _WIN32 )
214         UUID uuid;
215         unsigned char *uuidstr;
216         size_t uuidlen;
217
218         if( UuidCreate( &uuid ) != RPC_S_OK ) {
219                 return 0;
220         }
221  
222         if( UuidToString( &uuid, &uuidstr ) !=  RPC_S_OK ) {
223                 return 0;
224         }
225
226         uuidlen = strlen( uuidstr );
227         if( uuidlen >= len ) {
228                 return 0;
229         }
230
231         strncpy( buf, uuidstr, len );
232         RpcStringFree( &uuidstr );
233
234         return uuidlen;
235  
236 #else
237         struct timeval tv;
238         unsigned long long tl;
239         unsigned char *nl;
240         unsigned short t2, t3, s1;
241         unsigned int t1;
242
243         /*
244          * Theoretically we should delay if seq wraps within 100usec but for now
245          * systems are not fast enough to worry about it.
246          */
247         static int inited = 0;
248         static unsigned short seq;
249         
250         if (!inited) {
251                 lutil_entropy( (unsigned char *) &seq, sizeof(seq) );
252                 inited++;
253         }
254
255 #ifdef HAVE_GETTIMEOFDAY
256         gettimeofday( &tv, 0 );
257 #else
258         time( &tv.tv_sec );
259         tv.tv_usec = 0;
260 #endif
261
262         tl = ( tv.tv_sec * 10000000LL ) + ( tv.tv_usec * 10LL ) + UUID_TPLUS;
263         nl = lutil_eaddr();
264
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 */
269
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] );
276
277         return (0 < t1 && t1 < len) ? t1 : 0;
278 #endif
279 }
280
281 #ifdef TEST
282 int
283 main(int argc, char **argv)
284 {
285         char buf1[8], buf2[64];
286
287 #ifndef HAVE_UUID_TO_STR
288         unsigned char *p = lutil_eaddr();
289
290         if( p ) {
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]);
294         }
295 #endif
296
297         if ( lutil_uuidstr( buf1, sizeof( buf1 ) ) ) {
298                 printf( "UUID: %s\n", buf1 );
299         } else {
300                 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf1 ) );
301         }
302
303         if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) {
304                 printf( "UUID: %s\n", buf2 );
305         } else {
306                 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) );
307         }
308
309         if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) {
310                 printf( "UUID: %s\n", buf2 );
311         } else {
312                 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) );
313         }
314
315         return 0;
316 }
317 #endif