LCOV - code coverage report
Current view: top level - source4/dsdb/gmsa - gkdi.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 202 262 77.1 %
Date: 2024-04-21 15:09:00 Functions: 5 6 83.3 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Group Key Distribution Protocol functions
       4             : 
       5             :    Copyright (C) Catalyst.Net Ltd 2024
       6             : 
       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.
      11             : 
      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.
      16             : 
      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/>.
      19             : */
      20             : 
      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"
      36             : 
      37         101 : 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)
      41             : {
      42         101 :         NTSTATUS status = NT_STATUS_OK;
      43         101 :         struct ldb_val root_key_data = {};
      44         101 :         struct KdfAlgorithm kdf_algorithm = {};
      45             : 
      46         101 :         const int version = ldb_msg_find_attr_as_int(msg, "msKds-Version", 0);
      47         101 :         const NTTIME create_time = samdb_result_nttime(msg,
      48             :                                                        "msKds-CreateTime",
      49             :                                                        0);
      50         101 :         const NTTIME use_start_time = samdb_result_nttime(msg,
      51             :                                                           "msKds-UseStartTime",
      52             :                                                           0);
      53         101 :         const char *domain_id = ldb_msg_find_attr_as_string(msg,
      54             :                                                             "msKds-DomainID",
      55             :                                                             NULL);
      56             : 
      57             :         {
      58         101 :                 const struct ldb_val *root_key_val = ldb_msg_find_ldb_val(
      59             :                         msg, "msKds-RootKeyData");
      60         101 :                 if (root_key_val != NULL) {
      61         101 :                         root_key_data = *root_key_val;
      62             :                 }
      63             :         }
      64             : 
      65             :         {
      66         101 :                 const char *algorithm_id = ldb_msg_find_attr_as_string(
      67             :                         msg, "msKds-KDFAlgorithmID", NULL);
      68         101 :                 const struct ldb_val *kdf_param_val = ldb_msg_find_ldb_val(
      69             :                         msg, "msKds-KDFParam");
      70         101 :                 status = kdf_algorithm_from_params(algorithm_id,
      71             :                                                    kdf_param_val,
      72             :                                                    &kdf_algorithm);
      73         101 :                 if (!NT_STATUS_IS_OK(status)) {
      74           0 :                         goto out;
      75             :                 }
      76             :         }
      77             : 
      78         101 :         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         101 :         if (!NT_STATUS_IS_OK(status)) {
      88           0 :                 goto out;
      89             :         }
      90             : 
      91         101 : out:
      92         101 :         return status;
      93             : }
      94             : 
      95             : /*
      96             :  * Calculate an appropriate useStartTime for a root key created at
      97             :  * ‘current_time’.
      98             :  *
      99             :  * This function goes unused.
     100             :  */
     101           0 : NTTIME gkdi_root_key_use_start_time(const NTTIME current_time)
     102             : {
     103           0 :         const NTTIME start_time = gkdi_get_interval_start_time(current_time);
     104             : 
     105           0 :         return start_time + gkdi_key_cycle_duration + gkdi_max_clock_skew;
     106             : }
     107             : 
     108         100 : 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)
     114             : {
     115         100 :         TALLOC_CTX *tmp_ctx = NULL;
     116          22 :         struct GUID root_key_id;
     117         100 :         struct ldb_dn *server_config_dn = NULL;
     118         100 :         struct ldb_result *server_config_res = NULL;
     119         100 :         struct ldb_message *server_config_msg = NULL;
     120          22 :         uint64_t server_config_version;
     121         100 :         const struct ldb_val *server_config_version_val = NULL;
     122         100 :         const char *server_config_KDFAlgorithmID = NULL;
     123         100 :         const struct ldb_val *server_config_KDFParam = NULL;
     124         100 :         const char *server_config_SecretAgreementAlgorithmID = NULL;
     125         100 :         const struct ldb_val *server_config_SecretAgreementParam = NULL;
     126          22 :         uint64_t server_config_PublicKeyLength;
     127          22 :         uint64_t server_config_PrivateKeyLength;
     128          22 :         struct KdfAlgorithm kdf_algorithm;
     129         100 :         DATA_BLOB kdf_parameters_blob = data_blob_null;
     130         100 :         struct ldb_message *add_msg = NULL;
     131         100 :         NTSTATUS status = NT_STATUS_OK;
     132         100 :         int ret = LDB_SUCCESS;
     133             : 
     134          22 :         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
     143             :         };
     144             : 
     145         100 :         *root_key_dn_out = NULL;
     146             : 
     147         100 :         tmp_ctx = talloc_new(mem_ctx);
     148         100 :         if (tmp_ctx == NULL) {
     149           0 :                 ret = ldb_oom(ldb);
     150           0 :                 goto out;
     151             :         }
     152             : 
     153         100 :         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         100 :         if (server_config_dn == NULL) {
     160           0 :                 ret = ldb_oom(ldb);
     161           0 :                 goto out;
     162             :         }
     163             : 
     164         100 :         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);
     170             : 
     171         100 :         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
     172           0 :                 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           0 :                 goto out;
     175             :         }
     176             : 
     177         100 :         if (ret != LDB_SUCCESS) {
     178           0 :                 goto out;
     179             :         }
     180             : 
     181         100 :         server_config_msg = server_config_res->msgs[0];
     182             : 
     183          22 :         server_config_version_val
     184         100 :                 = ldb_msg_find_ldb_val(server_config_msg,
     185             :                                        "msKds-Version");
     186          22 :         server_config_version
     187         100 :                 = ldb_msg_find_attr_as_uint64(server_config_msg,
     188             :                                               "msKds-Version",
     189             :                                               0);
     190             : 
     191             :         /* These values we assert on, so we don't create keys we can't use */
     192         100 :         if (server_config_version_val == NULL) {
     193             :                 /*
     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
     198             :                  */
     199           1 :                 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           1 :                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
     204           1 :                 goto out;
     205          99 :         } else if (server_config_version != 1) {
     206           1 :                 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           1 :                 ret = LDB_ERR_CONSTRAINT_VIOLATION;
     213           1 :                 goto out;
     214             :         }
     215             : 
     216          22 :         server_config_KDFAlgorithmID
     217          98 :                 = ldb_msg_find_attr_as_string(server_config_msg,
     218             :                                               "msKds-KDFAlgorithmID",
     219             :                                               SP800_108_CTR_HMAC
     220             :                                               );
     221             : 
     222          22 :         server_config_KDFParam
     223          98 :                 = ldb_msg_find_ldb_val(server_config_msg,
     224             :                                        "msKds-KDFParam");
     225          98 :         if (server_config_KDFParam == NULL) {
     226          98 :                 struct KdfParameters kdf_parameters = {
     227             :                         .hash_algorithm = "SHA512"
     228             :                 };
     229          22 :                 enum ndr_err_code err;
     230             : 
     231          98 :                 err = ndr_push_struct_blob(&kdf_parameters_blob,
     232             :                                            tmp_ctx,
     233             :                                            &kdf_parameters,
     234             :                                            (ndr_push_flags_fn_t)
     235             :                                            ndr_push_KdfParameters);
     236             : 
     237          98 :                 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
     238           0 :                         status = ndr_map_error2ntstatus(err);
     239           0 :                         ldb_asprintf_errstring(ldb,
     240             :                                                "KdfParameters pull failed: %s\n",
     241             :                                                nt_errstr(status));
     242           0 :                         ret = LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
     243           0 :                         goto out;
     244             :                 }
     245             : 
     246          98 :                 server_config_KDFParam = &kdf_parameters_blob;
     247             :         }
     248             : 
     249          98 :         status = kdf_algorithm_from_params(server_config_KDFAlgorithmID,
     250             :                                            server_config_KDFParam,
     251             :                                            &kdf_algorithm);
     252          98 :         if (!NT_STATUS_IS_OK(status)) {
     253           1 :                 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           1 :                 ret = LDB_ERR_CONSTRAINT_VIOLATION;
     259           1 :                 goto out;
     260             :         }
     261             : 
     262          22 :         server_config_SecretAgreementAlgorithmID
     263          97 :                 = ldb_msg_find_attr_as_string(server_config_msg,
     264             :                                               "msKds-SecretAgreementAlgorithmID",
     265             :                                               "DH");
     266             : 
     267             :         /* Optional in msKds-ProvRootKey */
     268          22 :         server_config_SecretAgreementParam
     269          97 :                 = ldb_msg_find_ldb_val(server_config_msg,
     270             :                                        "msKds-SecretAgreementParam");
     271          97 :         if (server_config_SecretAgreementParam == NULL) {
     272          22 :                 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          22 :                 static const DATA_BLOB ffc_dh_parameters_blob = {
     322             :                         discard_const_p(uint8_t, ffc_dh_parameters),
     323             :                         sizeof ffc_dh_parameters};
     324          97 :                 server_config_SecretAgreementParam = &ffc_dh_parameters_blob;
     325             :         }
     326             : 
     327          22 :         server_config_PublicKeyLength
     328          97 :                 = ldb_msg_find_attr_as_uint64(server_config_msg,
     329             :                                               "msKds-PublicKeyLength",
     330             :                                               2048);
     331             : 
     332          22 :         server_config_PrivateKeyLength
     333          97 :                 = ldb_msg_find_attr_as_uint64(server_config_msg,
     334             :                                               "msKds-PrivateKeyLength",
     335             :                                               256);
     336             : 
     337          97 :         add_msg = ldb_msg_new(tmp_ctx);
     338          97 :         if (add_msg == NULL) {
     339           0 :                 ret = ldb_oom(ldb);
     340           0 :                 goto out;
     341             :         }
     342             : 
     343          97 :         ret = ldb_msg_append_string(add_msg,
     344             :                                     "objectClass",
     345             :                                     "msKds-ProvRootKey",
     346             :                                     LDB_FLAG_MOD_ADD);
     347          97 :         if (ret) {
     348           0 :                 goto out;
     349             :         }
     350             : 
     351             :         {
     352          22 :                 uint8_t root_key_data[GKDI_KEY_LEN];
     353          97 :                 const DATA_BLOB root_key_data_blob = {
     354             :                         .data = root_key_data, .length = sizeof root_key_data};
     355             : 
     356          97 :                 generate_secret_buffer(root_key_data, sizeof root_key_data);
     357             : 
     358          97 :                 ret = ldb_msg_append_value(add_msg,
     359             :                                            "msKds-RootKeyData",
     360             :                                            &root_key_data_blob,
     361             :                                            LDB_FLAG_MOD_ADD);
     362          97 :                 if (ret) {
     363           0 :                         goto out;
     364             :                 }
     365             :         }
     366             : 
     367          97 :         ret = samdb_msg_append_uint64(ldb,
     368             :                                       tmp_ctx,
     369             :                                       add_msg,
     370             :                                       "msKds-CreateTime",
     371             :                                       current_time,
     372             :                                       LDB_FLAG_MOD_ADD);
     373          97 :         if (ret) {
     374           0 :                 goto out;
     375             :         }
     376             : 
     377          97 :         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          97 :         if (ret) {
     384           0 :                 goto out;
     385             :         }
     386             : 
     387             :         {
     388          97 :                 struct ldb_dn *domain_dn = NULL;
     389             : 
     390          97 :                 ret = samdb_server_reference_dn(ldb, tmp_ctx, &domain_dn);
     391          97 :                 if (ret) {
     392           0 :                         goto out;
     393             :                 }
     394             : 
     395          97 :                 ret = ldb_msg_append_linearized_dn(add_msg,
     396             :                                                    "msKds-DomainID",
     397             :                                                    domain_dn,
     398             :                                                    LDB_FLAG_MOD_ADD);
     399          97 :                 if (ret) {
     400           0 :                         goto out;
     401             :                 }
     402             :         }
     403             : 
     404          97 :         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          97 :         if (ret) {
     411           0 :                 goto out;
     412             :         }
     413             : 
     414          97 :         ret = ldb_msg_append_string(add_msg,
     415             :                                     "msKds-KDFAlgorithmID",
     416             :                                     server_config_KDFAlgorithmID,
     417             :                                     LDB_FLAG_MOD_ADD);
     418          97 :         if (ret) {
     419           0 :                 goto out;
     420             :         }
     421             : 
     422          97 :         ret = ldb_msg_append_string(add_msg,
     423             :                                    "msKds-SecretAgreementAlgorithmID",
     424             :                                    server_config_SecretAgreementAlgorithmID,
     425             :                                    LDB_FLAG_MOD_ADD);
     426          97 :         if (ret) {
     427           0 :                 goto out;
     428             :         }
     429             : 
     430          97 :         if (server_config_SecretAgreementParam != NULL) {
     431          97 :                 ret = ldb_msg_append_value(add_msg,
     432             :                                            "msKds-SecretAgreementParam",
     433             :                                            server_config_SecretAgreementParam,
     434             :                                            LDB_FLAG_MOD_ADD);
     435          97 :                 if (ret) {
     436           0 :                         goto out;
     437             :                 }
     438             :         }
     439             : 
     440          97 :         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          97 :         if (ret) {
     447           0 :                 goto out;
     448             :         }
     449             : 
     450          97 :         ret = samdb_msg_append_uint64(ldb,
     451             :                                       tmp_ctx,
     452             :                                       add_msg,
     453             :                                       "msKds-PrivateKeyLength",
     454             :                                       server_config_PrivateKeyLength,
     455             :                                       LDB_FLAG_MOD_ADD);
     456             : 
     457          97 :         ret = ldb_msg_append_value(add_msg,
     458             :                                    "msKds-KDFParam",
     459             :                                    server_config_KDFParam,
     460             :                                    LDB_FLAG_MOD_ADD);
     461          97 :         if (ret) {
     462           0 :                 goto out;
     463             :         }
     464             : 
     465             :         {
     466          22 :                 uint8_t guid_buf[sizeof((struct GUID_ndr_buf){}.buf)];
     467          97 :                 const DATA_BLOB guid_blob = {.data = guid_buf,
     468             :                                              .length = sizeof guid_buf};
     469             : 
     470          97 :                 generate_secret_buffer(guid_buf, sizeof guid_buf);
     471             : 
     472          97 :                 status = GUID_from_ndr_blob(&guid_blob, &root_key_id);
     473          97 :                 if (!NT_STATUS_IS_OK(status)) {
     474           0 :                         ret = ldb_operr(ldb);
     475           0 :                         goto out;
     476             :                 }
     477             :         }
     478             : 
     479             :         {
     480          97 :                 struct ldb_dn *root_key_dn = NULL;
     481             : 
     482          97 :                 root_key_dn = samdb_gkdi_root_key_dn(ldb,
     483             :                                                      tmp_ctx,
     484             :                                                      &root_key_id);
     485          97 :                 if (root_key_dn == NULL) {
     486           0 :                         ret = ldb_operr(ldb);
     487           0 :                         goto out;
     488             :                 }
     489             : 
     490          97 :                 add_msg->dn = root_key_dn;
     491             :         }
     492             : 
     493          97 :         ret = dsdb_add(ldb, add_msg, 0);
     494          97 :         if (ret) {
     495           0 :                 goto out;
     496             :         }
     497             : 
     498          97 :         *root_key_id_out = root_key_id;
     499          97 :         *root_key_dn_out = talloc_steal(mem_ctx, add_msg->dn);
     500             : 
     501         100 : out:
     502         100 :         talloc_free(tmp_ctx);
     503         100 :         return ret;
     504             : }
     505             : 
     506             : /*
     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.
     510             :  */
     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,
     524             : };
     525             : 
     526             : /*
     527             :  * Create and return a new GKDI root key.
     528             :  *
     529             :  * This function goes unused.
     530             :  */
     531         100 : 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)
     537             : {
     538         100 :         TALLOC_CTX *tmp_ctx = NULL;
     539         100 :         struct ldb_dn *root_key_dn = NULL;
     540         100 :         struct ldb_result *res = NULL;
     541         100 :         int ret = LDB_SUCCESS;
     542             : 
     543         100 :         *root_key_out = NULL;
     544             : 
     545         100 :         tmp_ctx = talloc_new(mem_ctx);
     546         100 :         if (tmp_ctx == NULL) {
     547           0 :                 ret = ldb_oom(ldb);
     548           0 :                 goto out;
     549             :         }
     550             : 
     551         100 :         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         100 :         if (ret) {
     558           3 :                 goto out;
     559             :         }
     560             : 
     561          97 :         ret = dsdb_search_dn(
     562             :                 ldb, tmp_ctx, &res, root_key_dn, root_key_attrs, 0);
     563          97 :         if (ret) {
     564           0 :                 goto out;
     565             :         }
     566             : 
     567          97 :         if (res->count != 1) {
     568           0 :                 ret = LDB_ERR_NO_SUCH_OBJECT;
     569           0 :                 goto out;
     570             :         }
     571             : 
     572          97 :         *root_key_out = talloc_steal(mem_ctx, res->msgs[0]);
     573             : 
     574         100 : out:
     575         100 :         talloc_free(tmp_ctx);
     576         100 :         return ret;
     577             : }
     578             : 
     579          27 : 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)
     583             : {
     584          27 :         TALLOC_CTX *tmp_ctx = NULL;
     585          27 :         struct ldb_dn *root_key_dn = NULL;
     586          27 :         struct ldb_result *res = NULL;
     587          27 :         int ret = LDB_SUCCESS;
     588             : 
     589          27 :         *root_key_out = NULL;
     590             : 
     591          27 :         tmp_ctx = talloc_new(mem_ctx);
     592          27 :         if (tmp_ctx == NULL) {
     593           0 :                 ret = ldb_oom(ldb);
     594           0 :                 goto out;
     595             :         }
     596             : 
     597          27 :         root_key_dn = samdb_gkdi_root_key_dn(ldb, tmp_ctx, root_key_id);
     598          27 :         if (root_key_dn == NULL) {
     599           0 :                 ret = ldb_operr(ldb);
     600           0 :                 goto out;
     601             :         }
     602             : 
     603          27 :         ret = dsdb_search_dn(
     604             :                 ldb, tmp_ctx, &res, root_key_dn, root_key_attrs, 0);
     605          27 :         if (ret) {
     606           0 :                 goto out;
     607             :         }
     608             : 
     609          27 :         if (res->count != 1) {
     610           0 :                 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           0 :                 goto out;
     615             :         }
     616             : 
     617          27 :         *root_key_out = talloc_steal(mem_ctx, res->msgs[0]);
     618             : 
     619          27 : out:
     620          27 :         talloc_free(tmp_ctx);
     621          27 :         return ret;
     622             : }
     623             : 
     624          74 : 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)
     631             : {
     632          74 :         TALLOC_CTX *tmp_ctx = NULL;
     633          74 :         struct ldb_result *res = NULL;
     634          74 :         int ret = LDB_SUCCESS;
     635             : 
     636          74 :         *root_key_out = NULL;
     637             : 
     638          74 :         tmp_ctx = talloc_new(mem_ctx);
     639          74 :         if (tmp_ctx == NULL) {
     640           0 :                 ret = ldb_oom(ldb);
     641           0 :                 goto out;
     642             :         }
     643             : 
     644             :         {
     645          74 :                 struct ldb_dn *root_key_container_dn = NULL;
     646             : 
     647          74 :                 root_key_container_dn = samdb_gkdi_root_key_container_dn(
     648             :                         ldb, tmp_ctx);
     649          74 :                 if (root_key_container_dn == NULL) {
     650           0 :                         ret = ldb_operr(ldb);
     651           0 :                         goto out;
     652             :                 }
     653             : 
     654          74 :                 ret = dsdb_search(ldb,
     655             :                                   tmp_ctx,
     656             :                                   &res,
     657             :                                   root_key_container_dn,
     658             :                                   LDB_SCOPE_ONELEVEL,
     659             :                                   root_key_attrs,
     660             :                                   0,
     661             :                                   "(msKds-UseStartTime<=%" PRIu64 ")",
     662             :                                   not_after);
     663          74 :                 if (ret) {
     664           0 :                         goto out;
     665             :                 }
     666             :         }
     667             : 
     668             :         /*
     669             :          * Windows just gives up if there are more than 1000 root keys in the
     670             :          * container.
     671             :          */
     672             : 
     673             :         {
     674           0 :                 struct root_key_candidate {
     675             :                         struct GUID id;
     676             :                         const struct ldb_message *key;
     677             :                         NTTIME create_time;
     678          74 :                 } most_recent_key = {
     679             :                         .key = NULL,
     680             :                 };
     681           0 :                 unsigned i;
     682             : 
     683         680 :                 for (i = 0; i < res->count; ++i) {
     684         606 :                         struct root_key_candidate key = {
     685         606 :                                 .key = res->msgs[i],
     686             :                         };
     687         606 :                         const struct ldb_val *rdn_val = NULL;
     688           0 :                         bool ok;
     689             : 
     690         606 :                         key.create_time = samdb_result_nttime(
     691             :                                 key.key, "msKds-CreateTime", 0);
     692         606 :                         if (key.create_time < most_recent_key.create_time) {
     693             :                                 /* We already have a more recent key. */
     694         368 :                                 continue;
     695             :                         }
     696             : 
     697         238 :                         rdn_val = ldb_dn_get_rdn_val(key.key->dn);
     698         238 :                         if (rdn_val == NULL) {
     699           0 :                                 continue;
     700             :                         }
     701             : 
     702         238 :                         if (rdn_val->length != 36) {
     703             :                                 /*
     704             :                                  * Check the RDN is the right length — 36 is the
     705             :                                  * length of a UUID.
     706             :                                  */
     707           0 :                                 continue;
     708             :                         }
     709             : 
     710         238 :                         ok = parse_guid_string((const char *)rdn_val->data,
     711             :                                                &key.id);
     712         238 :                         if (!ok) {
     713             :                                 /* The RDN is not a correctly formatted GUID. */
     714           0 :                                 continue;
     715             :                         }
     716             : 
     717             :                         /*
     718             :                          * We’ve found a new candidate for the most recent root
     719             :                          * key.
     720             :                          */
     721         238 :                         most_recent_key = key;
     722             :                 }
     723             : 
     724          74 :                 if (most_recent_key.key == NULL) {
     725             :                         /*
     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.
     731             :                          *
     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.
     736             :                          */
     737             : 
     738           0 :                         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           0 :                         goto out;
     744             :                 }
     745             : 
     746             :                 /* Return the root key that we found. */
     747          74 :                 *root_key_id_out = most_recent_key.id;
     748          74 :                 *root_key_out = talloc_steal(mem_ctx, most_recent_key.key);
     749             :         }
     750             : 
     751          74 : out:
     752          74 :         talloc_free(tmp_ctx);
     753          74 :         return ret;
     754             : }

Generated by: LCOV version 1.14