1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-05 09:18:06 +03:00
samba-mirror/source4/dsdb/gmsa/gkdi.c
Andreas Schneider c5a1c8d45b s4:dsdb: Fix stack use after scope in gkdi_create_root_key()
==20978==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7f4f91ff51a0 at pc 0x7f4f94cf93d6 bp 0x7ffdb90fc510 sp 0x7ffdb90fbcd0
READ of size 64 at 0x7f4f91ff51a0 thread T0
    #0 0x7f4f94cf93d5 in memcpy ../../../../libsanitizer/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc:115
    #1 0x7f4f933bdb67 in ldb_val_dup ../../lib/ldb/common/ldb_msg.c:325
    #2 0x7f4f933c11d1 in ldb_msg_copy ../../lib/ldb/common/ldb_msg.c:1182
    #3 0x7f4f933c13d2 in ldb_msg_normalize ../../lib/ldb/common/ldb_msg.c:1235
    #4 0x7f4f933ab556 in ldb_request ../../lib/ldb/common/ldb.c:1196
    #5 0x7f4f8e82b1d4 in dsdb_autotransaction_request ../../source4/dsdb/common/util.c:1220
    #6 0x7f4f8e831c8a in dsdb_add ../../source4/dsdb/common/util.c:5354
    #7 0x7f4f8e853a01 in gkdi_create_root_key ../../source4/dsdb/gmsa/gkdi.c:493
    #8 0x7f4f8e853a01 in gkdi_new_root_key ../../source4/dsdb/gmsa/gkdi.c:551
    #9 0x7f4f8cd4ca52 in py_dsdb_create_gkdi_root_key ../../source4/dsdb/pydsdb.c:1388
    #10 0x7f4f947ce01c  (/lib64/libpython3.11.so.1.0+0x1ce01c) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #11 0x7f4f947de4c0 in _PyObject_Call (/lib64/libpython3.11.so.1.0+0x1de4c0) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #12 0x7f4f947be6ca in _PyEval_EvalFrameDefault (/lib64/libpython3.11.so.1.0+0x1be6ca) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #13 0x7f4f947b6e79  (/lib64/libpython3.11.so.1.0+0x1b6e79) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #14 0x7f4f947de5d8  (/lib64/libpython3.11.so.1.0+0x1de5d8) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #15 0x7f4f947be6ca in _PyEval_EvalFrameDefault (/lib64/libpython3.11.so.1.0+0x1be6ca) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #16 0x7f4f947b6e79  (/lib64/libpython3.11.so.1.0+0x1b6e79) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #17 0x7f4f947edabb  (/lib64/libpython3.11.so.1.0+0x1edabb) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #18 0x7f4f947de5d8  (/lib64/libpython3.11.so.1.0+0x1de5d8) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #19 0x7f4f947be6ca in _PyEval_EvalFrameDefault (/lib64/libpython3.11.so.1.0+0x1be6ca) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #20 0x7f4f947b6e79  (/lib64/libpython3.11.so.1.0+0x1b6e79) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #21 0x7f4f947ed9fb  (/lib64/libpython3.11.so.1.0+0x1ed9fb) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #22 0x7f4f947be6ca in _PyEval_EvalFrameDefault (/lib64/libpython3.11.so.1.0+0x1be6ca) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #23 0x7f4f947b6e79  (/lib64/libpython3.11.so.1.0+0x1b6e79) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #24 0x7f4f947be6ca in _PyEval_EvalFrameDefault (/lib64/libpython3.11.so.1.0+0x1be6ca) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #25 0x7f4f947b6e79  (/lib64/libpython3.11.so.1.0+0x1b6e79) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #26 0x7f4f94839997 in PyEval_EvalCode (/lib64/libpython3.11.so.1.0+0x239997) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #27 0x7f4f94856862  (/lib64/libpython3.11.so.1.0+0x256862) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #28 0x7f4f94852e59  (/lib64/libpython3.11.so.1.0+0x252e59) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #29 0x7f4f94868fb1  (/lib64/libpython3.11.so.1.0+0x268fb1) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #30 0x7f4f948687a3 in _PyRun_SimpleFileObject (/lib64/libpython3.11.so.1.0+0x2687a3) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #31 0x7f4f94868453 in _PyRun_AnyFileObject (/lib64/libpython3.11.so.1.0+0x268453) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #32 0x7f4f94861c53 in Py_RunMain (/lib64/libpython3.11.so.1.0+0x261c53) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #33 0x7f4f94829996 in Py_BytesMain (/lib64/libpython3.11.so.1.0+0x229996) (BuildId: 170cbf941d17f6c2ac4f784129b31ebaa10c44a7)
    #34 0x7f4f9422a1ef in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #35 0x7f4f9422a2b8 in __libc_start_main_impl ../csu/libc-start.c:360
    #36 0x5604497e3084 in _start (/usr/bin/python3.11+0x1084) (BuildId: f5d6e3bdbf9098a6ddde0b7f2e07ffc9ad1b1dc3)

