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