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