1*f4147939Sguenther /* $OpenBSD: uuid.c,v 1.6 2018/04/26 12:42:51 guenther Exp $ */
25d465952Smartinh /*
35d465952Smartinh * Copyright (c) 2002, Stockholms Universitet
45d465952Smartinh * (Stockholm University, Stockholm Sweden)
55d465952Smartinh * All rights reserved.
65d465952Smartinh *
75d465952Smartinh * Redistribution and use in source and binary forms, with or without
85d465952Smartinh * modification, are permitted provided that the following conditions
95d465952Smartinh * are met:
105d465952Smartinh *
115d465952Smartinh * 1. Redistributions of source code must retain the above copyright
125d465952Smartinh * notice, this list of conditions and the following disclaimer.
135d465952Smartinh *
145d465952Smartinh * 2. Redistributions in binary form must reproduce the above copyright
155d465952Smartinh * notice, this list of conditions and the following disclaimer in the
165d465952Smartinh * documentation and/or other materials provided with the distribution.
175d465952Smartinh *
185d465952Smartinh * 3. Neither the name of the university nor the names of its contributors
195d465952Smartinh * may be used to endorse or promote products derived from this software
205d465952Smartinh * without specific prior written permission.
215d465952Smartinh *
225d465952Smartinh * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
235d465952Smartinh * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
245d465952Smartinh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
255d465952Smartinh * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
265d465952Smartinh * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
275d465952Smartinh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
285d465952Smartinh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
295d465952Smartinh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
305d465952Smartinh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
315d465952Smartinh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
325d465952Smartinh * POSSIBILITY OF SUCH DAMAGE.
335d465952Smartinh */
345d465952Smartinh
355d465952Smartinh /*
365d465952Smartinh * NCS/DCE/AFS/GUID generator
375d465952Smartinh *
385d465952Smartinh * for more information about DCE UUID, see
395d465952Smartinh * <http://www.opengroup.org/onlinepubs/9629399/apdxa.htm>
405d465952Smartinh *
415d465952Smartinh * Note, the Microsoft GUID is a DCE UUID, but it seems like they
425d465952Smartinh * folded in the seq num with the node part. That would explain how
435d465952Smartinh * the reserved field have a bit pattern 110 when reserved is a 2 bit
445d465952Smartinh * field.
455d465952Smartinh *
465d465952Smartinh * XXX should hash the node address for privacy issues
475d465952Smartinh */
485d465952Smartinh
495d465952Smartinh #include <sys/types.h>
505d465952Smartinh #include <sys/socket.h>
51c4b5d4d4Sguenther #include <sys/time.h>
525d465952Smartinh #include <netinet/in.h>
535d465952Smartinh #include <net/if.h>
545d465952Smartinh #include <net/if_types.h>
555d465952Smartinh #include <net/if_dl.h>
565d465952Smartinh
575d465952Smartinh #include <fcntl.h>
585d465952Smartinh #include <ifaddrs.h>
595d465952Smartinh #include <stdio.h>
605d465952Smartinh #include <stdlib.h>
615d465952Smartinh #include <string.h>
625d465952Smartinh #include <unistd.h>
635d465952Smartinh
645d465952Smartinh #include "uuid.h"
655d465952Smartinh
665d465952Smartinh static uint32_t seq_num;
675d465952Smartinh static struct timeval last_time;
685d465952Smartinh static int32_t counter;
695d465952Smartinh static char nodeaddr[6];
705d465952Smartinh
715d465952Smartinh enum { UUID_NODE_MULTICAST = 0x80 };
725d465952Smartinh
735d465952Smartinh static int
time_cmp(struct timeval * tv1,struct timeval * tv2)745d465952Smartinh time_cmp(struct timeval *tv1, struct timeval *tv2)
755d465952Smartinh {
765d465952Smartinh if (tv1->tv_sec > tv2->tv_sec)
775d465952Smartinh return -1;
785d465952Smartinh if (tv1->tv_sec < tv2->tv_sec)
795d465952Smartinh return 1;
805d465952Smartinh if (tv1->tv_usec > tv2->tv_usec)
815d465952Smartinh return -1;
825d465952Smartinh if (tv1->tv_usec < tv2->tv_usec)
835d465952Smartinh return 1;
845d465952Smartinh return 0;
855d465952Smartinh }
865d465952Smartinh
875d465952Smartinh static void
get_node_addr(char * addr)885d465952Smartinh get_node_addr(char *addr)
895d465952Smartinh {
905d465952Smartinh struct ifaddrs *ifa, *ifa0;
915d465952Smartinh int found_mac = 0;
925d465952Smartinh
935d465952Smartinh if (getifaddrs(&ifa0) != 0)
945d465952Smartinh ifa0 = NULL;
955d465952Smartinh
965d465952Smartinh for (ifa = ifa0; ifa != NULL && !found_mac; ifa = ifa->ifa_next) {
975d465952Smartinh if (ifa->ifa_addr == NULL)
985d465952Smartinh continue;
995d465952Smartinh
1005d465952Smartinh #if IFF_LOOPBACK
1015d465952Smartinh if (ifa->ifa_flags & IFF_LOOPBACK)
1025d465952Smartinh continue;
1035d465952Smartinh #endif
1045d465952Smartinh
1055d465952Smartinh switch (ifa->ifa_addr->sa_family) {
1065d465952Smartinh #ifdef AF_LINK
1075d465952Smartinh case AF_LINK: {
1085d465952Smartinh struct sockaddr_dl *dl = (struct sockaddr_dl *)ifa->ifa_addr;
1095d465952Smartinh
1105d465952Smartinh switch (dl->sdl_type) {
1115d465952Smartinh case IFT_ETHER:
1125d465952Smartinh case IFT_FDDI:
1135d465952Smartinh if (dl->sdl_alen == 6) {
1145d465952Smartinh memcpy(addr, LLADDR(dl), 6);
1155d465952Smartinh found_mac = 1;
1165d465952Smartinh }
1175d465952Smartinh }
1185d465952Smartinh
1195d465952Smartinh }
1205d465952Smartinh #endif
1215d465952Smartinh default:
1225d465952Smartinh break;
1235d465952Smartinh }
1245d465952Smartinh }
1255d465952Smartinh
1265d465952Smartinh if (ifa0 != NULL)
1275d465952Smartinh freeifaddrs(ifa0);
1285d465952Smartinh
1295d465952Smartinh if (!found_mac) {
1305d465952Smartinh /*
1315d465952Smartinh * Set the multicast bit to make sure we won't collide with an
1325d465952Smartinh * allocated (mac) address.
1335d465952Smartinh */
1345d465952Smartinh arc4random_buf(addr, 6);
1355d465952Smartinh addr[0] |= UUID_NODE_MULTICAST;
1365d465952Smartinh }
1375d465952Smartinh return;
1385d465952Smartinh }
1395d465952Smartinh
1405d465952Smartinh /*
1415d465952Smartinh * Creates a new UUID.
1425d465952Smartinh */
1435d465952Smartinh
1441291887fSmartinh void
uuid_create(afsUUID * uuid)1455d465952Smartinh uuid_create(afsUUID *uuid)
1465d465952Smartinh {
1475d465952Smartinh static int uuid_inited = 0;
1485d465952Smartinh struct timeval tv;
1495d465952Smartinh int ret, got_time;
1505d465952Smartinh uint64_t dce_time;
1515d465952Smartinh
1525d465952Smartinh if (uuid_inited == 0) {
1535d465952Smartinh gettimeofday(&last_time, NULL);
1545d465952Smartinh seq_num = arc4random();
1555d465952Smartinh get_node_addr(nodeaddr);
1565d465952Smartinh uuid_inited = 1;
1575d465952Smartinh }
1585d465952Smartinh
1595d465952Smartinh gettimeofday(&tv, NULL);
1605d465952Smartinh
1615d465952Smartinh got_time = 0;
1625d465952Smartinh
1635d465952Smartinh do {
1645d465952Smartinh ret = time_cmp(&tv, &last_time);
1655d465952Smartinh if (ret < 0) {
1665d465952Smartinh /* Time went backward, just inc seq_num and be done.
1675d465952Smartinh * seq_num is 6 + 8 bit field it the uuid, so let it wrap
1685d465952Smartinh * around. don't let it be zero.
1695d465952Smartinh */
1705d465952Smartinh seq_num = (seq_num + 1) & 0x3fff ;
1715d465952Smartinh if (seq_num == 0)
1725d465952Smartinh seq_num++;
1735d465952Smartinh got_time = 1;
1745d465952Smartinh counter = 0;
1755d465952Smartinh last_time = tv;
1765d465952Smartinh } else if (ret > 0) {
1775d465952Smartinh /* time went forward, reset counter and be happy */
1785d465952Smartinh last_time = tv;
1795d465952Smartinh counter = 0;
1805d465952Smartinh got_time = 1;
1815d465952Smartinh } else {
1825d465952Smartinh #define UUID_MAX_HZ (1) /* make this bigger fix you have larger tickrate */
1835d465952Smartinh #define MULTIPLIER_100_NANO_SEC 10
1845d465952Smartinh if (++counter < UUID_MAX_HZ * MULTIPLIER_100_NANO_SEC)
1855d465952Smartinh got_time = 1;
1865d465952Smartinh }
1875d465952Smartinh } while(!got_time);
1885d465952Smartinh
1895d465952Smartinh /*
1905d465952Smartinh * now shift time to dce_time, epoch 00:00:00:00, 15 October 1582
1915d465952Smartinh * dce time ends year ~3400, so start to worry now
1925d465952Smartinh */
1935d465952Smartinh
1945d465952Smartinh dce_time = tv.tv_usec * MULTIPLIER_100_NANO_SEC + counter;
1955d465952Smartinh dce_time += ((uint64_t)tv.tv_sec) * 10000000;
1965d465952Smartinh dce_time += (((uint64_t)0x01b21dd2) << 32) + 0x13814000;
1975d465952Smartinh
1985d465952Smartinh uuid->time_low = dce_time & 0xffffffff;
1995d465952Smartinh uuid->time_mid = 0xffff & (dce_time >> 32);
2005d465952Smartinh uuid->time_hi_and_version = 0x0fff & (dce_time >> 48);
2015d465952Smartinh
2025d465952Smartinh uuid->time_hi_and_version |= (1 << 12);
2035d465952Smartinh
2045d465952Smartinh uuid->clock_seq_low = seq_num & 0xff;
2055d465952Smartinh uuid->clock_seq_hi_and_reserved = (seq_num >> 8) & 0x3f;
2065d465952Smartinh uuid->clock_seq_hi_and_reserved |= 0x80; /* dce variant */
2075d465952Smartinh
2085d465952Smartinh memcpy(uuid->node, nodeaddr, 6);
2095d465952Smartinh }
2105d465952Smartinh
2115d465952Smartinh /*
2125d465952Smartinh * Converts a UUID from binary representation to a string representation.
2135d465952Smartinh */
2145d465952Smartinh
21537ddeb55Smartinh void
uuid_to_string(const afsUUID * uuid,char * str,size_t strsz)2165d465952Smartinh uuid_to_string(const afsUUID *uuid, char *str, size_t strsz)
2175d465952Smartinh {
2185d465952Smartinh snprintf(str, strsz,
2195d465952Smartinh "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2205d465952Smartinh uuid->time_low,
2215d465952Smartinh uuid->time_mid,
2225d465952Smartinh uuid->time_hi_and_version,
2235d465952Smartinh (unsigned char)uuid->clock_seq_hi_and_reserved,
2245d465952Smartinh (unsigned char)uuid->clock_seq_low,
2255d465952Smartinh (unsigned char)uuid->node[0],
2265d465952Smartinh (unsigned char)uuid->node[1],
2275d465952Smartinh (unsigned char)uuid->node[2],
2285d465952Smartinh (unsigned char)uuid->node[3],
2295d465952Smartinh (unsigned char)uuid->node[4],
2305d465952Smartinh (unsigned char)uuid->node[5]);
2315d465952Smartinh }
2325d465952Smartinh
2335d465952Smartinh
2345d465952Smartinh #ifdef TEST
2355d465952Smartinh int
main(int argc,char ** argv)2365d465952Smartinh main(int argc, char **argv)
2375d465952Smartinh {
2385d465952Smartinh char str[1000];
2395d465952Smartinh afsUUID u1, u2;
2405d465952Smartinh
2415d465952Smartinh uuid_create(&u1);
2425d465952Smartinh
2435d465952Smartinh uuid_to_string(&u1, str, sizeof(str));
2445d465952Smartinh
2455d465952Smartinh printf("u: %s\n", str);
2465d465952Smartinh
2475d465952Smartinh if (uuid_from_string(str, &u2)) {
2485d465952Smartinh printf("failed to parse\n");
2495d465952Smartinh return 0;
2505d465952Smartinh }
2515d465952Smartinh
25237ddeb55Smartinh if (bcmp(&u1, &u2, sizeof(u1)) != 0)
2535d465952Smartinh printf("u1 != u2\n");
2545d465952Smartinh
2555d465952Smartinh return 0;
2565d465952Smartinh }
2575d465952Smartinh #endif
258