sd-id128.c revision ec202eae8e84a4c99f054f771cb832046cb8769f
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering/***
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering This file is part of systemd.
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering Copyright 2011 Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering systemd is free software; you can redistribute it and/or modify it
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering under the terms of the GNU Lesser General Public License as published by
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering (at your option) any later version.
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering systemd is distributed in the hope that it will be useful, but
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering Lesser General Public License for more details.
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering You should have received a copy of the GNU Lesser General Public License
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering***/
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
718db96199eb307751264e4163555662c9a389faLennart Poettering#include <errno.h>
718db96199eb307751264e4163555662c9a389faLennart Poettering#include <fcntl.h>
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include <unistd.h>
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include "util.h"
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include "macro.h"
718db96199eb307751264e4163555662c9a389faLennart Poettering#include "sd-id128.h"
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering
4e2f8d27781731021aa6b96c0ee18a8966eefe1cLennart Poettering_public_ char *sd_id128_to_string(sd_id128_t id, char s[33]) {
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering unsigned n;
a911bb9ab27ac0eb3bbf4e8b4109e5da9b88eee3Lennart Poettering
a911bb9ab27ac0eb3bbf4e8b4109e5da9b88eee3Lennart Poettering assert_return(s, NULL);
4e2f8d27781731021aa6b96c0ee18a8966eefe1cLennart Poettering
a911bb9ab27ac0eb3bbf4e8b4109e5da9b88eee3Lennart Poettering for (n = 0; n < 16; n++) {
a911bb9ab27ac0eb3bbf4e8b4109e5da9b88eee3Lennart Poettering s[n*2] = hexchar(id.bytes[n] >> 4);
a911bb9ab27ac0eb3bbf4e8b4109e5da9b88eee3Lennart Poettering s[n*2+1] = hexchar(id.bytes[n] & 0xF);
a911bb9ab27ac0eb3bbf4e8b4109e5da9b88eee3Lennart Poettering }
a911bb9ab27ac0eb3bbf4e8b4109e5da9b88eee3Lennart Poettering
4e2f8d27781731021aa6b96c0ee18a8966eefe1cLennart Poettering s[32] = 0;
4e2f8d27781731021aa6b96c0ee18a8966eefe1cLennart Poettering
4e2f8d27781731021aa6b96c0ee18a8966eefe1cLennart Poettering return s;
4e2f8d27781731021aa6b96c0ee18a8966eefe1cLennart Poettering}
4e2f8d27781731021aa6b96c0ee18a8966eefe1cLennart Poettering
4e2f8d27781731021aa6b96c0ee18a8966eefe1cLennart Poettering_public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
4e2f8d27781731021aa6b96c0ee18a8966eefe1cLennart Poettering unsigned n, i;
4e2f8d27781731021aa6b96c0ee18a8966eefe1cLennart Poettering sd_id128_t t;
a911bb9ab27ac0eb3bbf4e8b4109e5da9b88eee3Lennart Poettering bool is_guid = false;
a911bb9ab27ac0eb3bbf4e8b4109e5da9b88eee3Lennart Poettering
718db96199eb307751264e4163555662c9a389faLennart Poettering assert_return(s, -EINVAL);
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering assert_return(ret, -EINVAL);
718db96199eb307751264e4163555662c9a389faLennart Poettering
718db96199eb307751264e4163555662c9a389faLennart Poettering for (n = 0, i = 0; n < 16;) {
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering int a, b;
556089dc57b10a12a03edd3d3e90ca17398ad206Lennart Poettering
718db96199eb307751264e4163555662c9a389faLennart Poettering if (s[i] == '-') {
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering /* Is this a GUID? Then be nice, and skip over
a911bb9ab27ac0eb3bbf4e8b4109e5da9b88eee3Lennart Poettering * the dashes */
718db96199eb307751264e4163555662c9a389faLennart Poettering
718db96199eb307751264e4163555662c9a389faLennart Poettering if (i == 8)
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering is_guid = true;
9f2e86af0600e99cff00d1c92f9bb8d38f29896aLennart Poettering else if (i == 13 || i == 18 || i == 23) {
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering if (!is_guid)
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering return -EINVAL;
718db96199eb307751264e4163555662c9a389faLennart Poettering } else
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering return -EINVAL;
718db96199eb307751264e4163555662c9a389faLennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering i++;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering continue;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering }
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
718db96199eb307751264e4163555662c9a389faLennart Poettering a = unhexchar(s[i++]);
718db96199eb307751264e4163555662c9a389faLennart Poettering if (a < 0)
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering return -EINVAL;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
294a90cc4af5139e936975a38baaa62771af96baDave Reisner b = unhexchar(s[i++]);
718db96199eb307751264e4163555662c9a389faLennart Poettering if (b < 0)
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering return -EINVAL;
718db96199eb307751264e4163555662c9a389faLennart Poettering
718db96199eb307751264e4163555662c9a389faLennart Poettering t.bytes[n++] = (a << 4) | b;
718db96199eb307751264e4163555662c9a389faLennart Poettering }
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
718db96199eb307751264e4163555662c9a389faLennart Poettering if (i != (is_guid ? 36 : 32))
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering return -EINVAL;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering if (s[i] != 0)
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering return -EINVAL;
adb3a45d9a1cebdec30406cc2c04503fc5e735beLennart Poettering
a911bb9ab27ac0eb3bbf4e8b4109e5da9b88eee3Lennart Poettering *ret = t;
adb3a45d9a1cebdec30406cc2c04503fc5e735beLennart Poettering return 0;
adb3a45d9a1cebdec30406cc2c04503fc5e735beLennart Poettering}
adb3a45d9a1cebdec30406cc2c04503fc5e735beLennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poetteringstatic sd_id128_t make_v4_uuid(sd_id128_t id) {
adb3a45d9a1cebdec30406cc2c04503fc5e735beLennart Poettering /* Stolen from generate_random_uuid() of drivers/char/random.c
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering * in the kernel sources */
718db96199eb307751264e4163555662c9a389faLennart Poettering
718db96199eb307751264e4163555662c9a389faLennart Poettering /* Set UUID version to 4 --- truly random generation */
718db96199eb307751264e4163555662c9a389faLennart Poettering id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
718db96199eb307751264e4163555662c9a389faLennart Poettering
718db96199eb307751264e4163555662c9a389faLennart Poettering /* Set the UUID variant to DCE */
718db96199eb307751264e4163555662c9a389faLennart Poettering id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
adb3a45d9a1cebdec30406cc2c04503fc5e735beLennart Poettering return id;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering}
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering_public_ int sd_id128_get_machine(sd_id128_t *ret) {
cc23f9f17434aad3941dff3c20bce485b39ce47cLennart Poettering static thread_local sd_id128_t saved_machine_id;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering static thread_local bool saved_machine_id_valid = false;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering _cleanup_close_ int fd = -1;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering char buf[33];
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering ssize_t k;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering unsigned j;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering sd_id128_t t;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering assert_return(ret, -EINVAL);
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering if (saved_machine_id_valid) {
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering *ret = saved_machine_id;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering return 0;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering }
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering if (fd < 0)
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering return -errno;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering k = loop_read(fd, buf, 33, false);
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering if (k < 0)
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering return (int) k;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering if (k != 33)
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering return -EIO;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering if (buf[32] !='\n')
cc23f9f17434aad3941dff3c20bce485b39ce47cLennart Poettering return -EIO;
cc23f9f17434aad3941dff3c20bce485b39ce47cLennart Poettering
cc23f9f17434aad3941dff3c20bce485b39ce47cLennart Poettering for (j = 0; j < 16; j++) {
718db96199eb307751264e4163555662c9a389faLennart Poettering int a, b;
718db96199eb307751264e4163555662c9a389faLennart Poettering
718db96199eb307751264e4163555662c9a389faLennart Poettering a = unhexchar(buf[j*2]);
718db96199eb307751264e4163555662c9a389faLennart Poettering b = unhexchar(buf[j*2+1]);
718db96199eb307751264e4163555662c9a389faLennart Poettering
718db96199eb307751264e4163555662c9a389faLennart Poettering if (a < 0 || b < 0)
718db96199eb307751264e4163555662c9a389faLennart Poettering return -EIO;
718db96199eb307751264e4163555662c9a389faLennart Poettering
718db96199eb307751264e4163555662c9a389faLennart Poettering t.bytes[j] = a << 4 | b;
cc23f9f17434aad3941dff3c20bce485b39ce47cLennart Poettering }
cc23f9f17434aad3941dff3c20bce485b39ce47cLennart Poettering
cc23f9f17434aad3941dff3c20bce485b39ce47cLennart Poettering saved_machine_id = t;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering saved_machine_id_valid = true;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering *ret = t;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering return 0;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering}
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering_public_ int sd_id128_get_boot(sd_id128_t *ret) {
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering static thread_local sd_id128_t saved_boot_id;
718db96199eb307751264e4163555662c9a389faLennart Poettering static thread_local bool saved_boot_id_valid = false;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering _cleanup_close_ int fd = -1;
718db96199eb307751264e4163555662c9a389faLennart Poettering char buf[36];
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering ssize_t k;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering unsigned j;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering sd_id128_t t;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering char *p;
718db96199eb307751264e4163555662c9a389faLennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering assert_return(ret, -EINVAL);
718db96199eb307751264e4163555662c9a389faLennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering if (saved_boot_id_valid) {
718db96199eb307751264e4163555662c9a389faLennart Poettering *ret = saved_boot_id;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering return 0;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering }
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering if (fd < 0)
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering return -errno;
718db96199eb307751264e4163555662c9a389faLennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering k = loop_read(fd, buf, 36, false);
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering if (k < 0)
a6c0353b9268d5b780fb7ff05a10cb5031446e5dLennart Poettering return (int) k;
718db96199eb307751264e4163555662c9a389faLennart Poettering
a6c0353b9268d5b780fb7ff05a10cb5031446e5dLennart Poettering if (k != 36)
a6c0353b9268d5b780fb7ff05a10cb5031446e5dLennart Poettering return -EIO;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering for (j = 0, p = buf; j < 16; j++) {
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering int a, b;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering if (p >= buf + k)
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering return -EIO;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering if (*p == '-')
bc432dc7eb62c5671f2b741a86a66393adb350dcLennart Poettering p++;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
bc432dc7eb62c5671f2b741a86a66393adb350dcLennart Poettering a = unhexchar(p[0]);
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering b = unhexchar(p[1]);
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering if (a < 0 || b < 0)
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering return -EIO;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering t.bytes[j] = a << 4 | b;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering p += 2;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering }
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering saved_boot_id = t;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering saved_boot_id_valid = true;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering *ret = t;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering return 0;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering}
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering_public_ int sd_id128_randomize(sd_id128_t *ret) {
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering _cleanup_close_ int fd = -1;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering sd_id128_t t;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering ssize_t k;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering assert_return(ret, -EINVAL);
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering if (fd < 0)
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering return -errno;
2d4a39e759c4ab846ad8a546abeddd40bc8d736eLennart Poettering
k = loop_read(fd, &t, 16, false);
if (k < 0)
return (int) k;
if (k != 16)
return -EIO;
/* Turn this into a valid v4 UUID, to be nice. Note that we
* only guarantee this for newly generated UUIDs, not for
* pre-existing ones.*/
*ret = make_v4_uuid(t);
return 0;
}