Hi,

On Fri, 21 Aug 2020 22:34:35 +1000
Jonathan Matthew <jonat...@d14n.org> wrote:

> On Wed, Aug 19, 2020 at 09:28:41PM -0500, Scott Cheloha wrote:
> > Hi,
> > 
> > I was auditing the tree for odd-looking time structure usage and I
> > came across the UUID code in ldapd(8), uuid.c.
> > 
> > time_cmp() is backwards.  Or the caller is misusing it.  One or the
> > other.  It returns -1 if tv1 exceeds tv2 but the comments in the
> > caller indicate the opposite impression.  I don't think this code
> > has ever worked as intended.

The code is from the ARLA AFS implentation and essentially unchanged.
(Note: this project seems to be defunct for about 13 years, I found the
source at fossies.org.)

> > 
> > It would be a lot easier if we just threw the code out and used
> > random UUIDs.  After reading over the RFC it seems to me that
> > time-based UUIDs are collision-prone.  Their implementation is also
> > complicated. Purely random UUIDs should effectively never collide
> > and are trivial to implement.  
> 
> RFC 4530, defining the entryUUID attribute, says this:
> 
>    UUID are to be generated in accordance with Section 4 of [RFC4122].
>    In particular, servers MUST ensure that each generated UUID is
> unique in space and time.
> 
> Which doesn't rule out random uuids at all.  Is arc4random_buf() a
> better attempt at ensuring the uuids are unique than doing
> complicated stuff with clocks and mac addresses?  Maybe.  Windows has
> been generating random uuids for about 20 years now.

If random UUIDs are an option, there is a UUID implementation in libc,
though the functions used (uuid_create and uuid_to_string) do have a
different signatures.

A patch to use libc UUID is below.

> 
> > 
> > However, assuming we can't just use random UUIDs, here's an attempt
> > at improving this code:
> > 
> > - Use clock_gettime(2).  With nanosecond resolution we don't need
> >   a 'counter'.
> > 
> > - Reduce the scope of all the static state to uuid_create().
> > 
> > - Shrink the loop.  Just read the clock until it changes, then
> > decide what to do re. seq_num.  This is effectively what the
> > example code in RFC 4122 does.
> > 
> > I'm unsure what the right thing to do is if the system clock
> > predates the UUID epoch (Oct 15 1582).  My code just returns zero.
> > Maybe we should just kill the daemon in that case?  The UUIDv1
> > scheme breaks down if time is that seriously screwed up.
> > 
> > Is there an active ldapd(8) person?  Or at least someone with an
> > ldapd(8) setup who can test this?  
> 
> I'm kind of an active ldapd person, though I don't actually use it
> actively.  I can try this out if need be.
> 

Index: Makefile
===================================================================
RCS file: /cvs/src/usr.sbin/ldapd/Makefile,v
retrieving revision 1.16
diff -u -p -r1.16 Makefile
--- Makefile    11 May 2019 17:46:02 -0000      1.16
+++ Makefile    1 Sep 2020 13:53:44 -0000
@@ -6,7 +6,7 @@ SRCS=           log.c logmsg.c control.c \
                util.c ldapd.c ldape.c conn.c attributes.c namespace.c \
                btree.c filter.c search.c parse.y \
                auth.c modify.c index.c evbuffer_tls.c \
-               validate.c uuid.c schema.c imsgev.c syntax.c matching.c
+               validate.c schema.c imsgev.c syntax.c matching.c
 
 LDADD=         -levent -ltls -lssl -lcrypto -lz -lutil
 DPADD=         ${LIBEVENT} ${LIBTLS} ${LIBSSL} ${LIBCRYPTO} ${LIBZ} ${LIBUTIL}
Index: modify.c
===================================================================
RCS file: /cvs/src/usr.sbin/ldapd/modify.c,v
retrieving revision 1.23
diff -u -p -r1.23 modify.c
--- modify.c    24 Oct 2019 12:39:26 -0000      1.23
+++ modify.c    1 Sep 2020 13:53:44 -0000
@@ -23,10 +23,10 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <uuid.h>
 
 #include "ldapd.h"
 #include "log.h"
-#include "uuid.h"
 
 int
 ldap_delete(struct request *req)
