s4:dsdb: Add functions for Group Managed Service Accounts implementation
[Samba.git] / source4 / dsdb / gmsa / gkdi.c
blob917b13559587bf4d6429869f20f7084f62ab73a0
1 /*
2 Unix SMB/CIFS implementation.
3 Group Key Distribution Protocol functions
5 Copyright (C) Catalyst.Net Ltd 2024
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include <ldb.h>
23 #include <ldb_errors.h>
24 #include <ldb_module.h>
25 #include "lib/crypto/gkdi.h"
26 #include "lib/util/data_blob.h"
27 #include "lib/util/samba_util.h"
28 #include "lib/util/util_str_hex.h"
29 #include "librpc/ndr/libndr.h"
30 #include "dsdb/gmsa/gkdi.h"
31 #include "dsdb/samdb/ldb_modules/util.h"
32 #include "dsdb/samdb/samdb.h"
33 #include "dsdb/common/proto.h"
34 #include "librpc/gen_ndr/gkdi.h"
35 #include "librpc/gen_ndr/ndr_gkdi.h"
37 NTSTATUS gkdi_root_key_from_msg(TALLOC_CTX *mem_ctx,
38 const struct GUID root_key_id,
39 const struct ldb_message *const msg,
40 const struct ProvRootKey **const root_key_out)
42 NTSTATUS status = NT_STATUS_OK;
43 struct ldb_val root_key_data = {};
44 struct KdfAlgorithm kdf_algorithm = {};
46 const int version = ldb_msg_find_attr_as_int(msg, "msKds-Version", 0);
47 const NTTIME create_time = samdb_result_nttime(msg,
48 "msKds-CreateTime",
49 0);
50 const NTTIME use_start_time = samdb_result_nttime(msg,
51 "msKds-UseStartTime",
52 0);
53 const char *domain_id = ldb_msg_find_attr_as_string(msg,
54 "msKds-DomainID",
55 NULL);
58 const struct ldb_val *root_key_val = ldb_msg_find_ldb_val(
59 msg, "msKds-RootKeyData");
60 if (root_key_val != NULL) {
61 root_key_data = *root_key_val;
66 const char *algorithm_id = ldb_msg_find_attr_as_string(
67 msg, "msKds-KDFAlgorithmID", NULL);
68 const struct ldb_val *kdf_param_val = ldb_msg_find_ldb_val(
69 msg, "msKds-KDFParam");
70 status = kdf_algorithm_from_params(algorithm_id,
71 kdf_param_val,
72 &kdf_algorithm);
73 if (!NT_STATUS_IS_OK(status)) {
74 goto out;
78 status = ProvRootKey(mem_ctx,
79 root_key_id,
80 version,
81 root_key_data,
82 create_time,
83 use_start_time,
84 domain_id,
85 kdf_algorithm,
86 root_key_out);
87 if (!NT_STATUS_IS_OK(status)) {
88 goto out;
91 out:
92 return status;
96 * Calculate an appropriate useStartTime for a root key created at
97 * ‘current_time’.
99 * This function goes unused.
101 NTTIME gkdi_root_key_use_start_time(const NTTIME current_time)
103 const NTTIME start_time = gkdi_get_interval_start_time(current_time);
105 return start_time + gkdi_key_cycle_duration + gkdi_max_clock_skew;
108 static int gkdi_create_root_key(TALLOC_CTX *mem_ctx,
109 struct ldb_context *const ldb,
110 const NTTIME current_time,
111 const NTTIME use_start_time,
112 struct GUID *const root_key_id_out,
113 struct ldb_dn **const root_key_dn_out)
115 TALLOC_CTX *tmp_ctx = NULL;
116 struct GUID root_key_id;
117 struct ldb_dn *server_config_dn = NULL;
118 struct ldb_result *server_config_res = NULL;
119 struct ldb_message *server_config_msg = NULL;
120 uint64_t server_config_version;
121 const struct ldb_val *server_config_version_val = NULL;
122 const char *server_config_KDFAlgorithmID = NULL;
123 const struct ldb_val *server_config_KDFParam = NULL;
124 const char *server_config_SecretAgreementAlgorithmID = NULL;
125 const struct ldb_val *server_config_SecretAgreementParam = NULL;
126 uint64_t server_config_PublicKeyLength;
127 uint64_t server_config_PrivateKeyLength;
128 struct KdfAlgorithm kdf_algorithm;
129 DATA_BLOB kdf_parameters_blob = data_blob_null;
130 struct ldb_message *add_msg = NULL;
131 NTSTATUS status = NT_STATUS_OK;
132 int ret = LDB_SUCCESS;
134 static const char *server_config_attrs[] = {
135 "msKds-Version",
136 "msKds-KDFAlgorithmID",
137 "msKds-SecretAgreementAlgorithmID",
138 "msKds-SecretAgreementParam",
139 "msKds-PublicKeyLength",
140 "msKds-PrivateKeyLength",
141 "msKds-KDFParam",
142 NULL
145 *root_key_dn_out = NULL;
147 tmp_ctx = talloc_new(mem_ctx);
148 if (tmp_ctx == NULL) {
149 ret = ldb_oom(ldb);
150 goto out;
153 server_config_dn = samdb_configuration_dn(ldb,
154 mem_ctx,
155 "CN=Group Key Distribution Service Server Configuration,"
156 "CN=Server Configuration,"
157 "CN=Group Key Distribution Service,"
158 "CN=Services");
159 if (server_config_dn == NULL) {
160 ret = ldb_oom(ldb);
161 goto out;
164 ret = dsdb_search_dn(ldb,
165 tmp_ctx,
166 &server_config_res,
167 server_config_dn,
168 server_config_attrs,
169 DSDB_SEARCH_ONE_ONLY);
171 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
172 ldb_asprintf_errstring(ldb, "Unable to create new GKDI root key as we do not have a GKDI server configuration at %s",
173 ldb_dn_get_linearized(server_config_dn));
174 goto out;
177 if (ret != LDB_SUCCESS) {
178 goto out;
181 server_config_msg = server_config_res->msgs[0];
183 server_config_version_val
184 = ldb_msg_find_ldb_val(server_config_msg,
185 "msKds-Version");
186 server_config_version
187 = ldb_msg_find_attr_as_uint64(server_config_msg,
188 "msKds-Version",
191 /* These values we assert on, so we don't create keys we can't use */
192 if (server_config_version_val == NULL) {
194 * The systemMustContain msKds-Version attribute
195 * cannot be read, so if absent we just fail with
196 * permission denied, as that is all that this can
197 * mean
199 ldb_asprintf_errstring(ldb,
200 "Unwilling to create new GKDI root key as "
201 "msKds-Version is not readable on %s\n",
202 ldb_dn_get_linearized(server_config_dn));
203 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
204 goto out;
205 } else if (server_config_version != 1) {
206 ldb_asprintf_errstring(ldb,
207 "Unwilling to create new GKDI root key as "
208 "%s has msKds-Version = %s "
209 "and we only support version 1\n",
210 ldb_dn_get_linearized(server_config_dn),
211 ldb_msg_find_attr_as_string(server_config_msg, "msKds-Version", "(missing)"));
212 ret = LDB_ERR_CONSTRAINT_VIOLATION;
213 goto out;
216 server_config_KDFAlgorithmID
217 = ldb_msg_find_attr_as_string(server_config_msg,
218 "msKds-KDFAlgorithmID",
219 SP800_108_CTR_HMAC
222 server_config_KDFParam
223 = ldb_msg_find_ldb_val(server_config_msg,
224 "msKds-KDFParam");
225 if (server_config_KDFParam == NULL) {
226 struct KdfParameters kdf_parameters = {
227 .hash_algorithm = "SHA512"
229 enum ndr_err_code err;
231 err = ndr_push_struct_blob(&kdf_parameters_blob,
232 tmp_ctx,
233 &kdf_parameters,
234 (ndr_push_flags_fn_t)
235 ndr_push_KdfParameters);
237 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
238 status = ndr_map_error2ntstatus(err);
239 ldb_asprintf_errstring(ldb,
240 "KdfParameters pull failed: %s\n",
241 nt_errstr(status));
242 ret = LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
243 goto out;
246 server_config_KDFParam = &kdf_parameters_blob;
249 status = kdf_algorithm_from_params(server_config_KDFAlgorithmID,
250 server_config_KDFParam,
251 &kdf_algorithm);
252 if (!NT_STATUS_IS_OK(status)) {
253 ldb_asprintf_errstring(ldb,
254 "Unwilling to create new GKDI root key as "
255 "%s has an unsupported msKds-KDFAlgorithmID / msKds-KDFParam combination set: %s\n",
256 ldb_dn_get_linearized(server_config_dn),
257 nt_errstr(status));
258 ret = LDB_ERR_CONSTRAINT_VIOLATION;
259 goto out;
262 server_config_SecretAgreementAlgorithmID
263 = ldb_msg_find_attr_as_string(server_config_msg,
264 "msKds-SecretAgreementAlgorithmID",
265 "DH");
267 /* Optional in msKds-ProvRootKey */
268 server_config_SecretAgreementParam
269 = ldb_msg_find_ldb_val(server_config_msg,
270 "msKds-SecretAgreementParam");
271 if (server_config_SecretAgreementParam == NULL) {
272 static const uint8_t ffc_dh_parameters[] = {
273 12, 2, 0, 0, 68, 72, 80, 77, 0, 1, 0,
274 0, 135, 168, 230, 29, 180, 182, 102, 60, 255, 187,
275 209, 156, 101, 25, 89, 153, 140, 238, 246, 8, 102,
276 13, 208, 242, 93, 44, 238, 212, 67, 94, 59, 0,
277 224, 13, 248, 241, 214, 25, 87, 212, 250, 247, 223,
278 69, 97, 178, 170, 48, 22, 195, 217, 17, 52, 9,
279 111, 170, 59, 244, 41, 109, 131, 14, 154, 124, 32,
280 158, 12, 100, 151, 81, 122, 189, 90, 138, 157, 48,
281 107, 207, 103, 237, 145, 249, 230, 114, 91, 71, 88,
282 192, 34, 224, 177, 239, 66, 117, 191, 123, 108, 91,
283 252, 17, 212, 95, 144, 136, 185, 65, 245, 78, 177,
284 229, 155, 184, 188, 57, 160, 191, 18, 48, 127, 92,
285 79, 219, 112, 197, 129, 178, 63, 118, 182, 58, 202,
286 225, 202, 166, 183, 144, 45, 82, 82, 103, 53, 72,
287 138, 14, 241, 60, 109, 154, 81, 191, 164, 171, 58,
288 216, 52, 119, 150, 82, 77, 142, 246, 161, 103, 181,
289 164, 24, 37, 217, 103, 225, 68, 229, 20, 5, 100,
290 37, 28, 202, 203, 131, 230, 180, 134, 246, 179, 202,
291 63, 121, 113, 80, 96, 38, 192, 184, 87, 246, 137,
292 150, 40, 86, 222, 212, 1, 10, 189, 11, 230, 33,
293 195, 163, 150, 10, 84, 231, 16, 195, 117, 242, 99,
294 117, 215, 1, 65, 3, 164, 181, 67, 48, 193, 152,
295 175, 18, 97, 22, 210, 39, 110, 17, 113, 95, 105,
296 56, 119, 250, 215, 239, 9, 202, 219, 9, 74, 233,
297 30, 26, 21, 151, 63, 179, 44, 155, 115, 19, 77,
298 11, 46, 119, 80, 102, 96, 237, 189, 72, 76, 167,
299 177, 143, 33, 239, 32, 84, 7, 244, 121, 58, 26,
300 11, 161, 37, 16, 219, 193, 80, 119, 190, 70, 63,
301 255, 79, 237, 74, 172, 11, 181, 85, 190, 58, 108,
302 27, 12, 107, 71, 177, 188, 55, 115, 191, 126, 140,
303 111, 98, 144, 18, 40, 248, 194, 140, 187, 24, 165,
304 90, 227, 19, 65, 0, 10, 101, 1, 150, 249, 49,
305 199, 122, 87, 242, 221, 244, 99, 229, 233, 236, 20,
306 75, 119, 125, 230, 42, 170, 184, 168, 98, 138, 195,
307 118, 210, 130, 214, 237, 56, 100, 230, 121, 130, 66,
308 142, 188, 131, 29, 20, 52, 143, 111, 47, 145, 147,
309 181, 4, 90, 242, 118, 113, 100, 225, 223, 201, 103,
310 193, 251, 63, 46, 85, 164, 189, 27, 255, 232, 59,
311 156, 128, 208, 82, 185, 133, 209, 130, 234, 10, 219,
312 42, 59, 115, 19, 211, 254, 20, 200, 72, 75, 30,
313 5, 37, 136, 185, 183, 210, 187, 210, 223, 1, 97,
314 153, 236, 208, 110, 21, 87, 205, 9, 21, 179, 53,
315 59, 187, 100, 224, 236, 55, 127, 208, 40, 55, 13,
316 249, 43, 82, 199, 137, 20, 40, 205, 198, 126, 182,
317 24, 75, 82, 61, 29, 178, 70, 195, 47, 99, 7,
318 132, 144, 240, 14, 248, 214, 71, 209, 72, 212, 121,
319 84, 81, 94, 35, 39, 207, 239, 152, 197, 130, 102,
320 75, 76, 15, 108, 196, 22, 89};
321 static const DATA_BLOB ffc_dh_parameters_blob = {
322 discard_const_p(uint8_t, ffc_dh_parameters),
323 sizeof ffc_dh_parameters};
324 server_config_SecretAgreementParam = &ffc_dh_parameters_blob;
327 server_config_PublicKeyLength
328 = ldb_msg_find_attr_as_uint64(server_config_msg,
329 "msKds-PublicKeyLength",
330 2048);
332 server_config_PrivateKeyLength
333 = ldb_msg_find_attr_as_uint64(server_config_msg,
334 "msKds-PrivateKeyLength",
335 256);
337 add_msg = ldb_msg_new(tmp_ctx);
338 if (add_msg == NULL) {
339 ret = ldb_oom(ldb);
340 goto out;
343 ret = ldb_msg_append_string(add_msg,
344 "objectClass",
345 "msKds-ProvRootKey",
346 LDB_FLAG_MOD_ADD);
347 if (ret) {
348 goto out;
352 uint8_t root_key_data[GKDI_KEY_LEN];
353 const DATA_BLOB root_key_data_blob = {
354 .data = root_key_data, .length = sizeof root_key_data};
356 generate_secret_buffer(root_key_data, sizeof root_key_data);
358 ret = ldb_msg_append_value(add_msg,
359 "msKds-RootKeyData",
360 &root_key_data_blob,
361 LDB_FLAG_MOD_ADD);
362 if (ret) {
363 goto out;
367 ret = samdb_msg_append_uint64(ldb,
368 tmp_ctx,
369 add_msg,
370 "msKds-CreateTime",
371 current_time,
372 LDB_FLAG_MOD_ADD);
373 if (ret) {
374 goto out;
377 ret = samdb_msg_append_uint64(ldb,
378 tmp_ctx,
379 add_msg,
380 "msKds-UseStartTime",
381 use_start_time,
382 LDB_FLAG_MOD_ADD);
383 if (ret) {
384 goto out;
388 struct ldb_dn *domain_dn = NULL;
390 ret = samdb_server_reference_dn(ldb, tmp_ctx, &domain_dn);
391 if (ret) {
392 goto out;
395 ret = ldb_msg_append_linearized_dn(add_msg,
396 "msKds-DomainID",
397 domain_dn,
398 LDB_FLAG_MOD_ADD);
399 if (ret) {
400 goto out;
404 ret = samdb_msg_append_uint64(ldb,
405 tmp_ctx,
406 add_msg,
407 "msKds-Version",
408 server_config_version,
409 LDB_FLAG_MOD_ADD);
410 if (ret) {
411 goto out;
414 ret = ldb_msg_append_string(add_msg,
415 "msKds-KDFAlgorithmID",
416 server_config_KDFAlgorithmID,
417 LDB_FLAG_MOD_ADD);
418 if (ret) {
419 goto out;
422 ret = ldb_msg_append_string(add_msg,
423 "msKds-SecretAgreementAlgorithmID",
424 server_config_SecretAgreementAlgorithmID,
425 LDB_FLAG_MOD_ADD);
426 if (ret) {
427 goto out;
430 if (server_config_SecretAgreementParam != NULL) {
431 ret = ldb_msg_append_value(add_msg,
432 "msKds-SecretAgreementParam",
433 server_config_SecretAgreementParam,
434 LDB_FLAG_MOD_ADD);
435 if (ret) {
436 goto out;
440 ret = samdb_msg_append_uint64(ldb,
441 tmp_ctx,
442 add_msg,
443 "msKds-PublicKeyLength",
444 server_config_PublicKeyLength,
445 LDB_FLAG_MOD_ADD);
446 if (ret) {
447 goto out;
450 ret = samdb_msg_append_uint64(ldb,
451 tmp_ctx,
452 add_msg,
453 "msKds-PrivateKeyLength",
454 server_config_PrivateKeyLength,
455 LDB_FLAG_MOD_ADD);
457 ret = ldb_msg_append_value(add_msg,
458 "msKds-KDFParam",
459 server_config_KDFParam,
460 LDB_FLAG_MOD_ADD);
461 if (ret) {
462 goto out;
466 uint8_t guid_buf[sizeof((struct GUID_ndr_buf){}.buf)];
467 const DATA_BLOB guid_blob = {.data = guid_buf,
468 .length = sizeof guid_buf};
470 generate_secret_buffer(guid_buf, sizeof guid_buf);
472 status = GUID_from_ndr_blob(&guid_blob, &root_key_id);
473 if (!NT_STATUS_IS_OK(status)) {
474 ret = ldb_operr(ldb);
475 goto out;
480 struct ldb_dn *root_key_dn = NULL;
482 root_key_dn = samdb_gkdi_root_key_dn(ldb,
483 tmp_ctx,
484 &root_key_id);
485 if (root_key_dn == NULL) {
486 ret = ldb_operr(ldb);
487 goto out;
490 add_msg->dn = root_key_dn;
493 ret = dsdb_add(ldb, add_msg, 0);
494 if (ret) {
495 goto out;
498 *root_key_id_out = root_key_id;
499 *root_key_dn_out = talloc_steal(mem_ctx, add_msg->dn);
501 out:
502 talloc_free(tmp_ctx);
503 return ret;
507 * The PrivateKey, PublicKey, and SecretAgreement attributes are related to the
508 * public‐key functionality in GKDI. Samba doesn’t try to implement any of that,
509 * so we don’t bother looking at these attributes.
511 static const char *const root_key_attrs[] = {
512 "msKds-CreateTime",
513 "msKds-DomainID",
514 "msKds-KDFAlgorithmID",
515 "msKds-KDFParam",
516 /* "msKds-PrivateKeyLength", */
517 /* "msKds-PublicKeyLength", */
518 "msKds-RootKeyData",
519 /* "msKds-SecretAgreementAlgorithmID", */
520 /* "msKds-SecretAgreementParam", */
521 "msKds-UseStartTime",
522 "msKds-Version",
523 NULL,
527 * Create and return a new GKDI root key.
529 * This function goes unused.
531 int gkdi_new_root_key(TALLOC_CTX *mem_ctx,
532 struct ldb_context *const ldb,
533 const NTTIME current_time,
534 const NTTIME use_start_time,
535 struct GUID *const root_key_id_out,
536 const struct ldb_message **const root_key_out)
538 TALLOC_CTX *tmp_ctx = NULL;
539 struct ldb_dn *root_key_dn = NULL;
540 struct ldb_result *res = NULL;
541 int ret = LDB_SUCCESS;
543 *root_key_out = NULL;
545 tmp_ctx = talloc_new(mem_ctx);
546 if (tmp_ctx == NULL) {
547 ret = ldb_oom(ldb);
548 goto out;
551 ret = gkdi_create_root_key(tmp_ctx,
552 ldb,
553 current_time,
554 use_start_time,
555 root_key_id_out,
556 &root_key_dn);
557 if (ret) {
558 goto out;
561 ret = dsdb_search_dn(
562 ldb, tmp_ctx, &res, root_key_dn, root_key_attrs, 0);
563 if (ret) {
564 goto out;
567 if (res->count != 1) {
568 ret = LDB_ERR_NO_SUCH_OBJECT;
569 goto out;
572 *root_key_out = talloc_steal(mem_ctx, res->msgs[0]);
574 out:
575 talloc_free(tmp_ctx);
576 return ret;
579 int gkdi_root_key_from_id(TALLOC_CTX *mem_ctx,
580 struct ldb_context *const ldb,
581 const struct GUID *const root_key_id,
582 const struct ldb_message **const root_key_out)
584 TALLOC_CTX *tmp_ctx = NULL;
585 struct ldb_dn *root_key_dn = NULL;
586 struct ldb_result *res = NULL;
587 int ret = LDB_SUCCESS;
589 *root_key_out = NULL;
591 tmp_ctx = talloc_new(mem_ctx);
592 if (tmp_ctx == NULL) {
593 ret = ldb_oom(ldb);
594 goto out;
597 root_key_dn = samdb_gkdi_root_key_dn(ldb, tmp_ctx, root_key_id);
598 if (root_key_dn == NULL) {
599 ret = ldb_operr(ldb);
600 goto out;
603 ret = dsdb_search_dn(
604 ldb, tmp_ctx, &res, root_key_dn, root_key_attrs, 0);
605 if (ret) {
606 goto out;
609 if (res->count != 1) {
610 ret = dsdb_werror(ldb,
611 LDB_ERR_NO_SUCH_OBJECT,
612 W_ERROR(HRES_ERROR_V(HRES_NTE_NO_KEY)),
613 "failed to find root key");
614 goto out;
617 *root_key_out = talloc_steal(mem_ctx, res->msgs[0]);
619 out:
620 talloc_free(tmp_ctx);
621 return ret;
624 int gkdi_most_recently_created_root_key(
625 TALLOC_CTX *mem_ctx,
626 struct ldb_context *const ldb,
627 _UNUSED_ const NTTIME current_time,
628 const NTTIME not_after,
629 struct GUID *const root_key_id_out,
630 const struct ldb_message **const root_key_out)
632 TALLOC_CTX *tmp_ctx = NULL;
633 struct ldb_result *res = NULL;
634 int ret = LDB_SUCCESS;
636 *root_key_out = NULL;
638 tmp_ctx = talloc_new(mem_ctx);
639 if (tmp_ctx == NULL) {
640 ret = ldb_oom(ldb);
641 goto out;
645 struct ldb_dn *root_key_container_dn = NULL;
647 root_key_container_dn = samdb_gkdi_root_key_container_dn(
648 ldb, tmp_ctx);
649 if (root_key_container_dn == NULL) {
650 ret = ldb_operr(ldb);
651 goto out;
654 ret = dsdb_search(ldb,
655 tmp_ctx,
656 &res,
657 root_key_container_dn,
658 LDB_SCOPE_ONELEVEL,
659 root_key_attrs,
661 "(msKds-UseStartTime<=%" PRIu64 ")",
662 not_after);
663 if (ret) {
664 goto out;
669 * Windows just gives up if there are more than 1000 root keys in the
670 * container.
674 struct root_key_candidate {
675 struct GUID id;
676 const struct ldb_message *key;
677 NTTIME create_time;
678 } most_recent_key = {
679 .key = NULL,
681 unsigned i;
683 for (i = 0; i < res->count; ++i) {
684 struct root_key_candidate key = {
685 .key = res->msgs[i],
687 const struct ldb_val *rdn_val = NULL;
688 bool ok;
690 key.create_time = samdb_result_nttime(
691 key.key, "msKds-CreateTime", 0);
692 if (key.create_time < most_recent_key.create_time) {
693 /* We already have a more recent key. */
694 continue;
697 rdn_val = ldb_dn_get_rdn_val(key.key->dn);
698 if (rdn_val == NULL) {
699 continue;
702 if (rdn_val->length != 36) {
704 * Check the RDN is the right length — 36 is the
705 * length of a UUID.
707 continue;
710 ok = parse_guid_string((const char *)rdn_val->data,
711 &key.id);
712 if (!ok) {
713 /* The RDN is not a correctly formatted GUID. */
714 continue;
718 * We’ve found a new candidate for the most recent root
719 * key.
721 most_recent_key = key;
724 if (most_recent_key.key == NULL) {
726 * We were not able to find a suitable root key, but
727 * there is a possibility that a key we create now will
728 * do: if gkdi_root_key_use_start_time(current_time) ≤
729 * not_after, then a newly‐created key will satisfy our
730 * caller’s requirements.
732 * Unfortunately, with gMSAs this (I believe) will never
733 * be the case. It’s too late to call
734 * gkdi_new_root_key() — the new key will be a bit *too*
735 * new to be usable for a gMSA.
738 ret = dsdb_werror(ldb,
739 LDB_ERR_NO_SUCH_OBJECT,
740 W_ERROR(HRES_ERROR_V(
741 HRES_NTE_NO_KEY)),
742 "failed to find a suitable root key");
743 goto out;
746 /* Return the root key that we found. */
747 *root_key_id_out = most_recent_key.id;
748 *root_key_out = talloc_steal(mem_ctx, most_recent_key.key);
751 out:
752 talloc_free(tmp_ctx);
753 return ret;