]> git.sur5r.net Git - openldap/blob - libraries/liblutil/uuid.c
22dc216b204194d075a58897ae647459ed24ced2
[openldap] / libraries / liblutil / uuid.c
1 /*
2  * Copyright 1998-2000 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 /* Adapted for incorporatation into OpenLDAP by Kurt Zeilenga */
13
14 /*
15 ** Sorry this file is so scary, but it needs to run on a wide range of
16 ** platforms.  The only exported routine is lutil_uuidstr() which is all
17 ** that LDAP cares about.  It generates a new uuid and returns it in
18 ** in string form.
19 */
20 #include "portable.h"
21
22 #include <stdio.h>
23 #include <sys/types.h>
24
25 #ifdef HAVE_SYS_UUID_H
26 #  include <sys/uuid.h>
27 #else
28 #  include <ac/socket.h>
29 #  include <sys/sockio.h>
30 #  include <net/if_types.h>
31 #  include <net/if.h>
32 #  include <net/if_dl.h>
33 #  ifdef HAVE_SYS_SYSCTL_H
34 #    include <sys/sysctl.h>
35 #    include <net/route.h>
36 #  endif
37 #endif
38
39 /* 100 usec intervals from 10/10/1582 to 1/1/1970 */
40 #define UUID_TPLUS      0x01B21DD2138140LL
41
42 #ifndef HAVE_SYS_UUID_H
43 static unsigned char *
44 lutil_eaddr( void )
45 {
46         static unsigned char zero[6];
47         static unsigned char eaddr[6];
48
49 #ifdef HAVE_SYS_SYSCTL_H
50         size_t needed;
51         int mib[6];
52         char *buf, *next, *lim;
53         struct if_msghdr *ifm;
54         struct sockaddr_dl *sdl;
55
56         if (memcmp(eaddr, zero, sizeof(eaddr))) {
57                 return eaddr;
58         }
59
60         mib[0] = CTL_NET;
61         mib[1] = PF_ROUTE;
62         mib[3] = 0;
63         mib[3] = 0;
64         mib[4] = NET_RT_IFLIST;
65         mib[5] = 0;
66
67         if (sysctl(mib, sizeof(mib), NULL, &needed, NULL, 0) < 0) {
68                 return NULL;
69         }
70
71         buf = malloc(needed);
72         if( buf == NULL ) return NULL;
73
74         if (sysctl(mib, sizeof(mib), buf, &needed, NULL, 0) < 0) {
75                 free(buf);
76                 return NULL;
77         }
78
79         lim = buf + needed;
80         for (next = buf; next < lim; next += ifm->ifm_msglen) {
81                 ifm = (struct if_msghdr *)next;
82                 sdl = (struct sockaddr_dl *)(ifm + 1);
83
84                 if ( sdl->sdl_family != AF_LINK || sdl->sdl_alen == 6 ) {
85                         memcpy(eaddr,
86                                 (unsigned char *)sdl->sdl_data + sdl->sdl_nlen,
87                                 sizeof(eaddr));
88                         free(buf);
89                         return eaddr;
90                 }
91         }
92
93         free(buf);
94         return NULL;
95
96 #elif defined (SIOCGIFADDR)
97         char buf[sizeof(struct ifreq) * 32];
98         struct ifconf ifc;
99         struct ifreq *ifr;
100         struct sockaddr *sa;
101         struct sockaddr_dl *sdl;
102         unsigned char *p;
103         int s, i;
104
105         if (memcmp(eaddr, zero, sizeof(eaddr))) {
106                 return eaddr;
107         }
108
109         s = socket( AF_INET, SOCK_DGRAM, 0 );
110         if ( s < 0 ) {
111                 return NULL;
112         }
113
114         ifc.ifc_len = sizeof( buf );
115         ifc.ifc_buf = buf;
116         memset( buf, 0, sizeof( buf ) );
117
118         i = ioctl( s, SIOCGIFCONF, (char *)&ifc );
119         close( s );
120
121         if( i < 0 ) {
122                 return NULL;
123         }
124
125         for ( i = 0; i < ifc.ifc_len; ) {
126                 ifr = (struct ifreq *)&ifc.ifc_buf[i];
127                 sa = &ifr->ifr_addr;
128
129                 if ( sa->sa_len > sizeof( ifr->ifr_addr ) ) {
130                         i += sizeof( ifr->ifr_name ) + sa->sa_len;
131                 } else {
132                         i += sizeof( *ifr );
133                 }
134
135                 if ( sa->sa_family != AF_LINK ) {
136                         continue;
137                 }
138
139                 sdl = (struct sockaddr_dl *)sa;
140
141                 if ( sdl->sdl_alen == 6 ) {
142                         memcpy(eaddr,
143                                 (unsigned char *)sdl->sdl_data + sdl->sdl_nlen,
144                                 sizeof(eaddr));
145                         return eaddr;
146                 }
147         }
148
149         return NULL;
150
151 #else
152         if (memcmp(eaddr, zero, sizeof(eaddr)) == 0) {
153                 /* XXX - who knows? */
154                 lutil_entropy( eaddr, sizeof(eaddr) );
155         }
156
157         return eaddr;
158 #endif
159 }
160 #endif
161
162 /*
163 ** All we really care about is an ISO UUID string.  The format of a UUID is:
164 **      field                   octet           note
165 **      time_low                0-3             low field of the timestamp
166 **      time_mid                4-5             middle field of timestamp
167 **      time_hi_and_version     6-7             high field of timestamp and
168 **                                              version number
169 **      clock_seq_hi_and_resv   8               high field of clock sequence
170 **                                              and variant
171 **      clock_seq_low           9               low field of clock sequence
172 **      node                    10-15           spacially unique identifier
173 **
174 ** We use DCE version one, and the DCE variant.  Our unique identifier is
175 ** the first ethernet address on the system.
176 */
177 int
178 lutil_uuidstr( char *buf, size_t len )
179 {
180 #ifdef HAVE_SYS_UUID_H
181         uuid_t uu = {0};
182         unsigned rc;
183         char *s;
184
185         uuid_create( &uu, &rc );
186         if ( rc != uuid_s_ok ) {
187                 return 0;
188         }
189
190         uuid_to_str( &uu, &s, &rc );
191         if ( rc != uuid_s_ok ) {
192                 return 0;
193         }
194         if ( strlen( s ) >= len ) {
195                 free( s );
196                 return 0;
197         }
198
199         strncpy( buf, s, len );
200         free( s );
201
202         return 1;
203
204 #else
205         struct timeval tv;
206         unsigned long long tl;
207         unsigned char *nl;
208         unsigned short sq, t2, t3, s1, n1, n2, n3;
209         unsigned int t1;
210
211         /*
212          * Theoretically we should delay if seq wraps within 100usec but for now
213          * systems are not fast enough to worry about it.
214          */
215         static unsigned short seq = 0;
216
217 #ifdef HAVE_GETTIMEOFDAY
218         gettimeofday( &tv, 0 );
219 #else
220         time( &tv.tv_sec );
221         tv.tv_usec = 0;
222 #endif
223
224         tl = ( tv.tv_sec * 10000000LL ) + ( tv.tv_usec * 10LL ) + UUID_TPLUS;
225         nl = lutil_eaddr();
226
227         if (! seq) {
228                 lutil_entropy( &seq, sizeof(seq) );
229         }
230         sq = ++seq;
231
232         t1 = tl & 0xffffffff;                                   /* time_low */
233         t2 = ( tl >> 32 ) & 0xffff;                             /* time_mid */
234         t3 = ( tl >> 48 ) & 0x0fff | 0x1000;    /* time_hi_and_version */
235         s1 = (sq & 0x1fff ) | 0x8000;                   /* clock_seq_and_reserved */
236
237         t1 = snprintf( buf, len,
238                 "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
239             t1, (unsigned) t2, (unsigned) t3, (unsigned) s1,
240                 (unsigned) nl[0], (unsigned) nl[1],
241                 (unsigned) nl[2], (unsigned) nl[3],
242                 (unsigned) nl[4], (unsigned) nl[5] );
243
244         return (t1 < len) ? 1 : 0;
245 #endif
246 }
247
248 #ifdef TEST
249 int
250 main(int argc, char **argv)
251 {
252         char buf1[8], buf2[64];
253
254 #ifndef HAVE_SYS_UUID_H
255         unsigned char *p = lutil_eaddr();
256
257         if( p ) {
258                 printf( "Ethernet Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
259                         (unsigned) p[0], (unsigned) p[1], (unsigned) p[2],
260                         (unsigned) p[3], (unsigned) p[4], (unsigned) p[5]);
261         }
262 #endif
263
264         if ( lutil_uuidstr( buf1, sizeof( buf1 ) ) ) {
265                 printf( "UUID: %s\n", buf1 );
266         } else {
267                 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf1 ) );
268         }
269
270         if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) {
271                 printf( "UUID: %s\n", buf2 );
272         } else {
273                 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) );
274         }
275
276         if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) {
277                 printf( "UUID: %s\n", buf2 );
278         } else {
279                 fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) );
280         }
281
282         return 0;
283 }
284 #endif