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