/src/cryptsetup/lib/luks2/luks2_segment.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | // SPDX-License-Identifier: GPL-2.0-or-later  | 
2  |  | /*  | 
3  |  |  * LUKS - Linux Unified Key Setup v2, internal segment handling  | 
4  |  |  *  | 
5  |  |  * Copyright (C) 2018-2025 Red Hat, Inc. All rights reserved.  | 
6  |  |  * Copyright (C) 2018-2025 Ondrej Kozina  | 
7  |  |  */  | 
8  |  |  | 
9  |  | #include "luks2_internal.h"  | 
10  |  |  | 
11  |  | /* use only on already validated 'segments' object */  | 
12  |  | uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned blockwise)  | 
13  | 6.66k  | { | 
14  | 6.66k  |   uint64_t tmp, min = blockwise ? UINT64_MAX >> SECTOR_SHIFT : UINT64_MAX;  | 
15  |  |  | 
16  | 6.66k  |   if (!jobj_segments)  | 
17  | 0  |     return 0;  | 
18  |  |  | 
19  | 6.76k  |   json_object_object_foreach(jobj_segments, key, val) { | 
20  | 6.76k  |     UNUSED(key);  | 
21  |  |  | 
22  | 6.76k  |     if (json_segment_is_backup(val))  | 
23  | 61  |       continue;  | 
24  |  |  | 
25  | 6.70k  |     tmp = json_segment_get_offset(val, blockwise);  | 
26  |  |  | 
27  | 6.70k  |     if (!tmp)  | 
28  | 2.93k  |       return tmp;  | 
29  |  |  | 
30  | 3.77k  |     if (tmp < min)  | 
31  | 3.75k  |       min = tmp;  | 
32  | 3.77k  |   }  | 
33  |  |  | 
34  | 3.73k  |   return min;  | 
35  | 6.66k  | }  | 
36  |  |  | 
37  |  | uint64_t json_segment_get_offset(json_object *jobj_segment, unsigned blockwise)  | 
38  | 13.6k  | { | 
39  | 13.6k  |   json_object *jobj;  | 
40  |  |  | 
41  | 13.6k  |   if (!jobj_segment ||  | 
42  | 13.6k  |       !json_object_object_get_ex(jobj_segment, "offset", &jobj))  | 
43  | 0  |     return 0;  | 
44  |  |  | 
45  | 13.6k  |   return blockwise ? crypt_jobj_get_uint64(jobj) >> SECTOR_SHIFT : crypt_jobj_get_uint64(jobj);  | 
46  | 13.6k  | }  | 
47  |  |  | 
48  |  | const char *json_segment_type(json_object *jobj_segment)  | 
49  | 12  | { | 
50  | 12  |   json_object *jobj;  | 
51  |  |  | 
52  | 12  |   if (!jobj_segment ||  | 
53  | 12  |       !json_object_object_get_ex(jobj_segment, "type", &jobj))  | 
54  | 0  |     return NULL;  | 
55  |  |  | 
56  | 12  |   return json_object_get_string(jobj);  | 
57  | 12  | }  | 
58  |  |  | 
59  |  | uint64_t json_segment_get_iv_offset(json_object *jobj_segment)  | 
60  | 0  | { | 
61  | 0  |   json_object *jobj;  | 
62  |  | 
  | 
63  | 0  |   if (!jobj_segment ||  | 
64  | 0  |       !json_object_object_get_ex(jobj_segment, "iv_tweak", &jobj))  | 
65  | 0  |     return 0;  | 
66  |  |  | 
67  | 0  |   return crypt_jobj_get_uint64(jobj);  | 
68  | 0  | }  | 
69  |  |  | 
70  |  | uint64_t json_segment_get_size(json_object *jobj_segment, unsigned blockwise)  | 
71  | 6.89k  | { | 
72  | 6.89k  |   json_object *jobj;  | 
73  |  |  | 
74  | 6.89k  |   if (!jobj_segment ||  | 
75  | 6.89k  |       !json_object_object_get_ex(jobj_segment, "size", &jobj))  | 
76  | 0  |     return 0;  | 
77  |  |  | 
78  | 6.89k  |   return blockwise ? crypt_jobj_get_uint64(jobj) >> SECTOR_SHIFT : crypt_jobj_get_uint64(jobj);  | 
79  | 6.89k  | }  | 
80  |  |  | 
81  |  | static uint64_t json_segment_get_opal_size(json_object *jobj_segment, unsigned blockwise)  | 
82  | 0  | { | 
83  | 0  |   json_object *jobj;  | 
84  |  | 
  | 
85  | 0  |   if (!jobj_segment ||  | 
86  | 0  |       !json_object_object_get_ex(jobj_segment, "opal_segment_size", &jobj))  | 
87  | 0  |     return 0;  | 
88  |  |  | 
89  | 0  |   return blockwise ? crypt_jobj_get_uint64(jobj) >> SECTOR_SHIFT : crypt_jobj_get_uint64(jobj);  | 
90  | 0  | }  | 
91  |  |  | 
92  |  | static bool json_segment_set_size(json_object *jobj_segment, const uint64_t *size_bytes)  | 
93  | 0  | { | 
94  | 0  |   json_object *jobj;  | 
95  |  | 
  | 
96  | 0  |   if (!jobj_segment)  | 
97  | 0  |     return false;  | 
98  |  |  | 
99  | 0  |   jobj = size_bytes ? crypt_jobj_new_uint64(*size_bytes) : json_object_new_string("dynamic"); | 
100  | 0  |   if (!jobj)  | 
101  | 0  |     return false;  | 
102  |  |  | 
103  | 0  |   json_object_object_add(jobj_segment, "size", jobj);  | 
104  |  | 
  | 
105  | 0  |   return true;  | 
106  | 0  | }  | 
107  |  |  | 
108  |  | const char *json_segment_get_cipher(json_object *jobj_segment)  | 
109  | 0  | { | 
110  | 0  |   json_object *jobj;  | 
111  |  |  | 
112  |  |   /* FIXME: Pseudo "null" cipher should be handled elsewhere */  | 
113  | 0  |   if (!jobj_segment ||  | 
114  | 0  |       !json_object_object_get_ex(jobj_segment, "encryption", &jobj))  | 
115  | 0  |     return "null";  | 
116  |  |  | 
117  | 0  |   return json_object_get_string(jobj);  | 
118  | 0  | }  | 
119  |  |  | 
120  |  | uint32_t json_segment_get_sector_size(json_object *jobj_segment)  | 
121  | 2.29k  | { | 
122  | 2.29k  |   json_object *jobj;  | 
123  | 2.29k  |   int i;  | 
124  |  |  | 
125  | 2.29k  |   if (!jobj_segment ||  | 
126  | 2.29k  |             !json_object_object_get_ex(jobj_segment, "sector_size", &jobj))  | 
127  | 1.98k  |     return SECTOR_SIZE;  | 
128  |  |  | 
129  | 310  |   i = json_object_get_int(jobj);  | 
130  | 310  |   return i < 0 ? SECTOR_SIZE : i;  | 
131  | 2.29k  | }  | 
132  |  |  | 
133  |  | int json_segment_get_opal_segment_id(json_object *jobj_segment, uint32_t *ret_opal_segment_id)  | 
134  | 0  | { | 
135  | 0  |   json_object *jobj_segment_id;  | 
136  |  | 
  | 
137  | 0  |   assert(ret_opal_segment_id);  | 
138  |  |  | 
139  | 0  |   if (!json_object_object_get_ex(jobj_segment, "opal_segment_number", &jobj_segment_id))  | 
140  | 0  |     return -EINVAL;  | 
141  |  |  | 
142  | 0  |   *ret_opal_segment_id = json_object_get_int(jobj_segment_id);  | 
143  |  | 
  | 
144  | 0  |   return 0;  | 
145  | 0  | }  | 
146  |  |  | 
147  |  | int json_segment_get_opal_key_size(json_object *jobj_segment, size_t *ret_key_size)  | 
148  | 0  | { | 
149  | 0  |   json_object *jobj_key_size;  | 
150  |  | 
  | 
151  | 0  |   assert(ret_key_size);  | 
152  |  |  | 
153  | 0  |   if (!jobj_segment)  | 
154  | 0  |     return -EINVAL;  | 
155  |  |  | 
156  | 0  |   if (!json_object_object_get_ex(jobj_segment, "opal_key_size", &jobj_key_size))  | 
157  | 0  |     return -EINVAL;  | 
158  |  |  | 
159  | 0  |   *ret_key_size = json_object_get_int(jobj_key_size);  | 
160  |  | 
  | 
161  | 0  |   return 0;  | 
162  | 0  | }  | 
163  |  |  | 
164  |  | static json_object *json_segment_get_flags(json_object *jobj_segment)  | 
165  | 16.6k  | { | 
166  | 16.6k  |   json_object *jobj;  | 
167  |  |  | 
168  | 16.6k  |   if (!jobj_segment || !(json_object_object_get_ex(jobj_segment, "flags", &jobj)))  | 
169  | 1.90k  |     return NULL;  | 
170  | 14.7k  |   return jobj;  | 
171  | 16.6k  | }  | 
172  |  |  | 
173  |  | bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len)  | 
174  | 16.6k  | { | 
175  | 16.6k  |   int r, i;  | 
176  | 16.6k  |   json_object *jobj, *jobj_flags = json_segment_get_flags(jobj_segment);  | 
177  |  |  | 
178  | 16.6k  |   if (!jobj_flags)  | 
179  | 1.90k  |     return false;  | 
180  |  |  | 
181  | 44.4k  |   for (i = 0; i < (int)json_object_array_length(jobj_flags); i++) { | 
182  | 30.2k  |     jobj = json_object_array_get_idx(jobj_flags, i);  | 
183  | 30.2k  |     if (len)  | 
184  | 29.3k  |       r = strncmp(json_object_get_string(jobj), flag_str, len);  | 
185  | 858  |     else  | 
186  | 858  |       r = strcmp(json_object_get_string(jobj), flag_str);  | 
187  | 30.2k  |     if (!r)  | 
188  | 539  |       return true;  | 
189  | 30.2k  |   }  | 
190  |  |  | 
191  | 14.2k  |   return false;  | 
192  | 14.7k  | }  | 
193  |  |  | 
194  |  | bool json_segment_is_backup(json_object *jobj_segment)  | 
195  | 16.6k  | { | 
196  | 16.6k  |   return json_segment_contains_flag(jobj_segment, "backup-", 7);  | 
197  | 16.6k  | }  | 
198  |  |  | 
199  |  | json_object *json_segments_get_segment(json_object *jobj_segments, int segment)  | 
200  | 9.37k  | { | 
201  | 9.37k  |   json_object *jobj;  | 
202  | 9.37k  |   char segment_name[16];  | 
203  |  |  | 
204  | 9.37k  |   if (snprintf(segment_name, sizeof(segment_name), "%u", segment) < 1)  | 
205  | 0  |     return NULL;  | 
206  |  |  | 
207  | 9.37k  |   if (!json_object_object_get_ex(jobj_segments, segment_name, &jobj))  | 
208  | 30  |     return NULL;  | 
209  |  |  | 
210  | 9.34k  |   return jobj;  | 
211  | 9.37k  | }  | 
212  |  |  | 
213  |  | unsigned json_segments_count(json_object *jobj_segments)  | 
214  | 2.29k  | { | 
215  | 2.29k  |   unsigned count = 0;  | 
216  |  |  | 
217  | 2.29k  |   if (!jobj_segments)  | 
218  | 0  |     return 0;  | 
219  |  |  | 
220  | 2.32k  |   json_object_object_foreach(jobj_segments, slot, val) { | 
221  | 2.32k  |     UNUSED(slot);  | 
222  | 2.32k  |     if (!json_segment_is_backup(val))  | 
223  | 2.30k  |       count++;  | 
224  | 2.32k  |   }  | 
225  |  |  | 
226  | 2.29k  |   return count;  | 
227  | 2.29k  | }  | 
228  |  |  | 
229  |  | void json_segment_remove_flag(json_object *jobj_segment, const char *flag)  | 
230  | 0  | { | 
231  | 0  |   json_object *jobj_flags, *jobj_flags_new;  | 
232  |  | 
  | 
233  | 0  |   if (!jobj_segment)  | 
234  | 0  |     return;  | 
235  |  |  | 
236  | 0  |   jobj_flags = json_segment_get_flags(jobj_segment);  | 
237  | 0  |   if (!jobj_flags)  | 
238  | 0  |     return;  | 
239  |  |  | 
240  | 0  |   jobj_flags_new = LUKS2_array_remove(jobj_flags, flag);  | 
241  | 0  |   if (!jobj_flags_new)  | 
242  | 0  |     return;  | 
243  |  |  | 
244  | 0  |   if (json_object_array_length(jobj_flags_new) <= 0) { | 
245  | 0  |     json_object_put(jobj_flags_new);  | 
246  | 0  |     json_object_object_del(jobj_segment, "flags");  | 
247  | 0  |   } else  | 
248  | 0  |     json_object_object_add(jobj_segment, "flags", jobj_flags_new);  | 
249  | 0  | }  | 
250  |  |  | 
251  |  | static json_object *_segment_create_generic(const char *type, uint64_t offset, const uint64_t *length)  | 
252  | 0  | { | 
253  | 0  |   json_object *jobj = json_object_new_object();  | 
254  | 0  |   if (!jobj)  | 
255  | 0  |     return NULL;  | 
256  |  |  | 
257  | 0  |   json_object_object_add(jobj, "type",    json_object_new_string(type));  | 
258  | 0  |   json_object_object_add(jobj, "offset",    crypt_jobj_new_uint64(offset));  | 
259  | 0  |   json_object_object_add(jobj, "size",    length ? crypt_jobj_new_uint64(*length) : json_object_new_string("dynamic")); | 
260  |  | 
  | 
261  | 0  |   return jobj;  | 
262  | 0  | }  | 
263  |  |  | 
264  |  | json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption)  | 
265  | 0  | { | 
266  | 0  |   json_object *jobj = _segment_create_generic("linear", offset, length); | 
267  | 0  |   if (reencryption)  | 
268  | 0  |     LUKS2_segment_set_flag(jobj, "in-reencryption");  | 
269  | 0  |   return jobj;  | 
270  | 0  | }  | 
271  |  |  | 
272  |  | static bool json_add_crypt_fields(json_object *jobj_segment, uint64_t iv_offset,  | 
273  |  |           const char *cipher, const char *integrity, uint32_t integrity_key_size,  | 
274  |  |           uint32_t sector_size, unsigned reencryption)  | 
275  | 0  | { | 
276  | 0  |   json_object *jobj_integrity;  | 
277  |  | 
  | 
278  | 0  |   assert(cipher);  | 
279  |  |  | 
280  | 0  |   json_object_object_add(jobj_segment, "iv_tweak",    crypt_jobj_new_uint64(iv_offset));  | 
281  | 0  |   json_object_object_add(jobj_segment, "encryption",  json_object_new_string(cipher));  | 
282  | 0  |   json_object_object_add(jobj_segment, "sector_size", json_object_new_int(sector_size));  | 
283  |  | 
  | 
284  | 0  |   if (integrity) { | 
285  | 0  |     jobj_integrity = json_object_new_object();  | 
286  | 0  |     if (!jobj_integrity)  | 
287  | 0  |       return false;  | 
288  |  |  | 
289  | 0  |     json_object_object_add(jobj_integrity, "type", json_object_new_string(integrity));  | 
290  | 0  |     json_object_object_add(jobj_integrity, "journal_encryption", json_object_new_string("none")); | 
291  | 0  |     json_object_object_add(jobj_integrity, "journal_integrity", json_object_new_string("none")); | 
292  | 0  |     if (integrity_key_size)  | 
293  | 0  |       json_object_object_add(jobj_integrity, "key_size", json_object_new_int(integrity_key_size));  | 
294  | 0  |     json_object_object_add(jobj_segment,   "integrity", jobj_integrity);  | 
295  | 0  |   }  | 
296  |  |  | 
297  | 0  |   if (reencryption)  | 
298  | 0  |     LUKS2_segment_set_flag(jobj_segment, "in-reencryption");  | 
299  |  | 
  | 
300  | 0  |   return true;  | 
301  | 0  | }  | 
302  |  |  | 
303  |  | json_object *json_segment_create_crypt(uint64_t offset,  | 
304  |  |           uint64_t iv_offset, const uint64_t *length,  | 
305  |  |           const char *cipher, const char *integrity, uint32_t integrity_key_size,  | 
306  |  |           uint32_t sector_size, unsigned reencryption)  | 
307  | 0  | { | 
308  | 0  |   json_object *jobj = _segment_create_generic("crypt", offset, length); | 
309  |  | 
  | 
310  | 0  |   if (!jobj)  | 
311  | 0  |     return NULL;  | 
312  |  |  | 
313  | 0  |   if (json_add_crypt_fields(jobj, iv_offset, cipher, integrity, integrity_key_size, sector_size, reencryption))  | 
314  | 0  |     return jobj;  | 
315  |  |  | 
316  | 0  |   json_object_put(jobj);  | 
317  | 0  |   return NULL;  | 
318  | 0  | }  | 
319  |  |  | 
320  |  | static void json_add_opal_fields(json_object *jobj_segment, const uint64_t *length,  | 
321  |  |          uint32_t segment_number, uint32_t key_size)  | 
322  | 0  | { | 
323  | 0  |   assert(jobj_segment);  | 
324  | 0  |   assert(length);  | 
325  |  |  | 
326  | 0  |   json_object_object_add(jobj_segment, "opal_segment_number", json_object_new_int(segment_number));  | 
327  | 0  |   json_object_object_add(jobj_segment, "opal_key_size", json_object_new_int(key_size));  | 
328  | 0  |   json_object_object_add(jobj_segment, "opal_segment_size", crypt_jobj_new_uint64(*length));  | 
329  | 0  | }  | 
330  |  |  | 
331  |  | json_object *json_segment_create_opal(uint64_t offset, const uint64_t *length,  | 
332  |  |               uint32_t segment_number, uint32_t key_size)  | 
333  | 0  | { | 
334  | 0  |   json_object *jobj = _segment_create_generic("hw-opal", offset, length); | 
335  | 0  |   if (!jobj)  | 
336  | 0  |     return NULL;  | 
337  |  |  | 
338  | 0  |   json_add_opal_fields(jobj, length, segment_number, key_size);  | 
339  |  | 
  | 
340  | 0  |   return jobj;  | 
341  | 0  | }  | 
342  |  |  | 
343  |  | json_object *json_segment_create_opal_crypt(uint64_t offset, const uint64_t *length,  | 
344  |  |               uint32_t segment_number, uint32_t key_size,  | 
345  |  |               uint64_t iv_offset, const char *cipher,  | 
346  |  |               const char *integrity, uint32_t sector_size,  | 
347  |  |               unsigned reencryption)  | 
348  | 0  | { | 
349  | 0  |   json_object *jobj = _segment_create_generic("hw-opal-crypt", offset, length); | 
350  | 0  |   if (!jobj)  | 
351  | 0  |     return NULL;  | 
352  |  |  | 
353  | 0  |   json_add_opal_fields(jobj, length, segment_number, key_size);  | 
354  |  | 
  | 
355  | 0  |   if (json_add_crypt_fields(jobj, iv_offset, cipher, integrity, 0, sector_size, reencryption))  | 
356  | 0  |     return jobj;  | 
357  |  |  | 
358  | 0  |   json_object_put(jobj);  | 
359  | 0  |   return NULL;  | 
360  | 0  | }  | 
361  |  |  | 
362  |  | uint64_t LUKS2_segment_offset(struct luks2_hdr *hdr, int segment, unsigned blockwise)  | 
363  | 0  | { | 
364  | 0  |   return json_segment_get_offset(LUKS2_get_segment_jobj(hdr, segment), blockwise);  | 
365  | 0  | }  | 
366  |  |  | 
367  |  | int json_segments_segment_in_reencrypt(json_object *jobj_segments)  | 
368  | 0  | { | 
369  | 0  |   json_object *jobj_flags;  | 
370  |  | 
  | 
371  | 0  |   json_object_object_foreach(jobj_segments, slot, val) { | 
372  | 0  |     if (!json_object_object_get_ex(val, "flags", &jobj_flags) ||  | 
373  | 0  |         !LUKS2_array_jobj(jobj_flags, "in-reencryption"))  | 
374  | 0  |       continue;  | 
375  |  |  | 
376  | 0  |     return atoi(slot);  | 
377  | 0  |   }  | 
378  |  |  | 
379  | 0  |   return -1;  | 
380  | 0  | }  | 
381  |  |  | 
382  |  | uint64_t LUKS2_segment_size(struct luks2_hdr *hdr, int segment, unsigned blockwise)  | 
383  | 0  | { | 
384  | 0  |   return json_segment_get_size(LUKS2_get_segment_jobj(hdr, segment), blockwise);  | 
385  | 0  | }  | 
386  |  |  | 
387  |  | uint64_t LUKS2_opal_segment_size(struct luks2_hdr *hdr, int segment, unsigned blockwise)  | 
388  | 0  | { | 
389  | 0  |   return json_segment_get_opal_size(LUKS2_get_segment_jobj(hdr, segment), blockwise);  | 
390  | 0  | }  | 
391  |  |  | 
392  |  | bool LUKS2_segment_set_size(struct luks2_hdr *hdr, int segment, const uint64_t *segment_size_bytes)  | 
393  | 0  | { | 
394  | 0  |   return json_segment_set_size(LUKS2_get_segment_jobj(hdr, segment), segment_size_bytes);  | 
395  | 0  | }  | 
396  |  |  | 
397  |  | int LUKS2_segment_is_type(struct luks2_hdr *hdr, int segment, const char *type)  | 
398  | 0  | { | 
399  | 0  |   return !strcmp(json_segment_type(LUKS2_get_segment_jobj(hdr, segment)) ?: "", type);  | 
400  | 0  | }  | 
401  |  |  | 
402  |  | static bool json_segment_is_hw_opal_only(json_object *jobj_segment)  | 
403  | 0  | { | 
404  | 0  |   const char *type = json_segment_type(jobj_segment);  | 
405  |  | 
  | 
406  | 0  |   if (!type)  | 
407  | 0  |     return false;  | 
408  |  |  | 
409  | 0  |   return !strcmp(type, "hw-opal");  | 
410  | 0  | }  | 
411  |  |  | 
412  |  | static bool json_segment_is_hw_opal_crypt(json_object *jobj_segment)  | 
413  | 0  | { | 
414  | 0  |   const char *type = json_segment_type(jobj_segment);  | 
415  |  | 
  | 
416  | 0  |   if (!type)  | 
417  | 0  |     return false;  | 
418  |  |  | 
419  | 0  |   return !strcmp(type, "hw-opal-crypt");  | 
420  | 0  | }  | 
421  |  |  | 
422  |  | static bool json_segment_is_hw_opal(json_object *jobj_segment)  | 
423  | 0  | { | 
424  | 0  |   return json_segment_is_hw_opal_crypt(jobj_segment) ||  | 
425  | 0  |          json_segment_is_hw_opal_only(jobj_segment);  | 
426  | 0  | }  | 
427  |  |  | 
428  |  | bool LUKS2_segment_is_hw_opal_only(struct luks2_hdr *hdr, int segment)  | 
429  | 0  | { | 
430  | 0  |   return json_segment_is_hw_opal_only(LUKS2_get_segment_jobj(hdr, segment));  | 
431  | 0  | }  | 
432  |  |  | 
433  |  | bool LUKS2_segment_is_hw_opal_crypt(struct luks2_hdr *hdr, int segment)  | 
434  | 0  | { | 
435  | 0  |   return json_segment_is_hw_opal_crypt(LUKS2_get_segment_jobj(hdr, segment));  | 
436  | 0  | }  | 
437  |  |  | 
438  |  | bool LUKS2_segment_is_hw_opal(struct luks2_hdr *hdr, int segment)  | 
439  | 0  | { | 
440  | 0  |   return json_segment_is_hw_opal(LUKS2_get_segment_jobj(hdr, segment));  | 
441  | 0  | }  | 
442  |  |  | 
443  |  | int LUKS2_get_opal_segment_number(struct luks2_hdr *hdr, int segment, uint32_t *ret_opal_segment_number)  | 
444  | 0  | { | 
445  | 0  |   json_object *jobj_segment = LUKS2_get_segment_jobj(hdr, segment);  | 
446  |  | 
  | 
447  | 0  |   assert(ret_opal_segment_number);  | 
448  |  |  | 
449  | 0  |   if (!json_segment_is_hw_opal(jobj_segment))  | 
450  | 0  |     return -ENOENT;  | 
451  |  |  | 
452  | 0  |   return json_segment_get_opal_segment_id(jobj_segment, ret_opal_segment_number);  | 
453  | 0  | }  | 
454  |  |  | 
455  |  | int LUKS2_get_opal_key_size(struct luks2_hdr *hdr, int segment)  | 
456  | 0  | { | 
457  | 0  |   size_t key_size = 0;  | 
458  | 0  |   json_object *jobj_segment = LUKS2_get_segment_jobj(hdr, segment);  | 
459  |  | 
  | 
460  | 0  |   if (json_segment_get_opal_key_size(jobj_segment, &key_size) < 0)  | 
461  | 0  |     return 0;  | 
462  |  |  | 
463  | 0  |   return key_size;  | 
464  | 0  | }  | 
465  |  |  | 
466  |  | int LUKS2_last_segment_by_type(struct luks2_hdr *hdr, const char *type)  | 
467  | 0  | { | 
468  | 0  |   json_object *jobj_segments;  | 
469  | 0  |   int last_found = -1;  | 
470  |  | 
  | 
471  | 0  |   if (!type)  | 
472  | 0  |     return -1;  | 
473  |  |  | 
474  | 0  |   if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))  | 
475  | 0  |     return -1;  | 
476  |  |  | 
477  | 0  |   json_object_object_foreach(jobj_segments, slot, val) { | 
478  | 0  |     if (json_segment_is_backup(val))  | 
479  | 0  |       continue;  | 
480  | 0  |     if (strcmp(type, json_segment_type(val) ?: ""))  | 
481  | 0  |       continue;  | 
482  |  |  | 
483  | 0  |     if (atoi(slot) > last_found)  | 
484  | 0  |       last_found = atoi(slot);  | 
485  | 0  |   }  | 
486  |  | 
  | 
