1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 
7 #include "fd-util.h"
8 #include "hexdecoct.h"
9 #include "id128-util.h"
10 #include "io-util.h"
11 #include "stdio-util.h"
12 #include "string-util.h"
13 #include "sync-util.h"
14 
id128_is_valid(const char * s)15 bool id128_is_valid(const char *s) {
16         size_t i, l;
17 
18         assert(s);
19 
20         l = strlen(s);
21         if (l == 32) {
22 
23                 /* Plain formatted 128bit hex string */
24 
25                 for (i = 0; i < l; i++) {
26                         char c = s[i];
27 
28                         if (!(c >= '0' && c <= '9') &&
29                             !(c >= 'a' && c <= 'z') &&
30                             !(c >= 'A' && c <= 'Z'))
31                                 return false;
32                 }
33 
34         } else if (l == 36) {
35 
36                 /* Formatted UUID */
37 
38                 for (i = 0; i < l; i++) {
39                         char c = s[i];
40 
41                         if (IN_SET(i, 8, 13, 18, 23)) {
42                                 if (c != '-')
43                                         return false;
44                         } else {
45                                 if (!(c >= '0' && c <= '9') &&
46                                     !(c >= 'a' && c <= 'z') &&
47                                     !(c >= 'A' && c <= 'Z'))
48                                         return false;
49                         }
50                 }
51 
52         } else
53                 return false;
54 
55         return true;
56 }
57 
id128_read_fd(int fd,Id128Format f,sd_id128_t * ret)58 int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
59         char buffer[36 + 2];
60         ssize_t l;
61 
62         assert(fd >= 0);
63         assert(f < _ID128_FORMAT_MAX);
64 
65         /* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both
66          * optionally followed by a newline and nothing else. ID files should really be newline terminated, but if they
67          * aren't that's OK too, following the rule of "Be conservative in what you send, be liberal in what you
68          * accept". */
69 
70         l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 32/33 or 36/37 chars */
71         if (l < 0)
72                 return (int) l;
73         if (l == 0) /* empty? */
74                 return -ENOMEDIUM;
75 
76         switch (l) {
77 
78         case 13:
79         case 14:
80                 /* Treat an "uninitialized" id file like an empty one */
81                 return f == ID128_PLAIN_OR_UNINIT && strneq(buffer, "uninitialized\n", l) ? -ENOMEDIUM : -EINVAL;
82 
83         case 33: /* plain UUID with trailing newline */
84                 if (buffer[32] != '\n')
85                         return -EINVAL;
86 
87                 _fallthrough_;
88         case 32: /* plain UUID without trailing newline */
89                 if (f == ID128_UUID)
90                         return -EINVAL;
91 
92                 buffer[32] = 0;
93                 break;
94 
95         case 37: /* RFC UUID with trailing newline */
96                 if (buffer[36] != '\n')
97                         return -EINVAL;
98 
99                 _fallthrough_;
100         case 36: /* RFC UUID without trailing newline */
101                 if (IN_SET(f, ID128_PLAIN, ID128_PLAIN_OR_UNINIT))
102                         return -EINVAL;
103 
104                 buffer[36] = 0;
105                 break;
106 
107         default:
108                 return -EINVAL;
109         }
110 
111         return sd_id128_from_string(buffer, ret);
112 }
113 
id128_read(const char * p,Id128Format f,sd_id128_t * ret)114 int id128_read(const char *p, Id128Format f, sd_id128_t *ret) {
115         _cleanup_close_ int fd = -1;
116 
117         fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY);
118         if (fd < 0)
119                 return -errno;
120 
121         return id128_read_fd(fd, f, ret);
122 }
123 
id128_write_fd(int fd,Id128Format f,sd_id128_t id,bool do_sync)124 int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
125         char buffer[36 + 2];
126         size_t sz;
127         int r;
128 
129         assert(fd >= 0);
130         assert(f < _ID128_FORMAT_MAX);
131 
132         if (f != ID128_UUID) {
133                 assert_se(sd_id128_to_string(id, buffer));
134                 buffer[SD_ID128_STRING_MAX - 1] = '\n';
135                 sz = SD_ID128_STRING_MAX;
136         } else {
137                 assert_se(sd_id128_to_uuid_string(id, buffer));
138                 buffer[SD_ID128_UUID_STRING_MAX - 1] = '\n';
139                 sz = SD_ID128_UUID_STRING_MAX;
140         }
141 
142         r = loop_write(fd, buffer, sz, false);
143         if (r < 0)
144                 return r;
145 
146         if (do_sync) {
147                 r = fsync_full(fd);
148                 if (r < 0)
149                         return r;
150         }
151 
152         return 0;
153 }
154 
id128_write(const char * p,Id128Format f,sd_id128_t id,bool do_sync)155 int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) {
156         _cleanup_close_ int fd = -1;
157 
158         fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, 0444);
159         if (fd < 0)
160                 return -errno;
161 
162         return id128_write_fd(fd, f, id, do_sync);
163 }
164 
id128_hash_func(const sd_id128_t * p,struct siphash * state)165 void id128_hash_func(const sd_id128_t *p, struct siphash *state) {
166         siphash24_compress(p, sizeof(sd_id128_t), state);
167 }
168 
id128_compare_func(const sd_id128_t * a,const sd_id128_t * b)169 int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) {
170         return memcmp(a, b, 16);
171 }
172 
id128_make_v4_uuid(sd_id128_t id)173 sd_id128_t id128_make_v4_uuid(sd_id128_t id) {
174         /* Stolen from generate_random_uuid() of drivers/char/random.c
175          * in the kernel sources */
176 
177         /* Set UUID version to 4 --- truly random generation */
178         id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
179 
180         /* Set the UUID variant to DCE */
181         id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
182 
183         return id;
184 }
185 
186 DEFINE_HASH_OPS(id128_hash_ops, sd_id128_t, id128_hash_func, id128_compare_func);
187 
id128_get_product(sd_id128_t * ret)188 int id128_get_product(sd_id128_t *ret) {
189         sd_id128_t uuid;
190         int r;
191 
192         assert(ret);
193 
194         /* Reads the systems product UUID from DMI or devicetree (where it is located on POWER). This is
195          * particularly relevant in VM environments, where VM managers typically place a VM uuid there. */
196 
197         r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &uuid);
198         if (r == -ENOENT)
199                 r = id128_read("/proc/device-tree/vm,uuid", ID128_UUID, &uuid);
200         if (r < 0)
201                 return r;
202 
203         if (sd_id128_is_null(uuid) || sd_id128_is_allf(uuid))
204                 return -EADDRNOTAVAIL; /* Recognizable error */
205 
206         *ret = uuid;
207         return 0;
208 }
209 
id128_equal_string(const char * s,sd_id128_t id)210 int id128_equal_string(const char *s, sd_id128_t id) {
211         sd_id128_t parsed;
212         int r;
213 
214         if (!s)
215                 return false;
216 
217         /* Checks if the specified string matches a valid string representation of the specified 128 bit ID/uuid */
218 
219         r = sd_id128_from_string(s, &parsed);
220         if (r < 0)
221                 return r;
222 
223         return sd_id128_equal(parsed, id);
224 }
225