Address 0x7f4f91ff51a0 is located in stack of thread T0 at offset 416 in frame
    #0 0x7f4f8e852b37 in gkdi_new_root_key ../../source4/dsdb/gmsa/gkdi.c:537

  This frame has 12 object(s):
    [32, 40) 'root_key_dn' (line 539)
    [64, 72) 'res' (line 540)
    [96, 104) 'server_config_res' (line 118)
    [128, 136) 'kdf_algorithm' (line 128)
    [160, 168) 'domain_dn' (line 388)
    [192, 208) 'kdf_parameters_blob' (line 129)
    [224, 240) 'root_key_data_blob' (line 353)
    [256, 272) 'guid_blob' (line 467)
    [288, 312) 'kdf_parameters' (line 226)
    [352, 368) 'root_key_id' (line 116)
    [384, 400) 'guid_buf' (line 466)
    [416, 480) 'root_key_data' (line 352) <== Memory access at offset 416 is inside this variable

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Joseph Sutton <jsutton@samba.org>

Autobuild-User(master): Andreas Schneider <asn@cryptomilk.org>
Autobuild-Date(master): Fri May  3 12:20:55 UTC 2024 on atb-devel-224
2024-05-03 12:20:55 +00:00

755 lines
20 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Unix SMB/CIFS implementation.
Group Key Distribution Protocol functions
Copyright (C) Catalyst.Net Ltd 2024
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include <ldb.h>
#include <ldb_errors.h>
#include <ldb_module.h>
#include "lib/crypto/gkdi.h"
#include "lib/util/data_blob.h"
#include "lib/util/samba_util.h"
#include "lib/util/util_str_hex.h"
#include "librpc/ndr/libndr.h"
#include "dsdb/gmsa/gkdi.h"
#include "dsdb/samdb/ldb_modules/util.h"
#include "dsdb/samdb/samdb.h"
#include "dsdb/common/proto.h"
#include "librpc/gen_ndr/gkdi.h"
#include "librpc/gen_ndr/ndr_gkdi.h"
NTSTATUS gkdi_root_key_from_msg(TALLOC_CTX *mem_ctx,
const struct GUID root_key_id,
const struct ldb_message *const msg,
const struct ProvRootKey **const root_key_out)
{
NTSTATUS status = NT_STATUS_OK;
struct ldb_val root_key_data = {};
struct KdfAlgorithm kdf_algorithm = {};
const int version = ldb_msg_find_attr_as_int(msg, "msKds-Version", 0);
const NTTIME create_time = samdb_result_nttime(msg,
"msKds-CreateTime",
0);
const NTTIME use_start_time = samdb_result_nttime(msg,
"msKds-UseStartTime",
0);
const char *domain_id = ldb_msg_find_attr_as_string(msg,
"msKds-DomainID",
NULL);
{
const struct ldb_val *root_key_val = ldb_msg_find_ldb_val(
msg, "msKds-RootKeyData");
if (root_key_val != NULL) {
root_key_data = *root_key_val;
}
}
{
const char *algorithm_id = ldb_msg_find_attr_as_string(
msg, "msKds-KDFAlgorithmID", NULL);
const struct ldb_val *kdf_param_val = ldb_msg_find_ldb_val(
msg, "msKds-KDFParam");
status = kdf_algorithm_from_params(algorithm_id,
kdf_param_val,
&kdf_algorithm);
if (!NT_STATUS_IS_OK(status)) {
goto out;
}
}
status = ProvRootKey(mem_ctx,
root_key_id,
version,
root_key_data,
create_time,
use_start_time,
domain_id,
kdf_algorithm,
root_key_out);
if (!NT_STATUS_IS_OK(status)) {
goto out;
}
out:
return status;
}
/*
* Calculate an appropriate useStartTime for a root key created at
* current_time.
*
* This function goes unused.
*/
NTTIME gkdi_root_key_use_start_time(const NTTIME current_time)
{
const NTTIME start_time = gkdi_get_interval_start_time(current_time);
return start_time + gkdi_key_cycle_duration + gkdi_max_clock_skew;
}
static int gkdi_create_root_key(TALLOC_CTX *mem_ctx,
struct ldb_context *const ldb,
const NTTIME current_time,
const NTTIME use_start_time,
struct GUID *const root_key_id_out,
struct ldb_dn **const root_key_dn_out)
{
TALLOC_CTX *tmp_ctx = NULL;
struct GUID root_key_id;
struct ldb_dn *server_config_dn = NULL;
struct ldb_result *server_config_res = NULL;
struct ldb_message *server_config_msg = NULL;
uint64_t server_config_version;
const struct ldb_val *server_config_version_val = NULL;
const char *server_config_KDFAlgorithmID = NULL;
const struct ldb_val *server_config_KDFParam = NULL;
const char *server_config_SecretAgreementAlgorithmID = NULL;
const struct ldb_val *server_config_SecretAgreementParam = NULL;
uint64_t server_config_PublicKeyLength;
uint64_t server_config_PrivateKeyLength;
struct KdfAlgorithm kdf_algorithm;
DATA_BLOB kdf_parameters_blob = data_blob_null;
struct ldb_message *add_msg = NULL;
uint8_t root_key_data[GKDI_KEY_LEN];
NTSTATUS status = NT_STATUS_OK;
int ret = LDB_SUCCESS;
static const char *server_config_attrs[] = {
"msKds-Version",
"msKds-KDFAlgorithmID",
"msKds-SecretAgreementAlgorithmID",
"msKds-SecretAgreementParam",
"msKds-PublicKeyLength",
"msKds-PrivateKeyLength",
"msKds-KDFParam",
NULL
};
*root_key_dn_out = NULL;
tmp_ctx = talloc_new(mem_ctx);
if (tmp_ctx == NULL) {
ret = ldb_oom(ldb);
goto out;
}
server_config_dn = samdb_configuration_dn(ldb,
mem_ctx,
"CN=Group Key Distribution Service Server Configuration,"
"CN=Server Configuration,"
"CN=Group Key Distribution Service,"
"CN=Services");
if (server_config_dn == NULL) {
ret = ldb_oom(ldb);
goto out;
}
ret = dsdb_search_dn(ldb,
tmp_ctx,
&server_config_res,
server_config_dn,
server_config_attrs,
0);
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
ldb_asprintf_errstring(ldb, "Unable to create new GKDI root key as we do not have a GKDI server configuration at %s",
ldb_dn_get_linearized(server_config_dn));
goto out;
}
if (ret != LDB_SUCCESS) {
goto out;
}
server_config_msg = server_config_res->msgs[0];
server_config_version_val
= ldb_msg_find_ldb_val(server_config_msg,
"msKds-Version");
server_config_version
= ldb_msg_find_attr_as_uint64(server_config_msg,
"msKds-Version",
0);
/* These values we assert on, so we don't create keys we can't use */
if (server_config_version_val == NULL) {
/*
* The systemMustContain msKds-Version attribute
* cannot be read, so if absent we just fail with
* permission denied, as that is all that this can
* mean
*/
ldb_asprintf_errstring(ldb,
"Unwilling to create new GKDI root key as "
"msKds-Version is not readable on %s\n",
ldb_dn_get_linearized(server_config_dn));
ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
goto out;
} else if (server_config_version != 1) {
ldb_asprintf_errstring(ldb,
"Unwilling to create new GKDI root key as "
"%s has msKds-Version = %s "
"and we only support version 1\n",
ldb_dn_get_linearized(server_config_dn),
ldb_msg_find_attr_as_string(server_config_msg, "msKds-Version", "(missing)"));
ret = LDB_ERR_CONSTRAINT_VIOLATION;
goto out;
}
server_config_KDFAlgorithmID
= ldb_msg_find_attr_as_string(server_config_msg,
"msKds-KDFAlgorithmID",
SP800_108_CTR_HMAC
);
server_config_KDFParam
= ldb_msg_find_ldb_val(server_config_msg,
"msKds-KDFParam");
if (server_config_KDFParam == NULL) {
struct KdfParameters kdf_parameters = {
.hash_algorithm = "SHA512"
};
enum ndr_err_code err;
err = ndr_push_struct_blob(&kdf_parameters_blob,
tmp_ctx,
&kdf_parameters,
(ndr_push_flags_fn_t)
ndr_push_KdfParameters);
if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
status = ndr_map_error2ntstatus(err);
ldb_asprintf_errstring(ldb,
"KdfParameters pull failed: %s\n",
nt_errstr(status));
ret = LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
goto out;
}
server_config_KDFParam = &kdf_parameters_blob;
}
status = kdf_algorithm_from_params(server_config_KDFAlgorithmID,
server_config_KDFParam,
&kdf_algorithm);
if (!NT_STATUS_IS_OK(status)) {
ldb_asprintf_errstring(ldb,
"Unwilling to create new GKDI root key as "
"%s has an unsupported msKds-KDFAlgorithmID / msKds-KDFParam combination set: %s\n",
ldb_dn_get_linearized(server_config_dn),
nt_errstr(status));
ret = LDB_ERR_CONSTRAINT_VIOLATION;
goto out;
}
server_config_SecretAgreementAlgorithmID
= ldb_msg_find_attr_as_string(server_config_msg,
"msKds-SecretAgreementAlgorithmID",
"DH");
/* Optional in msKds-ProvRootKey */
server_config_SecretAgreementParam
= ldb_msg_find_ldb_val(server_config_msg,
"msKds-SecretAgreementParam");
if (server_config_SecretAgreementParam == NULL) {
static const uint8_t ffc_dh_parameters[] = {
12, 2, 0, 0, 68, 72, 80, 77, 0, 1, 0,
0, 135, 168, 230, 29, 180, 182, 102, 60, 255, 187,
209, 156, 101, 25, 89, 153, 140, 238, 246, 8, 102,
13, 208, 242, 93, 44, 238, 212, 67, 94, 59, 0,
224, 13, 248, 241, 214, 25, 87, 212, 250, 247, 223,
69, 97, 178, 170, 48, 22, 195, 217, 17, 52, 9,
111, 170, 59, 244, 41, 109, 131, 14, 154, 124, 32,
158, 12, 100, 151, 81, 122, 189, 90, 138, 157, 48,
107, 207, 103, 237, 145, 249, 230, 114, 91, 71, 88,
192, 34, 224, 177, 239, 66, 117, 191, 123, 108, 91,
252, 17, 212, 95, 144, 136, 185, 65, 245, 78, 177,
229, 155, 184, 188, 57, 160, 191, 18, 48, 127, 92,
79, 219, 112, 197, 129, 178, 63, 118, 182, 58, 202,
225, 202, 166, 183, 144, 45, 82, 82, 103, 53, 72,
138, 14, 241, 60, 109, 154, 81, 191, 164, 171, 58,
216, 52, 119, 150, 82, 77, 142, 246, 161, 103, 181,
164, 24, 37, 217, 103, 225, 68, 229, 20, 5, 100,
37, 28, 202, 203, 131, 230, 180, 134, 246, 179, 202,
63, 121, 113, 80, 96, 38, 192, 184, 87, 246, 137,
150, 40, 86, 222, 212, 1, 10, 189, 11, 230, 33,
195, 163, 150, 10, 84, 231, 16, 195, 117, 242, 99,
117, 215, 1, 65, 3, 164, 181, 67, 48, 193, 152,
175, 18, 97, 22, 210, 39, 110, 17, 113, 95, 105,
56, 119, 250, 215, 239, 9, 202, 219, 9, 74, 233,
30, 26, 21, 151, 63, 179, 44, 155, 115, 19, 77,
11, 46, 119, 80, 102, 96, 237, 189, 72, 76, 167,
177, 143, 33, 239, 32, 84, 7, 244, 121, 58, 26,
11, 161, 37, 16, 219, 193, 80, 119, 190, 70, 63,
255, 79, 237, 74, 172, 11, 181, 85, 190, 58, 108,
27, 12, 107, 71, 177, 188, 55, 115, 191, 126, 140,
111, 98, 144, 18, 40, 248, 194, 140, 187, 24, 165,
90, 227, 19, 65, 0, 10, 101, 1, 150, 249, 49,
199, 122, 87, 242, 221, 244, 99, 229, 233, 236, 20,
75, 119, 125, 230, 42, 170, 184, 168, 98, 138, 195,
118, 210, 130, 214, 237, 56, 100, 230, 121, 130, 66,
142, 188, 131, 29, 20, 52, 143, 111, 47, 145, 147,
181, 4, 90, 242, 118, 113, 100, 225, 223, 201, 103,
193, 251, 63, 46, 85, 164, 189, 27, 255, 232, 59,
156, 128, 208, 82, 185, 133, 209, 130, 234, 10, 219,
42, 59, 115, 19, 211, 254, 20, 200, 72, 75, 30,
5, 37, 136, 185, 183, 210, 187, 210, 223, 1, 97,
153, 236, 208, 110, 21, 87, 205, 9, 21, 179, 53,
59, 187, 100, 224, 236, 55, 127, 208, 40, 55, 13,
249, 43, 82, 199, 137, 20, 40, 205, 198, 126, 182,
24, 75, 82, 61, 29, 178, 70, 195, 47, 99, 7,
132, 144, 240, 14, 248, 214, 71, 209, 72, 212, 121,
84, 81, 94, 35, 39, 207, 239, 152, 197, 130, 102,
75, 76, 15, 108, 196, 22, 89};
static const DATA_BLOB ffc_dh_parameters_blob = {
discard_const_p(uint8_t, ffc_dh_parameters),
sizeof ffc_dh_parameters};
server_config_SecretAgreementParam = &ffc_dh_parameters_blob;
}
server_config_PublicKeyLength
= ldb_msg_find_attr_as_uint64(server_config_msg,
"msKds-PublicKeyLength",
2048);
server_config_PrivateKeyLength
= ldb_msg_find_attr_as_uint64(server_config_msg,
"msKds-PrivateKeyLength",
256);
add_msg = ldb_msg_new(tmp_ctx);
if (add_msg == NULL) {
ret = ldb_oom(ldb);
goto out;
}
ret = ldb_msg_append_string(add_msg,
"objectClass",
"msKds-ProvRootKey",
LDB_FLAG_MOD_ADD);
if (ret) {
goto out;
}
{
const DATA_BLOB root_key_data_blob = {
.data = root_key_data, .length = sizeof root_key_data};
generate_secret_buffer(root_key_data, sizeof root_key_data);
ret = ldb_msg_append_value(add_msg,
"msKds-RootKeyData",
&root_key_data_blob,
LDB_FLAG_MOD_ADD);
if (ret) {
goto out;
}
}
ret = samdb_msg_append_uint64(ldb,
tmp_ctx,
add_msg,
"msKds-CreateTime",
current_time,
LDB_FLAG_MOD_ADD);
if (ret) {
goto out;
}
ret = samdb_msg_append_uint64(ldb,
tmp_ctx,
add_msg,
"msKds-UseStartTime",
use_start_time,
LDB_FLAG_MOD_ADD);
if (ret) {
goto out;
}
{
struct ldb_dn *domain_dn = NULL;
ret = samdb_server_reference_dn(ldb, tmp_ctx, &domain_dn);
if (ret) {
goto out;
}
ret = ldb_msg_append_linearized_dn(add_msg,
"msKds-DomainID",
domain_dn,
LDB_FLAG_MOD_ADD);
if (ret) {
goto out;
}
}
ret = samdb_msg_append_uint64(ldb,
tmp_ctx,
add_msg,
"msKds-Version",
server_config_version,
LDB_FLAG_MOD_ADD);
if (ret) {
goto out;
}
ret = ldb_msg_append_string(add_msg,
"msKds-KDFAlgorithmID",
server_config_KDFAlgorithmID,
LDB_FLAG_MOD_ADD);
if (ret) {
goto out;
}
ret = ldb_msg_append_string(add_msg,
"msKds-SecretAgreementAlgorithmID",
server_config_SecretAgreementAlgorithmID,
LDB_FLAG_MOD_ADD);
if (ret) {
goto out;
}
if (server_config_SecretAgreementParam != NULL) {
ret = ldb_msg_append_value(add_msg,
"msKds-SecretAgreementParam",
server_config_SecretAgreementParam,
LDB_FLAG_MOD_ADD);
if (ret) {
goto out;
}
}
ret = samdb_msg_append_uint64(ldb,
tmp_ctx,
add_msg,
"msKds-PublicKeyLength",
server_config_PublicKeyLength,
LDB_FLAG_MOD_ADD);
if (ret) {
goto out;
}
ret = samdb_msg_append_uint64(ldb,
tmp_ctx,
add_msg,
"msKds-PrivateKeyLength",
server_config_PrivateKeyLength,
LDB_FLAG_MOD_ADD);
ret = ldb_msg_append_value(add_msg,
"msKds-KDFParam",
server_config_KDFParam,
LDB_FLAG_MOD_ADD);
if (ret) {
goto out;
}
{
uint8_t guid_buf[sizeof((struct GUID_ndr_buf){}.buf)];
const DATA_BLOB guid_blob = {.data = guid_buf,
.length = sizeof guid_buf};
generate_secret_buffer(guid_buf, sizeof guid_buf);
status = GUID_from_ndr_blob(&guid_blob, &root_key_id);
if (!NT_STATUS_IS_OK(status)) {
ret = ldb_operr(ldb);
goto out;
}
}
{
struct ldb_dn *root_key_dn = NULL;
root_key_dn = samdb_gkdi_root_key_dn(ldb,
tmp_ctx,
&root_key_id);
if (root_key_dn == NULL) {
ret = ldb_operr(ldb);
goto out;
}
add_msg->dn = root_key_dn;
}
ret = dsdb_add(ldb, add_msg, 0);
if (ret) {
goto out;
}
*root_key_id_out = root_key_id;
*root_key_dn_out = talloc_steal(mem_ctx, add_msg->dn);
out:
talloc_free(tmp_ctx);
return ret;
}
/*
* The PrivateKey, PublicKey, and SecretAgreement attributes are related to the
* publickey functionality in GKDI. Samba doesnt try to implement any of that,
* so we dont bother looking at these attributes.
*/
static const char *const root_key_attrs[] = {
"msKds-CreateTime",
"msKds-DomainID",
"msKds-KDFAlgorithmID",
"msKds-KDFParam",
/* "msKds-PrivateKeyLength", */
/* "msKds-PublicKeyLength", */
"msKds-RootKeyData",
/* "msKds-SecretAgreementAlgorithmID", */
/* "msKds-SecretAgreementParam", */
"msKds-UseStartTime",
"msKds-Version",
NULL,
};
/*
* Create and return a new GKDI root key.
*
* This function goes unused.
*/
int gkdi_new_root_key(TALLOC_CTX *mem_ctx,
struct ldb_context *const ldb,
const NTTIME current_time,
const NTTIME use_start_time,
struct GUID *const root_key_id_out,
const struct ldb_message **const root_key_out)
{
TALLOC_CTX *tmp_ctx = NULL;
struct ldb_dn *root_key_dn = NULL;
struct ldb_result *res = NULL;
int ret = LDB_SUCCESS;
*root_key_out = NULL;
tmp_ctx = talloc_new(mem_ctx);
if (tmp_ctx == NULL) {
ret = ldb_oom(ldb);
goto out;
}
ret = gkdi_create_root_key(tmp_ctx,
ldb,
current_time,
use_start_time,
root_key_id_out,
&root_key_dn);
if (ret) {
goto out;
}
ret = dsdb_search_dn(
ldb, tmp_ctx, &res, root_key_dn, root_key_attrs, 0);
if (ret) {
goto out;
}
if (res->count != 1) {
ret = LDB_ERR_NO_SUCH_OBJECT;
goto out;
}
*root_key_out = talloc_steal(mem_ctx, res->msgs[0]);
out:
talloc_free(tmp_ctx);
return ret;
}
int gkdi_root_key_from_id(TALLOC_CTX *mem_ctx,
struct ldb_context *const ldb,
const struct GUID *const root_key_id,
const struct ldb_message **const root_key_out)
{
TALLOC_CTX *tmp_ctx = NULL;
struct ldb_dn *root_key_dn = NULL;
struct ldb_result *res = NULL;
int ret = LDB_SUCCESS;
*root_key_out = NULL;
tmp_ctx = talloc_new(mem_ctx);
if (tmp_ctx == NULL) {
ret = ldb_oom(ldb);
goto out;
}
root_key_dn = samdb_gkdi_root_key_dn(ldb, tmp_ctx, root_key_id);
if (root_key_dn == NULL) {
ret = ldb_operr(ldb);
goto out;
}
ret = dsdb_search_dn(
ldb, tmp_ctx, &res, root_key_dn, root_key_attrs, 0);
if (ret) {
goto out;
}
if (res->count != 1) {
ret = dsdb_werror(ldb,
LDB_ERR_NO_SUCH_OBJECT,
W_ERROR(HRES_ERROR_V(HRES_NTE_NO_KEY)),
"failed to find root key");
goto out;
}
*root_key_out = talloc_steal(mem_ctx, res->msgs[0]);
out:
talloc_free(tmp_ctx);
return ret;
}
int gkdi_most_recently_created_root_key(
TALLOC_CTX *mem_ctx,
struct ldb_context *const ldb,
_UNUSED_ const NTTIME current_time,
const NTTIME not_after,
struct GUID *const root_key_id_out,
const struct ldb_message **const root_key_out)
{
TALLOC_CTX *tmp_ctx = NULL;
struct ldb_result *res = NULL;
int ret = LDB_SUCCESS;
*root_key_out = NULL;
tmp_ctx = talloc_new(mem_ctx);
if (tmp_ctx == NULL) {
ret = ldb_oom(ldb);
goto out;
}
{
struct ldb_dn *root_key_container_dn = NULL;
root_key_container_dn = samdb_gkdi_root_key_container_dn(
ldb, tmp_ctx);
if (root_key_container_dn == NULL) {
ret = ldb_operr(ldb);
goto out;
}
ret = dsdb_search(ldb,
tmp_ctx,
&res,
root_key_container_dn,
LDB_SCOPE_ONELEVEL,
root_key_attrs,
0,
"(msKds-UseStartTime<=%" PRIu64 ")",
not_after);
if (ret) {
goto out;
}
}
/*
* Windows just gives up if there are more than 1000 root keys in the
* container.
*/
{
struct root_key_candidate {
struct GUID id;
const struct ldb_message *key;
NTTIME create_time;
} most_recent_key = {
.key = NULL,
};
unsigned i;
for (i = 0; i < res->count; ++i) {
struct root_key_candidate key = {
.key = res->msgs[i],
};
const struct ldb_val *rdn_val = NULL;
bool ok;
key.create_time = samdb_result_nttime(
key.key, "msKds-CreateTime", 0);
if (key.create_time < most_recent_key.create_time) {
/* We already have a more recent key. */
continue;
}
rdn_val = ldb_dn_get_rdn_val(key.key->dn);
if (rdn_val == NULL) {
continue;
}
if (rdn_val->length != 36) {
/*
* Check the RDN is the right length — 36 is the
* length of a UUID.
*/
continue;
}
ok = parse_guid_string((const char *)rdn_val->data,
&key.id);
if (!ok) {
/* The RDN is not a correctly formatted GUID. */
continue;
}
/*
* Weve found a new candidate for the most recent root
* key.
*/
most_recent_key = key;
}
if (most_recent_key.key == NULL) {
/*
* We were not able to find a suitable root key, but
* there is a possibility that a key we create now will
* do: if gkdi_root_key_use_start_time(current_time) ≤
* not_after, then a newlycreated key will satisfy our
* callers requirements.
*
* Unfortunately, with gMSAs this (I believe) will never
* be the case. Its too late to call
* gkdi_new_root_key() — the new key will be a bit *too*
* new to be usable for a gMSA.
*/
ret = dsdb_werror(ldb,
LDB_ERR_NO_SUCH_OBJECT,
W_ERROR(HRES_ERROR_V(
HRES_NTE_NO_KEY)),
"failed to find a suitable root key");
goto out;
}
/* Return the root key that we found. */
*root_key_id_out = most_recent_key.id;
*root_key_out = talloc_steal(mem_ctx, most_recent_key.key);
}
out:
talloc_free(tmp_ctx);
return ret;
}