/src/util-linux/libuuid/src/gen_uuid.c
Line | Count | Source |
1 | | /* |
2 | | * gen_uuid.c --- generate a DCE-compatible uuid |
3 | | * |
4 | | * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o. |
5 | | * |
6 | | * %Begin-Header% |
7 | | * Redistribution and use in source and binary forms, with or without |
8 | | * modification, are permitted provided that the following conditions |
9 | | * are met: |
10 | | * 1. Redistributions of source code must retain the above copyright |
11 | | * notice, and the entire permission notice in its entirety, |
12 | | * including the disclaimer of warranties. |
13 | | * 2. Redistributions in binary form must reproduce the above copyright |
14 | | * notice, this list of conditions and the following disclaimer in the |
15 | | * documentation and/or other materials provided with the distribution. |
16 | | * 3. The name of the author may not be used to endorse or promote |
17 | | * products derived from this software without specific prior |
18 | | * written permission. |
19 | | * |
20 | | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
21 | | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
22 | | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
23 | | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
24 | | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
26 | | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
27 | | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
28 | | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
29 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
30 | | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
31 | | * DAMAGE. |
32 | | * %End-Header% |
33 | | */ |
34 | | |
35 | | #ifdef _WIN32 |
36 | | #define _WIN32_WINNT 0x0500 |
37 | | #include <windows.h> |
38 | | #define UUID MYUUID |
39 | | #endif |
40 | | #include <stdio.h> |
41 | | #ifdef HAVE_UNISTD_H |
42 | | #include <unistd.h> |
43 | | #endif |
44 | | #ifdef HAVE_STDLIB_H |
45 | | #include <stdlib.h> |
46 | | #endif |
47 | | #include <string.h> |
48 | | #include <fcntl.h> |
49 | | #include <errno.h> |
50 | | #include <limits.h> |
51 | | #include <sys/types.h> |
52 | | #ifdef HAVE_SYS_TIME_H |
53 | | #include <sys/time.h> |
54 | | #endif |
55 | | #include <sys/stat.h> |
56 | | #ifdef HAVE_SYS_FILE_H |
57 | | #include <sys/file.h> |
58 | | #endif |
59 | | #ifdef HAVE_SYS_IOCTL_H |
60 | | #include <sys/ioctl.h> |
61 | | #endif |
62 | | #ifdef HAVE_SYS_SOCKET_H |
63 | | #include <sys/socket.h> |
64 | | #endif |
65 | | #ifdef HAVE_SYS_UN_H |
66 | | #include <sys/un.h> |
67 | | #endif |
68 | | #ifdef HAVE_SYS_SOCKIO_H |
69 | | #include <sys/sockio.h> |
70 | | #endif |
71 | | #ifdef HAVE_NET_IF_H |
72 | | #include <net/if.h> |
73 | | #endif |
74 | | #ifdef HAVE_NETINET_IN_H |
75 | | #include <netinet/in.h> |
76 | | #endif |
77 | | #ifdef HAVE_NET_IF_DL_H |
78 | | #include <net/if_dl.h> |
79 | | #endif |
80 | | #if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) |
81 | | #include <sys/syscall.h> |
82 | | #endif |
83 | | #ifdef HAVE_LIBPTHREAD |
84 | | # include <pthread.h> |
85 | | #endif |
86 | | |
87 | | #include <signal.h> |
88 | | |
89 | | #include "all-io.h" |
90 | | #include "uuidP.h" |
91 | | #include "uuidd.h" |
92 | | #include "randutils.h" |
93 | | #include "strutils.h" |
94 | | #include "c.h" |
95 | | #include "md5.h" |
96 | | #include "sha1.h" |
97 | | #include "timeutils.h" |
98 | | |
99 | | |
100 | | #ifdef _WIN32 |
101 | | static void gettimeofday (struct timeval *tv, void *dummy) |
102 | | { |
103 | | FILETIME ftime; |
104 | | uint64_t n; |
105 | | |
106 | | GetSystemTimeAsFileTime (&ftime); |
107 | | n = (((uint64_t) ftime.dwHighDateTime << 32) |
108 | | + (uint64_t) ftime.dwLowDateTime); |
109 | | if (n) { |
110 | | n /= 10; |
111 | | n -= ((369 * 365 + 89) * (uint64_t) 86400) * 1000000; |
112 | | } |
113 | | |
114 | | tv->tv_sec = n / 1000000; |
115 | | tv->tv_usec = n % 1000000; |
116 | | } |
117 | | |
118 | | static int getuid (void) |
119 | | { |
120 | | return 1; |
121 | | } |
122 | | #endif |
123 | | |
124 | | #ifdef TEST_PROGRAM |
125 | | #define gettimeofday gettimeofday_fixed |
126 | | |
127 | | static int gettimeofday_fixed(struct timeval *tv, void *tz __attribute__((unused))) |
128 | | { |
129 | | tv->tv_sec = 1645557742; |
130 | | tv->tv_usec = 123456; |
131 | | return 0; |
132 | | } |
133 | | #endif |
134 | | |
135 | | /* |
136 | | * Get the ethernet hardware address, if we can find it... |
137 | | * |
138 | | * XXX for a windows version, probably should use GetAdaptersInfo: |
139 | | * http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451 |
140 | | * commenting out get_node_id just to get gen_uuid to compile under windows |
141 | | * is not the right way to go! |
142 | | */ |
143 | | static int get_node_id(unsigned char *node_id) |
144 | 0 | { |
145 | 0 | #ifdef HAVE_NET_IF_H |
146 | 0 | int sd; |
147 | 0 | struct ifreq ifr, *ifrp; |
148 | 0 | struct ifconf ifc; |
149 | 0 | char buf[1024]; |
150 | 0 | int n, i; |
151 | 0 | unsigned char *a = NULL; |
152 | | #ifdef HAVE_NET_IF_DL_H |
153 | | struct sockaddr_dl *sdlp; |
154 | | #endif |
155 | | |
156 | | /* |
157 | | * BSD 4.4 defines the size of an ifreq to be |
158 | | * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len |
159 | | * However, under earlier systems, sa_len isn't present, so the size is |
160 | | * just sizeof(struct ifreq) |
161 | | */ |
162 | | #ifdef HAVE_SA_LEN |
163 | | #define ifreq_size(i) max(sizeof(struct ifreq),\ |
164 | | sizeof((i).ifr_name)+(i).ifr_addr.sa_len) |
165 | | #else |
166 | 0 | #define ifreq_size(i) sizeof(struct ifreq) |
167 | 0 | #endif /* HAVE_SA_LEN */ |
168 | |
|
169 | 0 | sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); |
170 | 0 | if (sd < 0) { |
171 | 0 | return -1; |
172 | 0 | } |
173 | 0 | memset(buf, 0, sizeof(buf)); |
174 | 0 | ifc.ifc_len = sizeof(buf); |
175 | 0 | ifc.ifc_buf = buf; |
176 | 0 | if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) { |
177 | 0 | close(sd); |
178 | 0 | return -1; |
179 | 0 | } |
180 | 0 | n = ifc.ifc_len; |
181 | 0 | for (i = 0; i < n; i+= ifreq_size(*ifrp) ) { |
182 | 0 | ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i); |
183 | 0 | strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); |
184 | 0 | #ifdef SIOCGIFHWADDR |
185 | 0 | if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) |
186 | 0 | continue; |
187 | 0 | a = (unsigned char *) &ifr.ifr_hwaddr.sa_data; |
188 | | #else |
189 | | #ifdef SIOCGENADDR |
190 | | if (ioctl(sd, SIOCGENADDR, &ifr) < 0) |
191 | | continue; |
192 | | a = (unsigned char *) ifr.ifr_enaddr; |
193 | | #else |
194 | | #ifdef HAVE_NET_IF_DL_H |
195 | | sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr; |
196 | | if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6)) |
197 | | continue; |
198 | | a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen]; |
199 | | #else |
200 | | /* |
201 | | * XXX we don't have a way of getting the hardware |
202 | | * address |
203 | | */ |
204 | | close(sd); |
205 | | return 0; |
206 | | #endif /* HAVE_NET_IF_DL_H */ |
207 | | #endif /* SIOCGENADDR */ |
208 | | #endif /* SIOCGIFHWADDR */ |
209 | 0 | if (a == NULL || (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])) |
210 | 0 | continue; |
211 | 0 | if (node_id) { |
212 | 0 | memcpy(node_id, a, 6); |
213 | 0 | close(sd); |
214 | 0 | return 1; |
215 | 0 | } |
216 | 0 | } |
217 | 0 | close(sd); |
218 | 0 | #endif |
219 | 0 | return 0; |
220 | 0 | } |
221 | | |
222 | | enum { STATE_FD_ERROR = -1, STATE_FD_INIT = -2 }; |
223 | | |
224 | | static int state_fd_init(const char *clock_file, FILE **fp) |
225 | 0 | { |
226 | 0 | mode_t save_umask; |
227 | 0 | int state_fd; |
228 | 0 | FILE *state_f; |
229 | |
|
230 | 0 | save_umask = umask(0); |
231 | 0 | state_fd = open(clock_file, O_RDWR|O_CREAT|O_CLOEXEC, 0660); |
232 | 0 | (void) umask(save_umask); |
233 | 0 | if (state_fd != -1) { |
234 | 0 | state_f = fdopen(state_fd, "r+" UL_CLOEXECSTR); |
235 | 0 | if (!state_f) { |
236 | 0 | close(state_fd); |
237 | 0 | state_fd = STATE_FD_ERROR; |
238 | 0 | } else |
239 | 0 | *fp = state_f; |
240 | 0 | } |
241 | 0 | return state_fd; |
242 | 0 | } |
243 | | |
244 | | /* Assume that the gettimeofday() has microsecond granularity */ |
245 | 0 | #define MAX_ADJUSTMENT 10 |
246 | | /* Reserve a clock_seq value for the 'continuous clock' implementation */ |
247 | 0 | #define CLOCK_SEQ_CONT 0 |
248 | | |
249 | | /* |
250 | | * Get clock from global sequence clock counter. |
251 | | * |
252 | | * Return -1 if the clock counter could not be opened/locked (in this case |
253 | | * pseudorandom value is returned in @ret_clock_seq), otherwise return 0. |
254 | | */ |
255 | | static int get_clock(uint32_t *clock_high, uint32_t *clock_low, |
256 | | uint16_t *ret_clock_seq, int *num) |
257 | 0 | { |
258 | 0 | THREAD_LOCAL int adjustment = 0; |
259 | 0 | THREAD_LOCAL struct timeval last = {0, 0}; |
260 | 0 | THREAD_LOCAL int state_fd = STATE_FD_INIT; |
261 | 0 | THREAD_LOCAL FILE *state_f; |
262 | 0 | THREAD_LOCAL uint16_t clock_seq; |
263 | 0 | struct timeval tv; |
264 | 0 | uint64_t clock_reg; |
265 | 0 | int ret = 0; |
266 | |
|
267 | 0 | if (state_fd == STATE_FD_INIT) |
268 | 0 | state_fd = state_fd_init(LIBUUID_CLOCK_FILE, &state_f); |
269 | |
|
270 | 0 | if (state_fd >= 0) { |
271 | 0 | rewind(state_f); |
272 | 0 | while (flock(state_fd, LOCK_EX) < 0) { |
273 | 0 | if ((errno == EAGAIN) || (errno == EINTR)) |
274 | 0 | continue; |
275 | 0 | fclose(state_f); |
276 | 0 | close(state_fd); |
277 | 0 | state_fd = STATE_FD_ERROR; |
278 | 0 | ret = -1; |
279 | 0 | break; |
280 | 0 | } |
281 | 0 | } else |
282 | 0 | ret = -1; |
283 | |
|
284 | 0 | if (state_fd >= 0) { |
285 | 0 | unsigned int cl; |
286 | 0 | unsigned long tv1, tv2; |
287 | 0 | int a; |
288 | |
|
289 | 0 | if (fscanf(state_f, "clock: %04x tv: %lu %lu adj: %d\n", |
290 | 0 | &cl, &tv1, &tv2, &a) == 4) { |
291 | 0 | clock_seq = cl & 0x3FFF; |
292 | 0 | last.tv_sec = tv1; |
293 | 0 | last.tv_usec = tv2; |
294 | 0 | adjustment = a; |
295 | 0 | } |
296 | | // reset in case of reserved CLOCK_SEQ_CONT |
297 | 0 | if (clock_seq == CLOCK_SEQ_CONT) { |
298 | 0 | last.tv_sec = 0; |
299 | 0 | last.tv_usec = 0; |
300 | 0 | } |
301 | 0 | } |
302 | |
|
303 | 0 | if ((last.tv_sec == 0) && (last.tv_usec == 0)) { |
304 | 0 | do { |
305 | 0 | ul_random_get_bytes(&clock_seq, sizeof(clock_seq)); |
306 | 0 | clock_seq &= 0x3FFF; |
307 | 0 | } while (clock_seq == CLOCK_SEQ_CONT); |
308 | 0 | gettimeofday(&last, NULL); |
309 | 0 | last.tv_sec--; |
310 | 0 | } |
311 | |
|
312 | 0 | try_again: |
313 | 0 | gettimeofday(&tv, NULL); |
314 | 0 | if ((tv.tv_sec < last.tv_sec) || |
315 | 0 | ((tv.tv_sec == last.tv_sec) && |
316 | 0 | (tv.tv_usec < last.tv_usec))) { |
317 | 0 | do { |
318 | 0 | clock_seq = (clock_seq+1) & 0x3FFF; |
319 | 0 | } while (clock_seq == CLOCK_SEQ_CONT); |
320 | 0 | adjustment = 0; |
321 | 0 | last = tv; |
322 | 0 | } else if ((tv.tv_sec == last.tv_sec) && |
323 | 0 | (tv.tv_usec == last.tv_usec)) { |
324 | 0 | if (adjustment >= MAX_ADJUSTMENT) |
325 | 0 | goto try_again; |
326 | 0 | adjustment++; |
327 | 0 | } else { |
328 | 0 | adjustment = 0; |
329 | 0 | last = tv; |
330 | 0 | } |
331 | | |
332 | 0 | clock_reg = tv.tv_usec*10 + adjustment; |
333 | 0 | clock_reg += ((uint64_t) tv.tv_sec)*10000000; |
334 | 0 | clock_reg += (((uint64_t) 0x01B21DD2) << 32) + 0x13814000; |
335 | |
|
336 | 0 | if (num && (*num > 1)) { |
337 | 0 | adjustment += *num - 1; |
338 | 0 | last.tv_usec += adjustment / 10; |
339 | 0 | adjustment = adjustment % 10; |
340 | 0 | last.tv_sec += last.tv_usec / 1000000; |
341 | 0 | last.tv_usec = last.tv_usec % 1000000; |
342 | 0 | } |
343 | |
|
344 | 0 | if (state_fd >= 0) { |
345 | 0 | rewind(state_f); |
346 | 0 | fprintf(state_f, |
347 | 0 | "clock: %04x tv: %016ld %08ld adj: %08d \n", |
348 | 0 | clock_seq, (long)last.tv_sec, (long)last.tv_usec, adjustment); |
349 | 0 | fflush(state_f); |
350 | 0 | rewind(state_f); |
351 | 0 | flock(state_fd, LOCK_UN); |
352 | 0 | } |
353 | |
|
354 | 0 | *clock_high = clock_reg >> 32; |
355 | 0 | *clock_low = clock_reg; |
356 | 0 | *ret_clock_seq = clock_seq; |
357 | 0 | return ret; |
358 | 0 | } |
359 | | |
360 | | /* |
361 | | * Get current time in 100ns ticks. |
362 | | */ |
363 | | static uint64_t get_clock_counter(void) |
364 | 0 | { |
365 | 0 | struct timeval tv; |
366 | 0 | uint64_t clock_reg; |
367 | |
|
368 | 0 | gettimeofday(&tv, NULL); |
369 | 0 | clock_reg = tv.tv_usec*10; |
370 | 0 | clock_reg += ((uint64_t) tv.tv_sec) * 10000000ULL; |
371 | |
|
372 | 0 | return clock_reg; |
373 | 0 | } |
374 | | |
375 | | /* |
376 | | * Get continuous clock value. |
377 | | * |
378 | | * Return -1 if there is no valid clock counter available, |
379 | | * otherwise return 0. |
380 | | * |
381 | | * This implementation doesn't deliver clock counters based on |
382 | | * the current time because last_clock_reg is only incremented |
383 | | * by the number of requested UUIDs. |
384 | | * max_clock_offset is used to limit the offset of last_clock_reg. |
385 | | * used/reserved UUIDs are written to LIBUUID_CLOCK_CONT_FILE. |
386 | | */ |
387 | | static int get_clock_cont(uint32_t *clock_high, |
388 | | uint32_t *clock_low, |
389 | | int num, |
390 | | uint32_t max_clock_offset) |
391 | 0 | { |
392 | | /* all 64bit clock_reg values in this function represent '100ns ticks' |
393 | | * due to the combination of tv_usec + MAX_ADJUSTMENT */ |
394 | | |
395 | | /* time offset according to RFC 4122. 4.1.4. */ |
396 | 0 | const uint64_t reg_offset = (((uint64_t) 0x01B21DD2) << 32) + 0x13814000; |
397 | 0 | static uint64_t last_clock_reg = 0; |
398 | 0 | static uint64_t saved_clock_reg = 0; |
399 | 0 | static int state_fd = STATE_FD_INIT; |
400 | 0 | static FILE *state_f = NULL; |
401 | 0 | uint64_t clock_reg, next_clock_reg; |
402 | |
|
403 | 0 | if (state_fd == STATE_FD_ERROR) |
404 | 0 | return -1; |
405 | | |
406 | 0 | clock_reg = get_clock_counter(); |
407 | |
|
408 | 0 | if (state_fd == STATE_FD_INIT) { |
409 | 0 | struct stat st; |
410 | |
|
411 | 0 | state_fd = state_fd_init(LIBUUID_CLOCK_CONT_FILE, &state_f); |
412 | 0 | if (state_fd == STATE_FD_ERROR) |
413 | 0 | return -1; |
414 | | |
415 | 0 | if (fstat(state_fd, &st)) |
416 | 0 | goto error; |
417 | | |
418 | 0 | if (st.st_size) { |
419 | 0 | rewind(state_f); |
420 | 0 | if (fscanf(state_f, "cont: %"SCNu64"\n", &last_clock_reg) != 1) |
421 | 0 | goto error; |
422 | 0 | } else |
423 | 0 | last_clock_reg = clock_reg; |
424 | | |
425 | 0 | saved_clock_reg = last_clock_reg; |
426 | 0 | } |
427 | | |
428 | 0 | if (max_clock_offset) { |
429 | 0 | uint64_t co = 10000000ULL * (uint64_t)max_clock_offset; // clock_offset in [100ns] |
430 | |
|
431 | 0 | if ((last_clock_reg + co) < clock_reg) |
432 | 0 | last_clock_reg = clock_reg - co; |
433 | 0 | } |
434 | |
|
435 | 0 | clock_reg += MAX_ADJUSTMENT; |
436 | |
|
437 | 0 | next_clock_reg = last_clock_reg + (uint64_t)num; |
438 | 0 | if (next_clock_reg >= clock_reg) |
439 | 0 | return -1; |
440 | | |
441 | 0 | if (next_clock_reg >= saved_clock_reg) { |
442 | 0 | uint64_t cl = next_clock_reg + 100000000ULL; // 10s interval in [100ns] |
443 | 0 | int l; |
444 | |
|
445 | 0 | rewind(state_f); |
446 | 0 | l = fprintf(state_f, "cont: %020"PRIu64" \n", cl); |
447 | 0 | if (l < 30 || fflush(state_f)) |
448 | 0 | goto error; |
449 | 0 | saved_clock_reg = cl; |
450 | 0 | } |
451 | | |
452 | 0 | *clock_high = (last_clock_reg + reg_offset) >> 32; |
453 | 0 | *clock_low = last_clock_reg + reg_offset; |
454 | 0 | last_clock_reg = next_clock_reg; |
455 | |
|
456 | 0 | return 0; |
457 | | |
458 | 0 | error: |
459 | 0 | if (state_fd >= 0) |
460 | 0 | close(state_fd); |
461 | 0 | if (state_f) |
462 | 0 | fclose(state_f); |
463 | 0 | state_fd = STATE_FD_ERROR; |
464 | 0 | state_f = NULL; |
465 | 0 | return -1; |
466 | 0 | } |
467 | | |
468 | | #if defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H) && !defined(TEST_PROGRAM) |
469 | | |
470 | | /* |
471 | | * Try using the uuidd daemon to generate the UUID |
472 | | * |
473 | | * Returns 0 on success, non-zero on failure. |
474 | | */ |
475 | | static int get_uuid_via_daemon(int op, uuid_t out, int *num) |
476 | | { |
477 | | char op_buf[64]; |
478 | | int op_len; |
479 | | int s; |
480 | | ssize_t ret; |
481 | | int32_t reply_len = 0, expected = 16; |
482 | | struct sockaddr_un srv_addr; |
483 | | |
484 | | if (sizeof(UUIDD_SOCKET_PATH) > sizeof(srv_addr.sun_path)) |
485 | | return -1; |
486 | | |
487 | | if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) |
488 | | return -1; |
489 | | |
490 | | srv_addr.sun_family = AF_UNIX; |
491 | | xstrncpy(srv_addr.sun_path, UUIDD_SOCKET_PATH, sizeof(srv_addr.sun_path)); |
492 | | |
493 | | if (connect(s, (const struct sockaddr *) &srv_addr, |
494 | | sizeof(struct sockaddr_un)) < 0) |
495 | | goto fail; |
496 | | |
497 | | op_buf[0] = op; |
498 | | op_len = 1; |
499 | | if (op == UUIDD_OP_BULK_TIME_UUID) { |
500 | | memcpy(op_buf+1, num, sizeof(*num)); |
501 | | op_len += sizeof(*num); |
502 | | expected += sizeof(*num); |
503 | | } |
504 | | |
505 | | ret = write(s, op_buf, op_len); |
506 | | if (ret < 1) |
507 | | goto fail; |
508 | | |
509 | | ret = read_all(s, (char *) &reply_len, sizeof(reply_len)); |
510 | | if (ret < 0) |
511 | | goto fail; |
512 | | |
513 | | if (reply_len != expected) |
514 | | goto fail; |
515 | | |
516 | | ret = read_all(s, op_buf, reply_len); |
517 | | |
518 | | if (op == UUIDD_OP_BULK_TIME_UUID) |
519 | | memcpy(op_buf+16, num, sizeof(int)); |
520 | | |
521 | | memcpy(out, op_buf, 16); |
522 | | |
523 | | close(s); |
524 | | return ((ret == expected) ? 0 : -1); |
525 | | |
526 | | fail: |
527 | | close(s); |
528 | | return -1; |
529 | | } |
530 | | |
531 | | #else /* !defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H) */ |
532 | | static int get_uuid_via_daemon(int op __attribute__((__unused__)), |
533 | | uuid_t out __attribute__((__unused__)), |
534 | | int *num __attribute__((__unused__))) |
535 | 0 | { |
536 | 0 | return -1; |
537 | 0 | } |
538 | | #endif |
539 | | |
540 | | static int __uuid_generate_time_internal(uuid_t out, int *num, uint32_t cont_offset) |
541 | 0 | { |
542 | 0 | static unsigned char node_id[6]; |
543 | 0 | static int has_init = 0; |
544 | 0 | struct uuid uu; |
545 | 0 | uint32_t clock_mid; |
546 | 0 | int ret; |
547 | |
|
548 | 0 | if (!has_init) { |
549 | 0 | if (get_node_id(node_id) <= 0) { |
550 | 0 | ul_random_get_bytes(node_id, 6); |
551 | | /* |
552 | | * Set multicast bit, to prevent conflicts |
553 | | * with IEEE 802 addresses obtained from |
554 | | * network cards |
555 | | */ |
556 | 0 | node_id[0] |= 0x01; |
557 | 0 | } |
558 | 0 | has_init = 1; |
559 | 0 | } |
560 | 0 | if (cont_offset) { |
561 | 0 | ret = get_clock_cont(&clock_mid, &uu.time_low, *num, cont_offset); |
562 | 0 | uu.clock_seq = CLOCK_SEQ_CONT; |
563 | 0 | if (ret != 0) /* fallback to previous implpementation */ |
564 | 0 | ret = get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num); |
565 | 0 | } else { |
566 | 0 | ret = get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num); |
567 | 0 | } |
568 | 0 | uu.clock_seq |= 0x8000; |
569 | 0 | uu.time_mid = (uint16_t) clock_mid; |
570 | 0 | uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000; |
571 | 0 | memcpy(uu.node, node_id, 6); |
572 | 0 | uuid_pack(&uu, out); |
573 | 0 | return ret; |
574 | 0 | } |
575 | | |
576 | | int __uuid_generate_time(uuid_t out, int *num) |
577 | 0 | { |
578 | 0 | return __uuid_generate_time_internal(out, num, 0); |
579 | 0 | } |
580 | | |
581 | | int __uuid_generate_time_cont(uuid_t out, int *num, uint32_t cont_offset) |
582 | 0 | { |
583 | 0 | return __uuid_generate_time_internal(out, num, cont_offset); |
584 | 0 | } |
585 | | |
586 | 0 | #define CS_MIN (1<<6) |
587 | 0 | #define CS_MAX (1<<18) |
588 | 0 | #define CS_FACTOR 2 |
589 | | |
590 | | static void __uuid_set_variant_and_version(uuid_t uuid, int version) |
591 | 0 | { |
592 | 0 | uuid[6] = (uuid[6] & UUID_TYPE_MASK) | version << UUID_TYPE_SHIFT; |
593 | | /* only DCE is supported */ |
594 | 0 | uuid[8] = (uuid[8] & 0x3F) | 0x80; |
595 | 0 | } |
596 | | |
597 | | /* |
598 | | * Generate time-based UUID and store it to @out |
599 | | * |
600 | | * Tries to guarantee uniqueness of the generated UUIDs by obtaining them from the uuidd daemon, |
601 | | * or, if uuidd is not usable, by using the global clock state counter (see get_clock()). |
602 | | * If neither of these is possible (e.g. because of insufficient permissions), it generates |
603 | | * the UUID anyway, but returns -1. Otherwise, returns 0. |
604 | | */ |
605 | | #ifdef HAVE_LIBPTHREAD |
606 | | THREAD_LOCAL struct { |
607 | | int num; |
608 | | int cache_size; |
609 | | int last_used; |
610 | | struct uuid uu; |
611 | | time_t last_time; |
612 | | } uuidd_cache = { |
613 | | .cache_size = CS_MIN, |
614 | | }; |
615 | | |
616 | | static void reset_uuidd_cache(void) |
617 | 0 | { |
618 | 0 | memset(&uuidd_cache, 0, sizeof(uuidd_cache)); |
619 | 0 | uuidd_cache.cache_size = CS_MIN; |
620 | 0 | } |
621 | | #endif /* HAVE_LIBPTHREAD */ |
622 | | |
623 | 0 | static int uuid_generate_time_generic(uuid_t out) { |
624 | 0 | #ifdef HAVE_LIBPTHREAD |
625 | 0 | static volatile sig_atomic_t atfork_registered; |
626 | 0 | time_t now; |
627 | |
|
628 | 0 | if (!atfork_registered) { |
629 | 0 | pthread_atfork(NULL, NULL, reset_uuidd_cache); |
630 | 0 | atfork_registered = 1; |
631 | 0 | } |
632 | |
|
633 | 0 | if (uuidd_cache.num > 0) { /* expire cache */ |
634 | 0 | now = time(NULL); |
635 | 0 | if (now > uuidd_cache.last_time+1) { |
636 | 0 | uuidd_cache.last_used = uuidd_cache.cache_size - uuidd_cache.num; |
637 | 0 | uuidd_cache.num = 0; |
638 | 0 | } |
639 | 0 | } |
640 | 0 | if (uuidd_cache.num <= 0) { /* fill cache */ |
641 | | /* |
642 | | * num + OP_BULK provides a local cache in each application. |
643 | | * Start with a small cache size to cover short running applications |
644 | | * and adjust the cache size over the runntime. |
645 | | */ |
646 | 0 | if ((uuidd_cache.last_used == uuidd_cache.cache_size) && (uuidd_cache.cache_size < CS_MAX)) |
647 | 0 | uuidd_cache.cache_size *= CS_FACTOR; |
648 | 0 | else if ((uuidd_cache.last_used < (uuidd_cache.cache_size / CS_FACTOR)) && (uuidd_cache.cache_size > CS_MIN)) |
649 | 0 | uuidd_cache.cache_size /= CS_FACTOR; |
650 | |
|
651 | 0 | uuidd_cache.num = uuidd_cache.cache_size; |
652 | |
|
653 | 0 | if (get_uuid_via_daemon(UUIDD_OP_BULK_TIME_UUID, |
654 | 0 | out, &uuidd_cache.num) == 0) { |
655 | 0 | uuidd_cache.last_time = time(NULL); |
656 | 0 | uuid_unpack(out, &uuidd_cache.uu); |
657 | 0 | uuidd_cache.num--; |
658 | 0 | return 0; |
659 | 0 | } |
660 | | /* request to daemon failed, reset cache */ |
661 | 0 | reset_uuidd_cache(); |
662 | 0 | } |
663 | 0 | if (uuidd_cache.num > 0) { /* serve uuid from cache */ |
664 | 0 | uuidd_cache.uu.time_low++; |
665 | 0 | if (uuidd_cache.uu.time_low == 0) { |
666 | 0 | uuidd_cache.uu.time_mid++; |
667 | 0 | if (uuidd_cache.uu.time_mid == 0) |
668 | 0 | uuidd_cache.uu.time_hi_and_version++; |
669 | 0 | } |
670 | 0 | uuidd_cache.num--; |
671 | 0 | uuid_pack(&uuidd_cache.uu, out); |
672 | 0 | if (uuidd_cache.num == 0) |
673 | 0 | uuidd_cache.last_used = uuidd_cache.cache_size; |
674 | 0 | return 0; |
675 | 0 | } |
676 | | |
677 | | #else /* !HAVE_LIBPTHREAD */ |
678 | | { |
679 | | int num = 1; |
680 | | if (get_uuid_via_daemon(UUIDD_OP_TIME_UUID, out, &num) == 0) |
681 | | return 0; |
682 | | } |
683 | | #endif /* HAVE_LIBPTHREAD */ |
684 | | |
685 | 0 | return __uuid_generate_time(out, NULL); |
686 | 0 | } |
687 | | |
688 | | /* |
689 | | * Generate time-based UUID and store it to @out. |
690 | | * |
691 | | * Discards return value from uuid_generate_time_generic() |
692 | | */ |
693 | | void uuid_generate_time(uuid_t out) |
694 | 0 | { |
695 | 0 | (void)uuid_generate_time_generic(out); |
696 | 0 | } |
697 | | |
698 | | |
699 | | int uuid_generate_time_safe(uuid_t out) |
700 | 0 | { |
701 | 0 | return uuid_generate_time_generic(out); |
702 | 0 | } |
703 | | |
704 | | void uuid_generate_time_v6(uuid_t out) |
705 | 0 | { |
706 | 0 | uint32_t clock_high, clock_low; |
707 | 0 | uint16_t clock_seq; |
708 | |
|
709 | 0 | get_clock(&clock_high, &clock_low, &clock_seq, NULL); |
710 | |
|
711 | 0 | out[0] = clock_high >> 20; |
712 | 0 | out[1] = clock_high >> 12; |
713 | 0 | out[2] = clock_high >> 4; |
714 | 0 | out[3] = clock_high << 4; |
715 | 0 | out[3] |= clock_low >> 28; |
716 | 0 | out[4] = clock_low >> 20; |
717 | 0 | out[5] = clock_low >> 12; |
718 | 0 | out[6] = clock_low >> 8; |
719 | 0 | out[7] = clock_low >> 0; |
720 | |
|
721 | 0 | ul_random_get_bytes(out + 8, 8); |
722 | 0 | __uuid_set_variant_and_version(out, UUID_TYPE_DCE_TIME_V6); |
723 | 0 | } |
724 | | |
725 | | // FIXME variable additional information |
726 | | void uuid_generate_time_v7(uuid_t out) |
727 | 0 | { |
728 | 0 | struct timeval tv; |
729 | 0 | uint64_t ms; |
730 | |
|
731 | 0 | gettimeofday(&tv, NULL); |
732 | |
|
733 | 0 | ms = tv.tv_sec * MSEC_PER_SEC + tv.tv_usec / USEC_PER_MSEC; |
734 | |
|
735 | 0 | out[0] = ms >> 40; |
736 | 0 | out[1] = ms >> 32; |
737 | 0 | out[2] = ms >> 24; |
738 | 0 | out[3] = ms >> 16; |
739 | 0 | out[4] = ms >> 8; |
740 | 0 | out[5] = ms >> 0; |
741 | 0 | ul_random_get_bytes(out + 6, 10); |
742 | 0 | __uuid_set_variant_and_version(out, UUID_TYPE_DCE_TIME_V7); |
743 | 0 | } |
744 | | |
745 | | |
746 | | int __uuid_generate_random(uuid_t out, int *num) |
747 | 0 | { |
748 | 0 | uuid_t buf; |
749 | 0 | struct uuid uu; |
750 | 0 | int i, n, r = 0; |
751 | |
|
752 | 0 | if (!num || !*num) |
753 | 0 | n = 1; |
754 | 0 | else |
755 | 0 | n = *num; |
756 | |
|
757 | 0 | for (i = 0; i < n; i++) { |
758 | 0 | if (ul_random_get_bytes(buf, sizeof(buf))) |
759 | 0 | r = -1; |
760 | 0 | uuid_unpack(buf, &uu); |
761 | |
|
762 | 0 | uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000; |
763 | 0 | uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) |
764 | 0 | | 0x4000; |
765 | 0 | uuid_pack(&uu, out); |
766 | 0 | out += sizeof(uuid_t); |
767 | 0 | } |
768 | |
|
769 | 0 | return r; |
770 | 0 | } |
771 | | |
772 | | void uuid_generate_random(uuid_t out) |
773 | 0 | { |
774 | 0 | int num = 1; |
775 | | /* No real reason to use the daemon for random uuid's -- yet */ |
776 | |
|
777 | 0 | __uuid_generate_random(out, &num); |
778 | 0 | } |
779 | | |
780 | | /* |
781 | | * This is the generic front-end to __uuid_generate_random and |
782 | | * uuid_generate_time. It uses __uuid_generate_random output |
783 | | * only if high-quality randomness is available. |
784 | | */ |
785 | | void uuid_generate(uuid_t out) |
786 | 0 | { |
787 | 0 | int num = 1; |
788 | |
|
789 | 0 | if (__uuid_generate_random(out, &num)) |
790 | 0 | uuid_generate_time(out); |
791 | 0 | } |
792 | | |
793 | | /* |
794 | | * Generate an MD5 hashed (predictable) UUID based on a well-known UUID |
795 | | * providing the namespace and an arbitrary binary string. |
796 | | */ |
797 | | void uuid_generate_md5(uuid_t out, const uuid_t ns, const char *name, size_t len) |
798 | 0 | { |
799 | 0 | UL_MD5_CTX ctx; |
800 | 0 | char hash[UL_MD5LENGTH]; |
801 | 0 | uuid_t buf; |
802 | 0 | struct uuid uu; |
803 | |
|
804 | 0 | ul_MD5Init(&ctx); |
805 | 0 | ul_MD5Update(&ctx, ns, sizeof(uuid_t)); |
806 | 0 | ul_MD5Update(&ctx, (const unsigned char *)name, len); |
807 | 0 | ul_MD5Final((unsigned char *)hash, &ctx); |
808 | |
|
809 | 0 | assert(sizeof(buf) <= sizeof(hash)); |
810 | |
|
811 | 0 | memcpy(buf, hash, sizeof(buf)); |
812 | 0 | uuid_unpack(buf, &uu); |
813 | |
|
814 | 0 | uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000; |
815 | 0 | uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x3000; |
816 | 0 | uuid_pack(&uu, out); |
817 | 0 | } |
818 | | |
819 | | /* |
820 | | * Generate a SHA1 hashed (predictable) UUID based on a well-known UUID |
821 | | * providing the namespace and an arbitrary binary string. |
822 | | */ |
823 | | void uuid_generate_sha1(uuid_t out, const uuid_t ns, const char *name, size_t len) |
824 | 0 | { |
825 | 0 | UL_SHA1_CTX ctx; |
826 | 0 | char hash[UL_SHA1LENGTH]; |
827 | 0 | uuid_t buf; |
828 | 0 | struct uuid uu; |
829 | |
|
830 | 0 | ul_SHA1Init(&ctx); |
831 | 0 | ul_SHA1Update(&ctx, ns, sizeof(uuid_t)); |
832 | 0 | ul_SHA1Update(&ctx, (const unsigned char *)name, len); |
833 | 0 | ul_SHA1Final((unsigned char *)hash, &ctx); |
834 | |
|
835 | 0 | assert(sizeof(buf) <= sizeof(hash)); |
836 | |
|
837 | 0 | memcpy(buf, hash, sizeof(buf)); |
838 | 0 | uuid_unpack(buf, &uu); |
839 | |
|
840 | 0 | uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000; |
841 | 0 | uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x5000; |
842 | 0 | uuid_pack(&uu, out); |
843 | 0 | } |
844 | | |
845 | | #ifdef TEST_PROGRAM |
846 | | int main(void) |
847 | | { |
848 | | char buf[UUID_STR_LEN]; |
849 | | uuid_t uuid; |
850 | | |
851 | | uuid_generate_time(uuid); |
852 | | uuid_unparse(uuid, buf); |
853 | | printf("%s\n", buf); |
854 | | |
855 | | uuid_generate_time_v6(uuid); |
856 | | uuid_unparse(uuid, buf); |
857 | | printf("%s\n", buf); |
858 | | |
859 | | uuid_generate_time_v7(uuid); |
860 | | uuid_unparse(uuid, buf); |
861 | | printf("%s\n", buf); |
862 | | |
863 | | return 0; |
864 | | } |
865 | | #endif |