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 | #if HAVE_CONFIG_H |
---|
36 | #include "config.h" |
---|
37 | #endif |
---|
38 | |
---|
39 | /* |
---|
40 | * Force inclusion of SVID stuff since we need it if we're compiling in |
---|
41 | * gcc-wall wall mode |
---|
42 | */ |
---|
43 | #define _SVID_SOURCE |
---|
44 | |
---|
45 | #ifdef _WIN32 |
---|
46 | #define _WIN32_WINNT 0x0500 |
---|
47 | #include <windows.h> |
---|
48 | #define UUID MYUUID |
---|
49 | #endif |
---|
50 | #include <stdio.h> |
---|
51 | #include <limits.h> /* for CHAR_BIT */ |
---|
52 | #ifdef HAVE_UNISTD_H |
---|
53 | #include <unistd.h> |
---|
54 | #endif |
---|
55 | #ifdef HAVE_STDLIB_H |
---|
56 | #include <stdlib.h> |
---|
57 | #endif |
---|
58 | #include <string.h> |
---|
59 | #include <fcntl.h> |
---|
60 | #include <errno.h> |
---|
61 | #include <sys/types.h> |
---|
62 | #ifdef HAVE_SYS_TIME_H |
---|
63 | #include <sys/time.h> |
---|
64 | #endif |
---|
65 | #include <sys/wait.h> |
---|
66 | #include <sys/stat.h> |
---|
67 | #ifdef HAVE_SYS_FILE_H |
---|
68 | #include <sys/file.h> |
---|
69 | #endif |
---|
70 | #ifdef HAVE_SYS_IOCTL_H |
---|
71 | #include <sys/ioctl.h> |
---|
72 | #endif |
---|
73 | #ifdef HAVE_SYS_SOCKET_H |
---|
74 | #include <sys/socket.h> |
---|
75 | #endif |
---|
76 | #ifdef HAVE_SYS_UN_H |
---|
77 | #include <sys/un.h> |
---|
78 | #endif |
---|
79 | #ifdef HAVE_SYS_SOCKIO_H |
---|
80 | #include <sys/sockio.h> |
---|
81 | #endif |
---|
82 | #ifdef HAVE_NET_IF_H |
---|
83 | #include <net/if.h> |
---|
84 | #endif |
---|
85 | #ifdef HAVE_NETINET_IN_H |
---|
86 | #include <netinet/in.h> |
---|
87 | #endif |
---|
88 | #ifdef HAVE_NET_IF_DL_H |
---|
89 | #include <net/if_dl.h> |
---|
90 | #endif |
---|
91 | #if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) |
---|
92 | #include <sys/syscall.h> |
---|
93 | #endif |
---|
94 | #ifdef HAVE_SYS_RESOURCE_H |
---|
95 | #include <sys/resource.h> |
---|
96 | #endif |
---|
97 | |
---|
98 | #include "uuidP.h" |
---|
99 | #include "uuidd.h" |
---|
100 | |
---|
101 | #ifdef HAVE_SRANDOM |
---|
102 | #define srand(x) srandom(x) |
---|
103 | #define rand() random() |
---|
104 | #endif |
---|
105 | |
---|
106 | #ifdef TLS |
---|
107 | #define THREAD_LOCAL static TLS |
---|
108 | #else |
---|
109 | #define THREAD_LOCAL static |
---|
110 | #endif |
---|
111 | |
---|
112 | #if defined(__linux__) && defined(__NR_gettid) && defined(HAVE_JRAND48) |
---|
113 | #define DO_JRAND_MIX |
---|
114 | THREAD_LOCAL unsigned short jrand_seed[3]; |
---|
115 | #endif |
---|
116 | |
---|
117 | #ifdef _WIN32 |
---|
118 | static void gettimeofday (struct timeval *tv, void *dummy) |
---|
119 | { |
---|
120 | FILETIME ftime; |
---|
121 | uint64_t n; |
---|
122 | |
---|
123 | GetSystemTimeAsFileTime (&ftime); |
---|
124 | n = (((uint64_t) ftime.dwHighDateTime << 32) |
---|
125 | + (uint64_t) ftime.dwLowDateTime); |
---|
126 | if (n) { |
---|
127 | n /= 10; |
---|
128 | n -= ((369 * 365 + 89) * (uint64_t) 86400) * 1000000; |
---|
129 | } |
---|
130 | |
---|
131 | tv->tv_sec = n / 1000000; |
---|
132 | tv->tv_usec = n % 1000000; |
---|
133 | } |
---|
134 | |
---|
135 | static int getuid (void) |
---|
136 | { |
---|
137 | return 1; |
---|
138 | } |
---|
139 | #endif |
---|
140 | |
---|
141 | static int get_random_fd(void) |
---|
142 | { |
---|
143 | struct timeval tv; |
---|
144 | static int fd = -2; |
---|
145 | int i; |
---|
146 | |
---|
147 | if (fd == -2) { |
---|
148 | gettimeofday(&tv, 0); |
---|
149 | #ifndef _WIN32 |
---|
150 | fd = open("/dev/urandom", O_RDONLY); |
---|
151 | if (fd == -1) |
---|
152 | fd = open("/dev/random", O_RDONLY | O_NONBLOCK); |
---|
153 | if (fd >= 0) { |
---|
154 | i = fcntl(fd, F_GETFD); |
---|
155 | if (i >= 0) |
---|
156 | fcntl(fd, F_SETFD, i | FD_CLOEXEC); |
---|
157 | } |
---|
158 | #endif |
---|
159 | srand((getpid() << ((sizeof(pid_t)*CHAR_BIT)>>1)) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); |
---|
160 | #ifdef DO_JRAND_MIX |
---|
161 | jrand_seed[0] = getpid() ^ (tv.tv_sec & 0xFFFF); |
---|
162 | jrand_seed[1] = getppid() ^ (tv.tv_usec & 0xFFFF); |
---|
163 | jrand_seed[2] = (tv.tv_sec ^ tv.tv_usec) >> 16; |
---|
164 | #endif |
---|
165 | } |
---|
166 | /* Crank the random number generator a few times */ |
---|
167 | gettimeofday(&tv, 0); |
---|
168 | for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) |
---|
169 | rand(); |
---|
170 | return fd; |
---|
171 | } |
---|
172 | |
---|
173 | |
---|
174 | /* |
---|
175 | * Generate a series of random bytes. Use /dev/urandom if possible, |
---|
176 | * and if not, use srandom/random. |
---|
177 | */ |
---|
178 | static void get_random_bytes(void *buf, int nbytes) |
---|
179 | { |
---|
180 | int i, n = nbytes, fd = get_random_fd(); |
---|
181 | int lose_counter = 0; |
---|
182 | unsigned char *cp = (unsigned char *) buf; |
---|
183 | #ifdef DO_JRAND_MIX |
---|
184 | unsigned short tmp_seed[3]; |
---|
185 | #endif |
---|
186 | |
---|
187 | if (fd >= 0) { |
---|
188 | while (n > 0) { |
---|
189 | i = read(fd, cp, n); |
---|
190 | if (i <= 0) { |
---|
191 | if (lose_counter++ > 16) |
---|
192 | break; |
---|
193 | continue; |
---|
194 | } |
---|
195 | n -= i; |
---|
196 | cp += i; |
---|
197 | lose_counter = 0; |
---|
198 | } |
---|
199 | } |
---|
200 | |
---|
201 | /* |
---|
202 | * We do this all the time, but this is the only source of |
---|
203 | * randomness if /dev/random/urandom is out to lunch. |
---|
204 | */ |
---|
205 | for (cp = buf, i = 0; i < nbytes; i++) |
---|
206 | *cp++ ^= (rand() >> 7) & 0xFF; |
---|
207 | #ifdef DO_JRAND_MIX |
---|
208 | memcpy(tmp_seed, jrand_seed, sizeof(tmp_seed)); |
---|
209 | jrand_seed[2] = jrand_seed[2] ^ syscall(__NR_gettid); |
---|
210 | for (cp = buf, i = 0; i < nbytes; i++) |
---|
211 | *cp++ ^= (jrand48(tmp_seed) >> 7) & 0xFF; |
---|
212 | memcpy(jrand_seed, tmp_seed, |
---|
213 | sizeof(jrand_seed)-sizeof(unsigned short)); |
---|
214 | #endif |
---|
215 | |
---|
216 | return; |
---|
217 | } |
---|
218 | |
---|
219 | /* |
---|
220 | * Get the ethernet hardware address, if we can find it... |
---|
221 | * |
---|
222 | * XXX for a windows version, probably should use GetAdaptersInfo: |
---|
223 | * http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451 |
---|
224 | * commenting out get_node_id just to get gen_uuid to compile under windows |
---|
225 | * is not the right way to go! |
---|
226 | */ |
---|
227 | static int get_node_id(unsigned char *node_id) |
---|
228 | { |
---|
229 | #ifdef HAVE_NET_IF_H |
---|
230 | int sd; |
---|
231 | struct ifreq ifr, *ifrp; |
---|
232 | struct ifconf ifc; |
---|
233 | char buf[1024]; |
---|
234 | int n, i; |
---|
235 | unsigned char *a; |
---|
236 | #ifdef HAVE_NET_IF_DL_H |
---|
237 | struct sockaddr_dl *sdlp; |
---|
238 | #endif |
---|
239 | |
---|
240 | /* |
---|
241 | * BSD 4.4 defines the size of an ifreq to be |
---|
242 | * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len |
---|
243 | * However, under earlier systems, sa_len isn't present, so the size is |
---|
244 | * just sizeof(struct ifreq) |
---|
245 | */ |
---|
246 | #ifdef HAVE_SA_LEN |
---|
247 | #ifndef max |
---|
248 | #define max(a,b) ((a) > (b) ? (a) : (b)) |
---|
249 | #endif |
---|
250 | #define ifreq_size(i) max(sizeof(struct ifreq),\ |
---|
251 | sizeof((i).ifr_name)+(i).ifr_addr.sa_len) |
---|
252 | #else |
---|
253 | #define ifreq_size(i) sizeof(struct ifreq) |
---|
254 | #endif /* HAVE_SA_LEN*/ |
---|
255 | |
---|
256 | sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); |
---|
257 | if (sd < 0) { |
---|
258 | return -1; |
---|
259 | } |
---|
260 | memset(buf, 0, sizeof(buf)); |
---|
261 | ifc.ifc_len = sizeof(buf); |
---|
262 | ifc.ifc_buf = buf; |
---|
263 | if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) { |
---|
264 | close(sd); |
---|
265 | return -1; |
---|
266 | } |
---|
267 | n = ifc.ifc_len; |
---|
268 | for (i = 0; i < n; i+= ifreq_size(*ifrp) ) { |
---|
269 | ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i); |
---|
270 | strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); |
---|
271 | #ifdef SIOCGIFHWADDR |
---|
272 | if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) |
---|
273 | continue; |
---|
274 | a = (unsigned char *) &ifr.ifr_hwaddr.sa_data; |
---|
275 | #else |
---|
276 | #ifdef SIOCGENADDR |
---|
277 | if (ioctl(sd, SIOCGENADDR, &ifr) < 0) |
---|
278 | continue; |
---|
279 | a = (unsigned char *) ifr.ifr_enaddr; |
---|
280 | #else |
---|
281 | #ifdef HAVE_NET_IF_DL_H |
---|
282 | sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr; |
---|
283 | if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6)) |
---|
284 | continue; |
---|
285 | a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen]; |
---|
286 | #else |
---|
287 | /* |
---|
288 | * XXX we don't have a way of getting the hardware |
---|
289 | * address |
---|
290 | */ |
---|
291 | close(sd); |
---|
292 | return 0; |
---|
293 | #endif /* HAVE_NET_IF_DL_H */ |
---|
294 | #endif /* SIOCGENADDR */ |
---|
295 | #endif /* SIOCGIFHWADDR */ |
---|
296 | if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) |
---|
297 | continue; |
---|
298 | if (node_id) { |
---|
299 | memcpy(node_id, a, 6); |
---|
300 | close(sd); |
---|
301 | return 1; |
---|
302 | } |
---|
303 | } |
---|
304 | close(sd); |
---|
305 | #endif |
---|
306 | return 0; |
---|
307 | } |
---|
308 | |
---|
309 | /* Assume that the gettimeofday() has microsecond granularity */ |
---|
310 | #define MAX_ADJUSTMENT 10 |
---|
311 | |
---|
312 | static int get_clock(uint32_t *clock_high, uint32_t *clock_low, |
---|
313 | uint16_t *ret_clock_seq, int *num) |
---|
314 | { |
---|
315 | THREAD_LOCAL int adjustment = 0; |
---|
316 | THREAD_LOCAL struct timeval last = {0, 0}; |
---|
317 | THREAD_LOCAL int state_fd = -2; |
---|
318 | THREAD_LOCAL FILE *state_f; |
---|
319 | THREAD_LOCAL uint16_t clock_seq; |
---|
320 | struct timeval tv; |
---|
321 | struct flock fl; |
---|
322 | uint64_t clock_reg; |
---|
323 | mode_t save_umask; |
---|
324 | int len; |
---|
325 | |
---|
326 | if (state_fd == -2) { |
---|
327 | save_umask = umask(0); |
---|
328 | state_fd = open("/var/lib/libuuid/clock.txt", |
---|
329 | O_RDWR|O_CREAT, 0660); |
---|
330 | (void) umask(save_umask); |
---|
331 | state_f = fdopen(state_fd, "r+"); |
---|
332 | if (!state_f) { |
---|
333 | close(state_fd); |
---|
334 | state_fd = -1; |
---|
335 | } |
---|
336 | } |
---|
337 | fl.l_type = F_WRLCK; |
---|
338 | fl.l_whence = SEEK_SET; |
---|
339 | fl.l_start = 0; |
---|
340 | fl.l_len = 0; |
---|
341 | fl.l_pid = 0; |
---|
342 | if (state_fd >= 0) { |
---|
343 | rewind(state_f); |
---|
344 | while (fcntl(state_fd, F_SETLKW, &fl) < 0) { |
---|
345 | if ((errno == EAGAIN) || (errno == EINTR)) |
---|
346 | continue; |
---|
347 | fclose(state_f); |
---|
348 | close(state_fd); |
---|
349 | state_fd = -1; |
---|
350 | break; |
---|
351 | } |
---|
352 | } |
---|
353 | if (state_fd >= 0) { |
---|
354 | unsigned int cl; |
---|
355 | unsigned long tv1, tv2; |
---|
356 | int a; |
---|
357 | |
---|
358 | if (fscanf(state_f, "clock: %04x tv: %lu %lu adj: %d\n", |
---|
359 | &cl, &tv1, &tv2, &a) == 4) { |
---|
360 | clock_seq = cl & 0x3FFF; |
---|
361 | last.tv_sec = tv1; |
---|
362 | last.tv_usec = tv2; |
---|
363 | adjustment = a; |
---|
364 | } |
---|
365 | } |
---|
366 | |
---|
367 | if ((last.tv_sec == 0) && (last.tv_usec == 0)) { |
---|
368 | get_random_bytes(&clock_seq, sizeof(clock_seq)); |
---|
369 | clock_seq &= 0x3FFF; |
---|
370 | gettimeofday(&last, 0); |
---|
371 | last.tv_sec--; |
---|
372 | } |
---|
373 | |
---|
374 | try_again: |
---|
375 | gettimeofday(&tv, 0); |
---|
376 | if ((tv.tv_sec < last.tv_sec) || |
---|
377 | ((tv.tv_sec == last.tv_sec) && |
---|
378 | (tv.tv_usec < last.tv_usec))) { |
---|
379 | clock_seq = (clock_seq+1) & 0x3FFF; |
---|
380 | adjustment = 0; |
---|
381 | last = tv; |
---|
382 | } else if ((tv.tv_sec == last.tv_sec) && |
---|
383 | (tv.tv_usec == last.tv_usec)) { |
---|
384 | if (adjustment >= MAX_ADJUSTMENT) |
---|
385 | goto try_again; |
---|
386 | adjustment++; |
---|
387 | } else { |
---|
388 | adjustment = 0; |
---|
389 | last = tv; |
---|
390 | } |
---|
391 | |
---|
392 | clock_reg = tv.tv_usec*10 + adjustment; |
---|
393 | clock_reg += ((uint64_t) tv.tv_sec)*10000000; |
---|
394 | clock_reg += (((uint64_t) 0x01B21DD2) << 32) + 0x13814000; |
---|
395 | |
---|
396 | if (num && (*num > 1)) { |
---|
397 | adjustment += *num - 1; |
---|
398 | last.tv_usec += adjustment / 10; |
---|
399 | adjustment = adjustment % 10; |
---|
400 | last.tv_sec += last.tv_usec / 1000000; |
---|
401 | last.tv_usec = last.tv_usec % 1000000; |
---|
402 | } |
---|
403 | |
---|
404 | if (state_fd > 0) { |
---|
405 | rewind(state_f); |
---|
406 | len = fprintf(state_f, |
---|
407 | "clock: %04x tv: %016lu %08lu adj: %08d\n", |
---|
408 | clock_seq, last.tv_sec, last.tv_usec, adjustment); |
---|
409 | fflush(state_f); |
---|
410 | if (ftruncate(state_fd, len) < 0) { |
---|
411 | fprintf(state_f, " \n"); |
---|
412 | fflush(state_f); |
---|
413 | } |
---|
414 | rewind(state_f); |
---|
415 | fl.l_type = F_UNLCK; |
---|
416 | fcntl(state_fd, F_SETLK, &fl); |
---|
417 | } |
---|
418 | |
---|
419 | *clock_high = clock_reg >> 32; |
---|
420 | *clock_low = clock_reg; |
---|
421 | *ret_clock_seq = clock_seq; |
---|
422 | return 0; |
---|
423 | } |
---|
424 | |
---|
425 | /* unused */ |
---|
426 | #if defined(USE_UUIDD) && defined(HAVE_SYS_UN_H) |
---|
427 | static ssize_t read_all(int fd, char *buf, size_t count) |
---|
428 | { |
---|
429 | ssize_t ret; |
---|
430 | ssize_t c = 0; |
---|
431 | |
---|
432 | memset(buf, 0, count); |
---|
433 | while (count > 0) { |
---|
434 | ret = read(fd, buf, count); |
---|
435 | if (ret < 0) { |
---|
436 | if ((errno == EAGAIN) || (errno == EINTR)) |
---|
437 | continue; |
---|
438 | return -1; |
---|
439 | } |
---|
440 | count -= ret; |
---|
441 | buf += ret; |
---|
442 | c += ret; |
---|
443 | } |
---|
444 | return c; |
---|
445 | } |
---|
446 | #endif |
---|
447 | |
---|
448 | #if defined(USE_UUIDD) && defined(HAVE_SYS_UN_H) |
---|
449 | |
---|
450 | /* |
---|
451 | * Close all file descriptors |
---|
452 | */ |
---|
453 | static void close_all_fds(void) |
---|
454 | { |
---|
455 | int i, max; |
---|
456 | |
---|
457 | #if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) |
---|
458 | max = sysconf(_SC_OPEN_MAX); |
---|
459 | #elif defined(HAVE_GETDTABLESIZE) |
---|
460 | max = getdtablesize(); |
---|
461 | #elif defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) |
---|
462 | struct rlimit rl; |
---|
463 | |
---|
464 | getrlimit(RLIMIT_NOFILE, &rl); |
---|
465 | max = rl.rlim_cur; |
---|
466 | #else |
---|
467 | max = OPEN_MAX; |
---|
468 | #endif |
---|
469 | |
---|
470 | for (i=0; i < max; i++) |
---|
471 | close(i); |
---|
472 | } |
---|
473 | |
---|
474 | #endif |
---|
475 | |
---|
476 | |
---|
477 | /* |
---|
478 | * Try using the uuidd daemon to generate the UUID |
---|
479 | * |
---|
480 | * Returns 0 on success, non-zero on failure. |
---|
481 | */ |
---|
482 | static int get_uuid_via_daemon(int op, uuid_t out, int *num) |
---|
483 | { |
---|
484 | #if defined(USE_UUIDD) && defined(HAVE_SYS_UN_H) |
---|
485 | char op_buf[64]; |
---|
486 | int op_len; |
---|
487 | int s; |
---|
488 | ssize_t ret; |
---|
489 | int32_t reply_len = 0, expected = 16; |
---|
490 | struct sockaddr_un srv_addr; |
---|
491 | pid_t pid; |
---|
492 | static const char *uuidd_path = UUIDD_PATH; |
---|
493 | static int access_ret = -2; |
---|
494 | static int start_attempts = 0; |
---|
495 | |
---|
496 | if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) |
---|
497 | return -1; |
---|
498 | |
---|
499 | srv_addr.sun_family = AF_UNIX; |
---|
500 | strcpy(srv_addr.sun_path, UUIDD_SOCKET_PATH); |
---|
501 | |
---|
502 | if (connect(s, (const struct sockaddr *) &srv_addr, |
---|
503 | sizeof(struct sockaddr_un)) < 0) { |
---|
504 | if (access_ret == -2) |
---|
505 | access_ret = access(uuidd_path, X_OK); |
---|
506 | if (access_ret == 0 && start_attempts++ < 5) { |
---|
507 | if ((pid = fork()) == 0) { |
---|
508 | close_all_fds(); |
---|
509 | execl(uuidd_path, "uuidd", "-qT", "300", |
---|
510 | (char *) NULL); |
---|
511 | exit(1); |
---|
512 | } |
---|
513 | (void) waitpid(pid, 0, 0); |
---|
514 | if (connect(s, (const struct sockaddr *) &srv_addr, |
---|
515 | sizeof(struct sockaddr_un)) < 0) |
---|
516 | goto fail; |
---|
517 | } else |
---|
518 | goto fail; |
---|
519 | } |
---|
520 | op_buf[0] = op; |
---|
521 | op_len = 1; |
---|
522 | if (op == UUIDD_OP_BULK_TIME_UUID) { |
---|
523 | memcpy(op_buf+1, num, sizeof(*num)); |
---|
524 | op_len += sizeof(*num); |
---|
525 | expected += sizeof(*num); |
---|
526 | } |
---|
527 | |
---|
528 | ret = write(s, op_buf, op_len); |
---|
529 | if (ret < 1) |
---|
530 | goto fail; |
---|
531 | |
---|
532 | ret = read_all(s, (char *) &reply_len, sizeof(reply_len)); |
---|
533 | if (ret < 0) |
---|
534 | goto fail; |
---|
535 | |
---|
536 | if (reply_len != expected) |
---|
537 | goto fail; |
---|
538 | |
---|
539 | ret = read_all(s, op_buf, reply_len); |
---|
540 | |
---|
541 | if (op == UUIDD_OP_BULK_TIME_UUID) |
---|
542 | memcpy(op_buf+16, num, sizeof(int)); |
---|
543 | |
---|
544 | memcpy(out, op_buf, 16); |
---|
545 | |
---|
546 | close(s); |
---|
547 | return ((ret == expected) ? 0 : -1); |
---|
548 | |
---|
549 | fail: |
---|
550 | close(s); |
---|
551 | #endif |
---|
552 | return -1; |
---|
553 | } |
---|
554 | |
---|
555 | void uuid__generate_time(uuid_t out, int *num) |
---|
556 | { |
---|
557 | static unsigned char node_id[6]; |
---|
558 | static int has_init = 0; |
---|
559 | struct uuid uu; |
---|
560 | uint32_t clock_mid; |
---|
561 | |
---|
562 | if (!has_init) { |
---|
563 | if (get_node_id(node_id) <= 0) { |
---|
564 | get_random_bytes(node_id, 6); |
---|
565 | /* |
---|
566 | * Set multicast bit, to prevent conflicts |
---|
567 | * with IEEE 802 addresses obtained from |
---|
568 | * network cards |
---|
569 | */ |
---|
570 | node_id[0] |= 0x01; |
---|
571 | } |
---|
572 | has_init = 1; |
---|
573 | } |
---|
574 | get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num); |
---|
575 | uu.clock_seq |= 0x8000; |
---|
576 | uu.time_mid = (uint16_t) clock_mid; |
---|
577 | uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000; |
---|
578 | memcpy(uu.node, node_id, 6); |
---|
579 | uuid_pack(&uu, out); |
---|
580 | } |
---|
581 | |
---|
582 | void uuid_generate_time(uuid_t out) |
---|
583 | { |
---|
584 | #ifdef TLS |
---|
585 | THREAD_LOCAL int num = 0; |
---|
586 | THREAD_LOCAL struct uuid uu; |
---|
587 | THREAD_LOCAL time_t last_time = 0; |
---|
588 | time_t now; |
---|
589 | |
---|
590 | if (num > 0) { |
---|
591 | now = time(0); |
---|
592 | if (now > last_time+1) |
---|
593 | num = 0; |
---|
594 | } |
---|
595 | if (num <= 0) { |
---|
596 | num = 1000; |
---|
597 | if (get_uuid_via_daemon(UUIDD_OP_BULK_TIME_UUID, |
---|
598 | out, &num) == 0) { |
---|
599 | last_time = time(0); |
---|
600 | uuid_unpack(out, &uu); |
---|
601 | num--; |
---|
602 | return; |
---|
603 | } |
---|
604 | num = 0; |
---|
605 | } |
---|
606 | if (num > 0) { |
---|
607 | uu.time_low++; |
---|
608 | if (uu.time_low == 0) { |
---|
609 | uu.time_mid++; |
---|
610 | if (uu.time_mid == 0) |
---|
611 | uu.time_hi_and_version++; |
---|
612 | } |
---|
613 | num--; |
---|
614 | uuid_pack(&uu, out); |
---|
615 | return; |
---|
616 | } |
---|
617 | #else |
---|
618 | if (get_uuid_via_daemon(UUIDD_OP_TIME_UUID, out, 0) == 0) |
---|
619 | return; |
---|
620 | #endif |
---|
621 | |
---|
622 | uuid__generate_time(out, 0); |
---|
623 | } |
---|
624 | |
---|
625 | |
---|
626 | void uuid__generate_random(uuid_t out, int *num) |
---|
627 | { |
---|
628 | uuid_t buf; |
---|
629 | struct uuid uu; |
---|
630 | int i, n; |
---|
631 | |
---|
632 | if (!num || !*num) |
---|
633 | n = 1; |
---|
634 | else |
---|
635 | n = *num; |
---|
636 | |
---|
637 | for (i = 0; i < n; i++) { |
---|
638 | get_random_bytes(buf, sizeof(buf)); |
---|
639 | uuid_unpack(buf, &uu); |
---|
640 | |
---|
641 | uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000; |
---|
642 | uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) |
---|
643 | | 0x4000; |
---|
644 | uuid_pack(&uu, out); |
---|
645 | out += sizeof(uuid_t); |
---|
646 | } |
---|
647 | } |
---|
648 | |
---|
649 | void uuid_generate_random(uuid_t out) |
---|
650 | { |
---|
651 | int num = 1; |
---|
652 | /* No real reason to use the daemon for random uuid's -- yet */ |
---|
653 | |
---|
654 | uuid__generate_random(out, &num); |
---|
655 | } |
---|
656 | |
---|
657 | |
---|
658 | /* |
---|
659 | * This is the generic front-end to uuid_generate_random and |
---|
660 | * uuid_generate_time. It uses uuid_generate_random only if |
---|
661 | * /dev/urandom is available, since otherwise we won't have |
---|
662 | * high-quality randomness. |
---|
663 | */ |
---|
664 | void uuid_generate(uuid_t out) |
---|
665 | { |
---|
666 | if (get_random_fd() >= 0) |
---|
667 | uuid_generate_random(out); |
---|
668 | else |
---|
669 | uuid_generate_time(out); |
---|
670 | } |
---|