@@ -123,14 +123,15 @@ done:
 int
 ldap_add(struct request *req)
 {
-       char                     uuid_str[64];
-       struct uuid              uuid;
+       char                    *uuid_str = NULL;
+       uuid_t                   uuid;
        char                    *dn, *s;
        struct attr_type        *at;
        struct ber_element      *attrs, *attr, *elm, *set = NULL;
        struct namespace        *ns;
        struct referrals        *refs;
        int                      rc;
+       uint32_t                 status;
 
        ++stats.req_mod;
 
@@ -204,12 +205,19 @@ ldap_add(struct request *req)
        if (ldap_add_attribute(attrs, "createTimestamp", set) == NULL)
                goto fail;
 
-       uuid_create(&uuid);
-       uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
+       uuid_create(&uuid, &status);
+       if (status != uuid_s_ok)
+               goto fail;
+       uuid_to_string(&uuid, &uuid_str, &status);
+       if (status != uuid_s_ok)
+               goto fail;
        if ((set = ober_add_set(NULL)) == NULL)
                goto fail;
-       if (ober_add_string(set, uuid_str) == NULL)
+       if (ober_add_string(set, uuid_str) == NULL) {
+               free(uuid_str);
                goto fail;
+       }
+       free(uuid_str);
        if (ldap_add_attribute(attrs, "entryUUID", set) == NULL)
                goto fail;
 
Index: syntax.c
===================================================================
RCS file: /cvs/src/usr.sbin/ldapd/syntax.c,v
retrieving revision 1.5
diff -u -p -r1.5 syntax.c
--- syntax.c    28 May 2017 15:48:49 -0000      1.5
+++ syntax.c    1 Sep 2020 13:53:44 -0000
@@ -26,7 +26,6 @@
 #include <string.h>
 
 #include "schema.h"
-#include "uuid.h"
 
 #define SYNTAX_DECL(TYPE) \
        static int syntax_is_##TYPE(struct schema *schema, char *value, size_t 
len)
Index: uuid.c
===================================================================
RCS file: uuid.c
diff -N uuid.c
--- uuid.c      26 Apr 2018 12:42:51 -0000      1.6
+++ /dev/null   1 Jan 1970 00:00:00 -0000
@@ -1,257 +0,0 @@
-/*     $OpenBSD: uuid.c,v 1.6 2018/04/26 12:42:51 guenther Exp $ */
-/*
- * Copyright (c) 2002, Stockholms Universitet
- * (Stockholm University, Stockholm Sweden)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * 3. Neither the name of the university nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * NCS/DCE/AFS/GUID generator
- *
- *  for more information about DCE UUID, see
- *  <http://www.opengroup.org/onlinepubs/9629399/apdxa.htm>
- *
- *  Note, the Microsoft GUID is a DCE UUID, but it seems like they
- *  folded in the seq num with the node part. That would explain how
- *  the reserved field have a bit pattern 110 when reserved is a 2 bit
- *  field.
- *
- *  XXX should hash the node address for privacy issues
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <netinet/in.h>
-#include <net/if.h>
-#include <net/if_types.h>
-#include <net/if_dl.h>
-
-#include <fcntl.h>
-#include <ifaddrs.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "uuid.h"
-
-static uint32_t seq_num;
-static struct timeval last_time;
-static int32_t counter;
-static char nodeaddr[6];
-
-enum { UUID_NODE_MULTICAST = 0x80 };
-
-static int
-time_cmp(struct timeval *tv1, struct timeval *tv2)
-{
-    if (tv1->tv_sec > tv2->tv_sec)
-       return -1;
-    if (tv1->tv_sec < tv2->tv_sec)
-       return 1;
-    if (tv1->tv_usec > tv2->tv_usec)
-       return -1;
-    if (tv1->tv_usec < tv2->tv_usec)
-       return 1;
-    return 0;
-}
-
-static void
-get_node_addr(char *addr)
-{
-    struct ifaddrs *ifa, *ifa0;
-    int found_mac = 0;
-
-    if (getifaddrs(&ifa0) != 0)
-       ifa0 = NULL;
-
-    for (ifa = ifa0; ifa != NULL && !found_mac; ifa = ifa->ifa_next) {
-       if (ifa->ifa_addr == NULL)
-           continue;
-
-#if IFF_LOOPBACK
-       if (ifa->ifa_flags & IFF_LOOPBACK)
-           continue;
-#endif
-
-       switch (ifa->ifa_addr->sa_family) {
-#ifdef AF_LINK
-       case AF_LINK: {
-           struct sockaddr_dl *dl = (struct sockaddr_dl *)ifa->ifa_addr;
-
-           switch (dl->sdl_type) {
-           case IFT_ETHER:
-           case IFT_FDDI:
-               if (dl->sdl_alen == 6) {
-                   memcpy(addr, LLADDR(dl), 6);
-                   found_mac = 1;
-               }
-           }
-
-       }
-#endif
-       default:
-           break;
-       }
-    }
-
-    if (ifa0 != NULL)
-       freeifaddrs(ifa0);
-
-    if (!found_mac) {
-       /*
-        * Set the multicast bit to make sure we won't collide with an
-        * allocated (mac) address.
-        */
-       arc4random_buf(addr, 6);
-       addr[0] |= UUID_NODE_MULTICAST;
-    }
-    return;
-}
-
-/*
- *    Creates a new UUID.
- */
-
-void
-uuid_create(afsUUID *uuid)
-{
-    static int uuid_inited = 0;
-    struct timeval tv;
-    int ret, got_time;
-    uint64_t dce_time;
-
-    if (uuid_inited == 0) {
-       gettimeofday(&last_time, NULL);
-       seq_num = arc4random();
-       get_node_addr(nodeaddr);
-       uuid_inited = 1;
-    }
-
-    gettimeofday(&tv, NULL);
-
-    got_time = 0;
-
-    do {
-       ret = time_cmp(&tv, &last_time);
-       if (ret < 0) {
-           /* Time went backward, just inc seq_num and be done.
-            * seq_num is 6 + 8 bit field it the uuid, so let it wrap
-            * around. don't let it be zero.
-            */
-           seq_num = (seq_num + 1) & 0x3fff ;
-           if (seq_num == 0)
-               seq_num++;
-           got_time = 1;
-           counter = 0;
-           last_time = tv;
-       } else if (ret > 0) {
-           /* time went forward, reset counter and be happy */
-           last_time = tv;
-           counter = 0;
-           got_time = 1;
-       } else {
-#define UUID_MAX_HZ (1) /* make this bigger fix you have larger tickrate */
-#define MULTIPLIER_100_NANO_SEC 10
-           if (++counter < UUID_MAX_HZ * MULTIPLIER_100_NANO_SEC)
-               got_time = 1;
-       }
-    } while(!got_time);
-
-    /*
-     * now shift time to dce_time, epoch 00:00:00:00, 15 October 1582
-     * dce time ends year ~3400, so start to worry now
-     */
-
-    dce_time = tv.tv_usec * MULTIPLIER_100_NANO_SEC + counter;
-    dce_time += ((uint64_t)tv.tv_sec) * 10000000;
-    dce_time += (((uint64_t)0x01b21dd2) << 32) + 0x13814000;
-
-    uuid->time_low = dce_time & 0xffffffff;
-    uuid->time_mid = 0xffff & (dce_time >> 32);
-    uuid->time_hi_and_version = 0x0fff & (dce_time >> 48);
-
-    uuid->time_hi_and_version |= (1 << 12);
-
-    uuid->clock_seq_low = seq_num & 0xff;
-    uuid->clock_seq_hi_and_reserved = (seq_num >> 8) & 0x3f;
-    uuid->clock_seq_hi_and_reserved |= 0x80; /* dce variant */
-
-    memcpy(uuid->node, nodeaddr, 6);
-}
-
-/*
- *    Converts a UUID from binary representation to a string representation.
- */
-
-void
-uuid_to_string(const afsUUID *uuid, char *str, size_t strsz)
-{
-    snprintf(str, strsz,
-            "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
-            uuid->time_low,
-            uuid->time_mid,
-            uuid->time_hi_and_version,
-            (unsigned char)uuid->clock_seq_hi_and_reserved,
-            (unsigned char)uuid->clock_seq_low,
-            (unsigned char)uuid->node[0],
-            (unsigned char)uuid->node[1],
-            (unsigned char)uuid->node[2],
-            (unsigned char)uuid->node[3],
-            (unsigned char)uuid->node[4],
-            (unsigned char)uuid->node[5]);
-}
-
-
-#ifdef TEST
-int
-main(int argc, char **argv)
-{
-    char str[1000];
-    afsUUID u1, u2;
-
-    uuid_create(&u1);
-
-    uuid_to_string(&u1, str, sizeof(str));
-
-    printf("u: %s\n", str);
-
-    if (uuid_from_string(str, &u2)) {
-       printf("failed to parse\n");
-       return 0;
-    }
-
-    if (bcmp(&u1, &u2, sizeof(u1)) != 0)
-       printf("u1 != u2\n");
-
-    return 0;
-}
-#endif
Index: uuid.h
===================================================================
RCS file: uuid.h
diff -N uuid.h
--- uuid.h      27 Jun 2010 18:19:36 -0000      1.3
+++ /dev/null   1 Jan 1970 00:00:00 -0000
@@ -1,55 +0,0 @@
-/*     $OpenBSD: uuid.h,v 1.3 2010/06/27 18:19:36 martinh Exp $ */
-/*
- * Copyright (c) 2002, Stockholms Universitet
- * (Stockholm University, Stockholm Sweden)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * 3. Neither the name of the university nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-/* $arla: afs_uuid.h,v 1.3 2002/05/30 00:48:12 mattiasa Exp $ */
-
-#ifndef __ARLA_UUID_H__
-#define __ARLA_UUID_H__ 1
-
-struct uuid {
-       u_long time_low;
-       u_short time_mid;
-       u_short time_hi_and_version;
-       char clock_seq_hi_and_reserved;
-       char clock_seq_low;
-       char node[6];
-};
-
-typedef struct uuid afsUUID;
-
-void   uuid_create(afsUUID *);
-void   uuid_to_string(const afsUUID *, char *, size_t);
-
-#endif /* __ARLA_UUID_H__ */
-

Reply via email to