summaryrefslogtreecommitdiffstats
path: root/misc-utils
diff options
context:
space:
mode:
authorPhilip Prindeville2017-08-28 21:36:30 +0200
committerKarel Zak2017-09-05 11:56:24 +0200
commitc6f1ec68a8b38863efff2a18e30b7272db4fb273 (patch)
tree788a3325d6e02b23b35e87796c57c743528bea6e /misc-utils
parentmisc: replace magic number 37 with UUID_STR_LEN (diff)
downloadkernel-qcow2-util-linux-c6f1ec68a8b38863efff2a18e30b7272db4fb273.tar.gz
kernel-qcow2-util-linux-c6f1ec68a8b38863efff2a18e30b7272db4fb273.tar.xz
kernel-qcow2-util-linux-c6f1ec68a8b38863efff2a18e30b7272db4fb273.zip
uuidgen: add support for hash-based UUIDs
Signed-off-by: Philip Prindeville <philipp@redfish-solutions.com>
Diffstat (limited to 'misc-utils')
-rw-r--r--misc-utils/uuidgen.147
-rw-r--r--misc-utils/uuidgen.c124
2 files changed, 162 insertions, 9 deletions
diff --git a/misc-utils/uuidgen.1 b/misc-utils/uuidgen.1
index 56c2bc7bd..500e3124c 100644
--- a/misc-utils/uuidgen.1
+++ b/misc-utils/uuidgen.1
@@ -18,18 +18,41 @@ all UUIDs created on the local system,
and among UUIDs created on other systems in the past
and in the future.
.PP
-There are two types of UUIDs which
+There are three types of UUIDs which
.B uuidgen
-can generate: time-based UUIDs and random-based UUIDs. By default
+can generate: time-based UUIDs, random-based UUIDs, and hash-based UUIDs.
+By default
.B uuidgen
will generate a random-based UUID if a high-quality random number
generator is present. Otherwise, it will choose a time-based UUID.
-It is possible to force the generation of one of these two
+It is possible to force the generation of one of these first two
UUID types by using the
.B \-r
or
.B \-t
options.
+.PP
+The third type of UUID is generated with the
+.B \-m
+or
+.B \-s
+options (MD5 or SHA1, respectively), followed by
+.BR "\-n " \fInamespace
+and
+.BR "\-N " \fIname\fR.
+The \fInamespace\fR may either be a well-known UUID, or else
+an alias to one of the well-known UUIDs defined in RFC 4122, that is
+.BR @dns ,
+.BR @url ,
+.BR @oid ,
+or
+.BR @x500 .
+The \fIname\fR is an arbitrary string value. The generated UUID is the
+digest of the concatentation of the namespace UUID and the name value, hashed
+with the MD5 or SHA1 algorithms. It is, therefore, a predictable value
+which may be useful when UUIDs are being used as handles or nonces for
+more complex values or values which shouldn't be disclosed directly.
+See the RFC for more information.
.SH OPTIONS
.TP
.BR \-r , " \-\-random"
@@ -47,13 +70,29 @@ Display help text and exit.
.TP
.BR \-V , " \-\-version"
Display version information and exit.
+.TP
+.BR \-m , " \-\-md5"
+Use MD5 as the hash algorithm.
+.TP
+.BR \-s , " \-\-sha1"
+Use SHA1 as the hash algorith.
+.TP
+.BR \-n , " \-\-namespace " \fInamespace\fP
+Generate the hash with the \fInamespace\fP prefix.
+.TP
+.BR \-N , " \-\-name " \fIname\fR
+Generate the hash of the \fIname\fR.
+.TP
+.BR \-x , " \-\-hex"
+Interpret name \fIname\fR as a hexidecimal string.
.SH "CONFORMING TO"
OSF DCE 1.1
.SH AUTHOR
.B uuidgen
was written by Andreas Dilger for libuuid.
.SH SEE ALSO
-.BR libuuid (3)
+.BR libuuid (3),
+.B "RFC 4122"
.SH AVAILABILITY
The uuidgen command is part of the util-linux package and is available from
https://www.kernel.org/pub/linux/utils/util-linux/.
diff --git a/misc-utils/uuidgen.c b/misc-utils/uuidgen.c
index ac950747d..c19706953 100644
--- a/misc-utils/uuidgen.c
+++ b/misc-utils/uuidgen.c
@@ -29,27 +29,75 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(_("Create a new UUID value.\n"), out);
fputs(USAGE_OPTIONS, out);
- fputs(_(" -r, --random generate random-based uuid\n"), out);
- fputs(_(" -t, --time generate time-based uuid\n"), out);
+ fputs(_(" -r, --random generate random-based uuid\n"), out);
+ fputs(_(" -t, --time generate time-based uuid\n"), out);
+ fputs(_(" -n, --namespace ns generate hash-based uuid in this namespace\n"), out);
+ fputs(_(" -N, --name name generate hash-based uuid from this name\n"), out);
+ fputs(_(" -m, --md5 generate md5 hash\n"), out);
+ fputs(_(" -s, --sha1 generate sha1 hash\n"), out);
+ fputs(_(" -x, --hex interpret name as hex string\n"), out);
fputs(USAGE_SEPARATOR, out);
printf(USAGE_HELP_OPTIONS(18));
printf(USAGE_MAN_TAIL("uuidgen(1)"));
exit(EXIT_SUCCESS);
}
+static char *unhex(const char *value, size_t *valuelen)
+{
+ char c, *value2;
+ unsigned n, x;
+
+ if (*valuelen % 2 != 0) {
+badstring:
+ fprintf(stderr, "%s: not a valid hex string\n", program_invocation_short_name);
+ errtryhelp(EXIT_FAILURE);
+ }
+
+ value2 = malloc(*valuelen / 2 + 1);
+
+ for (x = n = 0; n < *valuelen; n++) {
+ c = value[n];
+ if ('0' <= c && c <= '9')
+ x += c - '0';
+ else if (('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'))
+ x += (c - 'A' + 10) & 0xf;
+ else
+ goto badstring;
+
+ if (n % 2 == 0)
+ x *= 16;
+ else {
+ value2[n / 2] = x;
+ x = 0;
+ }
+ }
+ value2[n / 2] = '\0';
+
+ *valuelen = (n / 2);
+
+ return value2;
+}
+
int
main (int argc, char *argv[])
{
int c;
- int do_type = 0;
+ int do_type = 0, is_hex = 0;
char str[UUID_STR_LEN];
- uuid_t uu;
+ char *namespace = NULL, *name = NULL;
+ size_t namelen = 0;
+ uuid_t ns, uu;
static const struct option longopts[] = {
{"random", no_argument, NULL, 'r'},
{"time", no_argument, NULL, 't'},
{"version", no_argument, NULL, 'V'},
{"help", no_argument, NULL, 'h'},
+ {"namespace", required_argument, NULL, 'n'},
+ {"name", required_argument, NULL, 'N'},
+ {"md5", no_argument, NULL, 'm'},
+ {"sha1", no_argument, NULL, 's'},
+ {"hex", no_argument, NULL, 'x'},
{NULL, 0, NULL, 0}
};
@@ -58,7 +106,7 @@ main (int argc, char *argv[])
textdomain(PACKAGE);
atexit(close_stdout);
- while ((c = getopt_long(argc, argv, "rtVh", longopts, NULL)) != -1)
+ while ((c = getopt_long(argc, argv, "rtVhn:N:msx", longopts, NULL)) != -1)
switch (c) {
case 't':
do_type = UUID_TYPE_DCE_TIME;
@@ -69,12 +117,53 @@ main (int argc, char *argv[])
case 'V':
printf(UTIL_LINUX_VERSION);
return EXIT_SUCCESS;
+ case 'n':
+ namespace = optarg;
+ break;
+ case 'N':
+ name = optarg;
+ break;
+ case 'm':
+ do_type = UUID_TYPE_DCE_MD5;
+ break;
+ case 's':
+ do_type = UUID_TYPE_DCE_SHA1;
+ break;
+ case 'x':
+ is_hex = 1;
+ break;
case 'h':
usage();
default:
errtryhelp(EXIT_FAILURE);
}
+ if (namespace) {
+ if (!name) {
+ fprintf(stderr, "%s: --namespace requires --name argument\n", program_invocation_short_name);
+ errtryhelp(EXIT_FAILURE);
+ }
+ if (do_type != UUID_TYPE_DCE_MD5 && do_type != UUID_TYPE_DCE_SHA1) {
+ fprintf(stderr, "%s: --namespace requires --md5 or --sha1\n", program_invocation_short_name);
+ errtryhelp(EXIT_FAILURE);
+ }
+ } else {
+ if (name) {
+ fprintf(stderr, "%s: --name requires --namespace argument\n", program_invocation_short_name);
+ errtryhelp(EXIT_FAILURE);
+ }
+ if (do_type == UUID_TYPE_DCE_MD5 || do_type == UUID_TYPE_DCE_SHA1) {
+ fprintf(stderr, "%s: --md5 or --sha1 require --namespace\n", program_invocation_short_name);
+ errtryhelp(EXIT_FAILURE);
+ }
+ }
+
+ if (name) {
+ namelen = strlen(name);
+ if (is_hex)
+ name = unhex(name, &namelen);
+ }
+
switch (do_type) {
case UUID_TYPE_DCE_TIME:
uuid_generate_time(uu);
@@ -82,6 +171,28 @@ main (int argc, char *argv[])
case UUID_TYPE_DCE_RANDOM:
uuid_generate_random(uu);
break;
+ case UUID_TYPE_DCE_MD5:
+ case UUID_TYPE_DCE_SHA1:
+ if (namespace[0] == '@' && namespace[1] != '\0') {
+ const uuid_t *uuidptr;
+
+ uuidptr = uuid_get_template(&namespace[1]);
+ if (uuidptr == NULL) {
+ fprintf(stderr, "%s: unknown namespace alias '%s'\n", program_invocation_short_name, namespace);
+ errtryhelp(EXIT_FAILURE);
+ }
+ memcpy(ns, *uuidptr, sizeof(ns));
+ } else {
+ if (uuid_parse(namespace, ns) != 0) {
+ fprintf(stderr, "%s: invalid uuid for namespace '%s'\n", program_invocation_short_name, namespace);
+ errtryhelp(EXIT_FAILURE);
+ }
+ }
+ if (do_type == UUID_TYPE_DCE_MD5)
+ uuid_generate_md5(uu, ns, name, namelen);
+ else
+ uuid_generate_sha1(uu, ns, name, namelen);
+ break;
default:
uuid_generate(uu);
break;
@@ -91,5 +202,8 @@ main (int argc, char *argv[])
printf("%s\n", str);
+ if (is_hex)
+ free(name);
+
return EXIT_SUCCESS;
}