487  | 0  |   return last_found;  | 
488  | 0  | }  | 
489  |  |  | 
490  |  | int LUKS2_segment_by_type(struct luks2_hdr *hdr, const char *type)  | 
491  | 0  | { | 
492  | 0  |   json_object *jobj_segments;  | 
493  | 0  |   int first_found = -1;  | 
494  |  | 
  | 
495  | 0  |   if (!type)  | 
496  | 0  |     return -EINVAL;  | 
497  |  |  | 
498  | 0  |   if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))  | 
499  | 0  |     return -EINVAL;  | 
500  |  |  | 
501  | 0  |   json_object_object_foreach(jobj_segments, slot, val) { | 
502  | 0  |     if (json_segment_is_backup(val))  | 
503  | 0  |       continue;  | 
504  | 0  |     if (strcmp(type, json_segment_type(val) ?: ""))  | 
505  | 0  |       continue;  | 
506  |  |  | 
507  | 0  |     if (first_found < 0)  | 
508  | 0  |       first_found = atoi(slot);  | 
509  | 0  |     else if (atoi(slot) < first_found)  | 
510  | 0  |       first_found = atoi(slot);  | 
511  | 0  |   }  | 
512  |  | 
  | 
513  | 0  |   return first_found;  | 
514  | 0  | }  | 
515  |  |  | 
516  |  | int LUKS2_segment_first_unused_id(struct luks2_hdr *hdr)  | 
517  | 0  | { | 
518  | 0  |   json_object *jobj_segments;  | 
519  |  | 
  | 
520  | 0  |   if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))  | 
521  | 0  |     return -EINVAL;  | 
522  |  |  | 
523  | 0  |   return json_object_object_length(jobj_segments);  | 
524  | 0  | }  | 
525  |  |  | 
526  |  | int LUKS2_segment_set_flag(json_object *jobj_segment, const char *flag)  | 
527  | 0  | { | 
528  | 0  |   json_object *jobj_flags;  | 
529  |  | 
  | 
530  | 0  |   if (!jobj_segment || !flag)  | 
531  | 0  |     return -EINVAL;  | 
532  |  |  | 
533  | 0  |   if (!json_object_object_get_ex(jobj_segment, "flags", &jobj_flags)) { | 
534  | 0  |     jobj_flags = json_object_new_array();  | 
535  | 0  |     if (!jobj_flags)  | 
536  | 0  |       return -ENOMEM;  | 
537  | 0  |     json_object_object_add(jobj_segment, "flags", jobj_flags);  | 
538  | 0  |   }  | 
539  |  |  | 
540  | 0  |   if (LUKS2_array_jobj(jobj_flags, flag))  | 
541  | 0  |     return 0;  | 
542  |  |  | 
543  | 0  |   json_object_array_add(jobj_flags, json_object_new_string(flag));  | 
544  |  | 
  | 
545  | 0  |   return 0;  | 
546  | 0  | }  | 
547  |  |  | 
548  |  | int LUKS2_segments_set(struct crypt_device *cd, struct luks2_hdr *hdr,  | 
549  |  |            json_object *jobj_segments, int commit)  | 
550  | 0  | { | 
551  | 0  |   json_object_object_add(hdr->jobj, "segments", jobj_segments);  | 
552  |  | 
  | 
553  | 0  |   return commit ? LUKS2_hdr_write(cd, hdr) : 0;  | 
554  | 0  | }  | 
555  |  |  | 
556  |  | int LUKS2_get_segment_id_by_flag(struct luks2_hdr *hdr, const char *flag)  | 
557  | 2.29k  | { | 
558  | 2.29k  |   json_object *jobj_flags, *jobj_segments = LUKS2_get_segments_jobj(hdr);  | 
559  |  |  | 
560  | 2.29k  |   if (!flag || !jobj_segments)  | 
561  | 0  |     return -ENOENT;  | 
562  |  |  | 
563  | 2.33k  |   json_object_object_foreach(jobj_segments, key, value) { | 
564  | 2.33k  |     if (!json_object_object_get_ex(value, "flags", &jobj_flags))  | 
565  | 334  |       continue;  | 
566  | 1.99k  |     if (LUKS2_array_jobj(jobj_flags, flag))  | 
567  | 1  |       return atoi(key);  | 
568  | 1.99k  |   }  | 
569  |  |  | 
570  | 2.29k  |   return -ENOENT;  | 
571  | 2.29k  | }  | 
572  |  |  | 
573  |  | json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag)  | 
574  | 0  | { | 
575  | 0  |   json_object *jobj_flags, *jobj_segments = LUKS2_get_segments_jobj(hdr);  | 
576  |  | 
  | 
577  | 0  |   if (!flag || !jobj_segments)  | 
578  | 0  |     return NULL;  | 
579  |  |  | 
580  | 0  |   json_object_object_foreach(jobj_segments, key, value) { | 
581  | 0  |     UNUSED(key);  | 
582  | 0  |     if (!json_object_object_get_ex(value, "flags", &jobj_flags))  | 
583  | 0  |       continue;  | 
584  | 0  |     if (LUKS2_array_jobj(jobj_flags, flag))  | 
585  | 0  |       return value;  | 
586  | 0  |   }  | 
587  |  |  | 
588  | 0  |   return NULL;  | 
589  | 0  | }  | 
590  |  |  | 
591  |  | /* compares key characteristics of both segments */  | 
592  |  | bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2)  | 
593  | 6  | { | 
594  | 6  |   const char *type = json_segment_type(jobj_segment_1);  | 
595  | 6  |   const char *type2 = json_segment_type(jobj_segment_2);  | 
596  |  |  | 
597  | 6  |   if (!type || !type2)  | 
598  | 0  |     return false;  | 
599  |  |  | 
600  | 6  |   if (strcmp(type, type2))  | 
601  | 6  |     return false;  | 
602  |  |  | 
603  | 0  |   if (!strcmp(type, "crypt"))  | 
604  | 0  |     return (json_segment_get_sector_size(jobj_segment_1) == json_segment_get_sector_size(jobj_segment_2) &&  | 
605  | 0  |       !strcmp(json_segment_get_cipher(jobj_segment_1),  | 
606  | 0  |               json_segment_get_cipher(jobj_segment_2)));  | 
607  |  |  | 
608  | 0  |   return true;  | 
609  | 0  | }  | 
610  |  |  | 
611  |  | bool LUKS2_segments_dynamic_size(struct luks2_hdr *hdr)  | 
612  | 0  | { | 
613  | 0  |   json_object *jobj_segments, *jobj_size;  | 
614  |  | 
  | 
615  | 0  |   assert(hdr);  | 
616  |  |  | 
617  | 0  |   jobj_segments = LUKS2_get_segments_jobj(hdr);  | 
618  | 0  |   if (!jobj_segments)  | 
619  | 0  |     return false;  | 
620  |  |  | 
621  | 0  |   json_object_object_foreach(jobj_segments, key, val) { | 
622  | 0  |     UNUSED(key);  | 
623  |  | 
  | 
624  | 0  |     if (json_segment_is_backup(val))  | 
625  | 0  |       continue;  | 
626  |  |  | 
627  | 0  |     if (json_object_object_get_ex(val, "size", &jobj_size) &&  | 
628  | 0  |         !strcmp(json_object_get_string(jobj_size), "dynamic"))  | 
629  | 0  |       return true;  | 
630  | 0  |   }  | 
631  |  |  | 
632  | 0  |   return false;  | 
633  | 0  | }  |