+1999-05-17 <tytso@rsts-11.mit.edu>
+
+ * gen_uuid.c (get_random_bytes): Use a while loop when reading
+ from /dev/urandom so that if we get interrupted while
+ reading the right thing happens.
+ (uuid_generate_random): Add new function which uses the
+ new UUID format which uses 122 random bits to form the
+ 128-bit UUID.
+ (uuid_generate): Rename the old uuid_generate to be
+ uuid_generate_time, and create a new uuid_generate
+ function which calls either uuid_generate_random or
+ uuid_genereate_time depending on whether /dev/urandom is
+ present.
+
+ * uuid_generate.3.in: Update to reflect changesin uuid_generate
+ and its two new variants.
+
+ * tst_uuid.c: Updated to test new uuid_generate functions, and to
+ reflect new semantics of uuid_compare. Added tests to
+ make sure the UUID type and variant created by UUID
+ generate is correct.
+
+ * uuid_time.c (uuid_variant, uuid_type): Added new functions to
+ return the UUID variant and type information. The
+ debugging program now prints the UUID variant and type,
+ and warns if the unparsed time information is likely to be
+ incorrect.
+
+ * uuid_parse.3.in, libuuid.3.in: Miscellaneous text cleanups.
+
1999-05-03 <tytso@rsts-11.mit.edu>
* compare.c (uuid_compare): Change sense of uuid_compare so that
$(RM) -f \#* *.s *.o *.a *~ *.bak core profiled/* checker/*
$(RM) -f ../libuuid.a ../libuuid_p.a tst_uuid uuid_time $(SMANPAGES)
+check:: tst_uuid
+ LD_LIBRARY_PATH=$(LIB) ./tst_uuid
+
mostlyclean:: clean
distclean:: clean
$(RM) -f .depend Makefile
#endif
#include <string.h>
#include <fcntl.h>
+#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
fd = open("/dev/urandom", O_RDONLY);
srand((getpid() << 16) ^ getuid() ^ time(0));
}
- if (fd > 0) {
- i = read(fd, cp, nbytes);
- if (i == nbytes)
- return;
- if (i > 0) {
+ if (fd >= 0) {
+ while (nbytes > 0) {
+ i = read(fd, cp, nbytes);
+ if (i < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+ break;
+ }
nbytes -= i;
cp += i;
}
}
+ if (nbytes == 0)
+ return;
+
+ /* XXX put something better here if no /dev/random! */
for (i=0; i < nbytes; i++)
*cp++ = rand() & 0xFF;
+ return;
+
}
/*
return 0;
}
-void uuid_generate(uuid_t out)
+void uuid_generate_time(uuid_t out)
{
static unsigned char node_id[6];
static int has_init = 0;
memcpy(uu.node, node_id, 6);
uuid_pack(&uu, out);
}
+
+void uuid_generate_random(uuid_t out)
+{
+ uuid_t buf;
+ struct uuid uu;
+
+ get_random_bytes(buf, sizeof(buf));
+ uuid_unpack(buf, &uu);
+
+ uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
+ uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000;
+ uuid_pack(&uu, out);
+}
+
+/*
+ * This is the generic front-end to uuid_generate_random and
+ * uuid_generate_time. It uses uuid_generate_random only if
+ * /dev/urandom is available, since otherwise we won't have
+ * high-quality randomness.
+ */
+void uuid_generate(uuid_t out)
+{
+ static int has_random = -1;
+
+ if (has_random < 0) {
+ if (access("/dev/urandom", R_OK) == 0)
+ has_random = 1;
+ else
+ has_random = 0;
+ }
+ if (has_random)
+ uuid_generate_random(out);
+ else
+ uuid_generate_time(out);
+}
+
.nf
.B #include <uuid/uuid.h>
.sp
+cc
+.I file.c
.B \-luuid
.SH DESCRIPTION
The
unsigned char *cp;
int i;
int failed = 0;
+ int type, variant;
uuid_generate(buf);
uuid_unparse(buf, str);
- printf("UUID string = %s\n", str);
+ printf("UUID generate = %s\n", str);
+ printf("UUID: ");
+ for (i=0, cp = (unsigned char *) &buf; i < 16; i++) {
+ printf("%02x", *cp++);
+ }
+ printf("\n");
+ type = uuid_type(buf); variant = uuid_variant(buf);
+ printf("UUID type = %d, UUID variant = %d\n", type, variant);
+ if (variant != UUID_VARIANT_DCE) {
+ printf("Incorrect UUID Variant; was expecting DCE!\n");
+ failed++;
+ }
+ printf("\n");
+
+ uuid_generate_random(buf);
+ uuid_unparse(buf, str);
+ printf("UUID random string = %s\n", str);
printf("UUID: ");
for (i=0, cp = (unsigned char *) &buf; i < 16; i++) {
printf("%02x", *cp++);
}
printf("\n");
+ type = uuid_type(buf); variant = uuid_variant(buf);
+ printf("UUID type = %d, UUID variant = %d\n", type, variant);
+ if (variant != UUID_VARIANT_DCE) {
+ printf("Incorrect UUID Variant; was expecting DCE!\n");
+ failed++;
+ }
+ if (type != 4) {
+ printf("Incorrect UUID type; was expecting "
+ "4 (random type)!\n");
+ failed++;
+ }
+ printf("\n");
+
+ uuid_generate_time(buf);
+ uuid_unparse(buf, str);
+ printf("UUID string = %s\n", str);
+ printf("UUID time: ");
+ for (i=0, cp = (unsigned char *) &buf; i < 16; i++) {
+ printf("%02x", *cp++);
+ }
+ printf("\n");
+ type = uuid_type(buf); variant = uuid_variant(buf);
+ printf("UUID type = %d, UUID variant = %d\n", type, variant);
+ if (variant != UUID_VARIANT_DCE) {
+ printf("Incorrect UUID Variant; was expecting DCE!\n");
+ failed++;
+ }
+ if (type != 1) {
+ printf("Incorrect UUID type; was expecting "
+ "1 (time-based type)!\\n");
+ failed++;
+ }
tv.tv_sec = 0;
tv.tv_usec = 0;
time_reg = uuid_time(buf, &tv);
printf("UUID time is: (%d, %d): %s\n", tv.tv_sec, tv.tv_usec,
ctime(&time_reg));
uuid_parse(str, tst);
- if (uuid_compare(buf, tst))
+ if (!uuid_compare(buf, tst))
printf("UUID parse and compare succeeded.\n");
else {
printf("UUID parse and compare failed!\n");
failed++;
}
uuid_copy(buf, tst);
- if (uuid_compare(buf, tst))
+ if (!uuid_compare(buf, tst))
printf("UUID copy and compare succeeded.\n");
else {
printf("UUID copy and compare failed!\n");
typedef unsigned char uuid_t[16];
+/* UUID Variant definitions */
+#define UUID_VARIANT_NCS 0
+#define UUID_VARIANT_DCE 1
+#define UUID_VARIANT_MICROSOFT 2
+#define UUID_VARIANT_OTHER 3
+
/* clear.c */
void uuid_clear(uuid_t uu);
/* uuid_time.c */
time_t uuid_time(uuid_t uu, struct timeval *ret_tv);
-
-
+int uuid_type(uuid_t uu);
+int uuid_variant(uuid_t uu);
.B #include <uuid/uuid.h>
.sp
.BI "void uuid_generate(uuid_t " out );
+.BI "void uuid_generate_random(uuid_t " out );
+.BI "void uuid_generate_time(uuid_t " out );
.fi
.SH DESCRIPTION
The
.B uuid_generate
-function creates a new universally unique identifier. Depending on
-compile\- and run\-time availability, the UUID will be based on the
-local ethernet MAC address (if available), random data from /dev/urandom
-or a pseudo\-random generator
-.BR rand "(3) or " random "(3),"
-and the current time.
+function creates a new universally unique identifier (UUID). The uuid will
+be generated based on high-quality randomness from
+.IR /dev/urandom ,
+if available. If it is not available, then
+.B uuid_generate
+will use an alternative algorithm which uses the current time, the
+local ethernet MAC address (if available), and random data generated
+using a pseudo-random generator.
+.sp
+The
+.B uuid_generate_random
+function forces the use of the all-random UUID format, even if
+a high-quality random number generator (i.e.,
+.IR /dev/urandom )
+is not available, in which case a pseudo-random
+generator will be subsituted. Note that the use of a pseudo-random
+generator may compromise the uniqueness of UUID's
+generated in this fashion.
+.sp
+The
+.B uuid_generate_time
+function forces the use of the alternative algorithm which uses the
+current time and the local ethernet MAC address (if available).
+This algorithm used to be the default one used to generate UUID, but
+because of the use of the ethernet MAC address, it can leak
+information about when and where the UUID was generated. This can cause
+privacy problems in some applications, so the
+.B uuid_generate
+function only uses this algorithm if a high-quality source of
+randomness is not available.
.sp
The UUID is 16 bytes (128 bits) long, which gives approximately 3.4x10^38
unique values (there are approximately 10^80 elemntary particles in
.SH DESCRIPTION
The
.B uuid_parse
-function converts the supplied UUID string given by
+function converts the UUID string given by
.I in
into the internal
.B uuid_t
/*
- * uuid_time.c --- Interpret the time field from a uuid
- *
- * Copyright (C) 1998 Theodore Ts'o.
+ * uuid_time.c --- Interpret the time field from a uuid. This program
+ * violates the UUID abstraction barrier by reaching into the guts
+ * of a UUID and interpreting it.
+ *
+ * Copyright (C) 1998, 1999 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
return tv.tv_sec;
}
+int uuid_type(uuid_t uu)
+{
+ struct uuid uuid;
+
+ uuid_unpack(uu, &uuid);
+ return ((uuid.time_hi_and_version >> 12) & 0xF);
+}
+
+int uuid_variant(uuid_t uu)
+{
+ struct uuid uuid;
+ int var;
+
+ uuid_unpack(uu, &uuid);
+ var = uuid.clock_seq;
+
+ if ((var & 0x8000) == 0)
+ return UUID_VARIANT_NCS;
+ if ((var & 0x4000) == 0)
+ return UUID_VARIANT_DCE;
+ if ((var & 0x2000) == 0)
+ return UUID_VARIANT_MICROSOFT;
+ return UUID_VARIANT_OTHER;
+}
+
#ifdef DEBUG
+const char *variant_string(int variant)
+{
+ switch (variant) {
+ case UUID_VARIANT_NCS:
+ return "NCS";
+ case UUID_VARIANT_DCE:
+ return "DCE";
+ case UUID_VARIANT_MICROSOFT:
+ return "Microsoft";
+ default:
+ return "Other";
+ }
+}
+
+
int
main(int argc, char **argv)
{
uuid_t buf;
time_t time_reg;
struct timeval tv;
+ int type, variant;
if (argc != 2) {
fprintf(stderr, "Usage: %s uuid\n", argv[0]);
fprintf(stderr, "Invalid UUID: %s\n", argv[1]);
exit(1);
}
+ variant = uuid_variant(buf);
+ type = uuid_type(buf);
time_reg = uuid_time(buf, &tv);
+ printf("UUID variant is %d (%s)\n", variant, variant_string(variant));
+ if (variant != UUID_VARIANT_DCE) {
+ printf("Warning: This program only knows how to interpret "
+ "DCE UUIDs.\n\tThe rest of the output is likely "
+ "to be incorrect!!\n");
+ }
+ printf("UUID type is %d", type);
+ switch (type) {
+ case 1:
+ printf(" (time based)\n");
+ break;
+ case 2:
+ printf(" (DCE)\n");
+ break;
+ case 3:
+ printf(" (name-based)\n");
+ break;
+ case 4:
+ printf(" (random)\n");
+ break;
+ default:
+ printf("\n");
+ }
+ if (type != 1) {
+ printf("Warning: not a time-based UUID, so UUID time "
+ "decoding will likely not work!\n");
+ }
printf("UUID time is: (%d, %d): %s\n", tv.tv_sec, tv.tv_usec,
ctime(&time_reg));
.\" This file may be copied under the terms of the GNU Public License.
.\"
.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger
-.TH UUIDGEN "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.TH UUIDGEN 1 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
.SH NAME
-uuidgen \- command\-line utility to create a new unique UUID value
+uuidgen \- command\-line utility to create a new UUID value
.SH SYNOPSIS
.nf
.B uuidgen
.SH DESCRIPTION
The
.B uuidgen
-program creates a new universally unique identifier using the
+program creates a new universally unique identifier (UUID) using the
.BR libuuid "(3) functions " uuid_generate "(3) and " uuid_unparse "(3)."
The new UUID can reasonably be considered unique among all UUIDs created
on the local system, and among UUIDs created on other systems in the past