From b19d1a959eeea17d6b899a5b994bf3f3691de947 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 18 Jun 1999 00:32:03 +0000 Subject: [PATCH] Many files: * 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. uuidgen.1.in: Miscellaneous text cleanups. --- lib/uuid/ChangeLog | 30 +++++++++++++++++ lib/uuid/Makefile.in | 3 ++ lib/uuid/gen_uuid.c | 58 +++++++++++++++++++++++++++++---- lib/uuid/libuuid.3.in | 2 ++ lib/uuid/tst_uuid.c | 55 ++++++++++++++++++++++++++++++-- lib/uuid/uuid.h | 10 ++++-- lib/uuid/uuid_generate.3.in | 38 ++++++++++++++++++---- lib/uuid/uuid_parse.3.in | 2 +- lib/uuid/uuid_time.c | 78 +++++++++++++++++++++++++++++++++++++++++++-- misc/uuidgen.1.in | 6 ++-- 10 files changed, 258 insertions(+), 24 deletions(-) diff --git a/lib/uuid/ChangeLog b/lib/uuid/ChangeLog index c38761c6..3fec3870 100644 --- a/lib/uuid/ChangeLog +++ b/lib/uuid/ChangeLog @@ -1,3 +1,33 @@ +1999-05-17 + + * 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 * compare.c (uuid_compare): Change sense of uuid_compare so that diff --git a/lib/uuid/Makefile.in b/lib/uuid/Makefile.in index 69a71c1b..ca924f36 100644 --- a/lib/uuid/Makefile.in +++ b/lib/uuid/Makefile.in @@ -144,6 +144,9 @@ clean:: $(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 diff --git a/lib/uuid/gen_uuid.c b/lib/uuid/gen_uuid.c index 328a58fd..0ed1a91b 100644 --- a/lib/uuid/gen_uuid.c +++ b/lib/uuid/gen_uuid.c @@ -17,6 +17,7 @@ #endif #include #include +#include #include #include #include @@ -54,17 +55,26 @@ static void get_random_bytes(void *buf, int nbytes) 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; + } /* @@ -184,7 +194,7 @@ try_again: 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; @@ -210,3 +220,39 @@ void uuid_generate(uuid_t out) 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); +} + diff --git a/lib/uuid/libuuid.3.in b/lib/uuid/libuuid.3.in index 4fd9549e..ea69e0ac 100644 --- a/lib/uuid/libuuid.3.in +++ b/lib/uuid/libuuid.3.in @@ -12,6 +12,8 @@ libuuid \- DCE compatible Universally Unique Identifier library .nf .B #include .sp +cc +.I file.c .B \-luuid .SH DESCRIPTION The diff --git a/lib/uuid/tst_uuid.c b/lib/uuid/tst_uuid.c index f7984701..b9fc5f69 100644 --- a/lib/uuid/tst_uuid.c +++ b/lib/uuid/tst_uuid.c @@ -24,22 +24,71 @@ main(int argc, char **argv) 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"); @@ -53,7 +102,7 @@ main(int argc, char **argv) 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"); diff --git a/lib/uuid/uuid.h b/lib/uuid/uuid.h index cf3a89ff..83541114 100644 --- a/lib/uuid/uuid.h +++ b/lib/uuid/uuid.h @@ -15,6 +15,12 @@ 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); @@ -38,5 +44,5 @@ void uuid_unparse(uuid_t uu, char *out); /* 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); diff --git a/lib/uuid/uuid_generate.3.in b/lib/uuid/uuid_generate.3.in index 33455f67..07764f98 100644 --- a/lib/uuid/uuid_generate.3.in +++ b/lib/uuid/uuid_generate.3.in @@ -13,16 +13,42 @@ uuid_generate \- create a new unique UUID value .B #include .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 diff --git a/lib/uuid/uuid_parse.3.in b/lib/uuid/uuid_parse.3.in index ab76cddf..221a10d9 100644 --- a/lib/uuid/uuid_parse.3.in +++ b/lib/uuid/uuid_parse.3.in @@ -17,7 +17,7 @@ uuid_parse \- convert an input UUID string into the libuuid internal format .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 diff --git a/lib/uuid/uuid_time.c b/lib/uuid/uuid_time.c index 2d9804f5..65264965 100644 --- a/lib/uuid/uuid_time.c +++ b/lib/uuid/uuid_time.c @@ -1,7 +1,9 @@ /* - * 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 @@ -41,13 +43,54 @@ time_t uuid_time(uuid_t uu, struct timeval *ret_tv) 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]); @@ -57,8 +100,37 @@ main(int argc, char **argv) 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)); diff --git a/misc/uuidgen.1.in b/misc/uuidgen.1.in index 48e8ffcf..049b663f 100644 --- a/misc/uuidgen.1.in +++ b/misc/uuidgen.1.in @@ -5,9 +5,9 @@ .\" 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 @@ -15,7 +15,7 @@ uuidgen \- command\-line utility to create a new unique UUID value .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 -- 2.11.0