LCOV - code coverage report
Current view: top level - source4/dsdb/common - rodc_helper.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 73 104 70.2 %
Date: 2024-04-13 12:30:31 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    common sid helper functions
       5             : 
       6             :    Copyright (C) Catalyst.NET Ltd 2017
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "rpc_server/dcerpc_server.h"
      24             : #include "librpc/gen_ndr/ndr_security.h"
      25             : #include "source4/dsdb/samdb/samdb.h"
      26             : #include "libcli/security/security.h"
      27             : 
      28             : /*
      29             :   see if any SIDs in list1 are in list2
      30             :  */
      31        2063 : static bool sid_list_match(uint32_t num_sids1,
      32             :                            const struct dom_sid *list1,
      33             :                            uint32_t num_sids2,
      34             :                            const struct dom_sid *list2)
      35             : {
      36           0 :         unsigned int i, j;
      37             :         /* do we ever have enough SIDs here to worry about O(n^2) ? */
      38        6855 :         for (i=0; i < num_sids1; i++) {
      39       29148 :                 for (j=0; j < num_sids2; j++) {
      40       24356 :                         if (dom_sid_equal(&list1[i], &list2[j])) {
      41        1092 :                                 return true;
      42             :                         }
      43             :                 }
      44             :         }
      45         971 :         return false;
      46             : }
      47             : 
      48             : /*
      49             :  * Return an array of SIDs from a ldb_message given an attribute name assumes
      50             :  * the SIDs are in NDR form (with primary_sid applied on the start).
      51             :  */
      52        1348 : static WERROR samdb_result_sid_array_ndr(struct ldb_context *sam_ctx,
      53             :                                          struct ldb_message *msg,
      54             :                                          TALLOC_CTX *mem_ctx,
      55             :                                          const char *attr,
      56             :                                          uint32_t *num_sids,
      57             :                                          struct dom_sid **sids,
      58             :                                          const struct dom_sid *primary_sid)
      59             : {
      60           0 :         struct ldb_message_element *el;
      61           0 :         unsigned int i;
      62             : 
      63        1348 :         el = ldb_msg_find_element(msg, attr);
      64        1348 :         if (!el) {
      65           1 :                 *sids = NULL;
      66           1 :                 return WERR_OK;
      67             :         }
      68             : 
      69             :         /* Make array long enough for NULL and additional SID */
      70        1347 :         (*sids) = talloc_array(mem_ctx, struct dom_sid,
      71             :                                el->num_values + 1);
      72        1347 :         W_ERROR_HAVE_NO_MEMORY(*sids);
      73             : 
      74        1347 :         (*sids)[PRIMARY_USER_SID_INDEX] = *primary_sid;
      75             : 
      76        9320 :         for (i = 0; i<el->num_values; i++) {
      77           0 :                 enum ndr_err_code ndr_err;
      78        7973 :                 struct dom_sid sid = { 0, };
      79             : 
      80        7973 :                 ndr_err = ndr_pull_struct_blob_all_noalloc(&el->values[i], &sid,
      81             :                                                (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
      82        7973 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
      83           0 :                         return WERR_INTERNAL_DB_CORRUPTION;
      84             :                 }
      85             :                 /* Primary SID is already in position zero. */
      86        7973 :                 (*sids)[i+1] = sid;
      87             :         }
      88             : 
      89        1347 :         *num_sids = i+1;
      90             : 
      91        1347 :         return WERR_OK;
      92             : }
      93             : 
      94             : /*
      95             :   return an array of SIDs from a ldb_message given an attribute name
      96             :   assumes the SIDs are in extended DN format
      97             :  */
      98        3090 : WERROR samdb_result_sid_array_dn(struct ldb_context *sam_ctx,
      99             :                                  const struct ldb_message *msg,
     100             :                                  TALLOC_CTX *mem_ctx,
     101             :                                  const char *attr,
     102             :                                  uint32_t *num_sids,
     103             :                                  struct dom_sid **sids)
     104             : {
     105           0 :         struct ldb_message_element *el;
     106           0 :         unsigned int i;
     107             : 
     108        3090 :         el = ldb_msg_find_element(msg, attr);
     109        3090 :         if (!el) {
     110           0 :                 *sids = NULL;
     111           0 :                 return WERR_OK;
     112             :         }
     113             : 
     114        3090 :         (*sids) = talloc_array(mem_ctx, struct dom_sid, el->num_values + 1);
     115        3090 :         W_ERROR_HAVE_NO_MEMORY(*sids);
     116             : 
     117       12976 :         for (i=0; i<el->num_values; i++) {
     118        9886 :                 struct ldb_dn *dn = ldb_dn_from_ldb_val(mem_ctx, sam_ctx, &el->values[i]);
     119           0 :                 NTSTATUS status;
     120        9886 :                 struct dom_sid sid = { 0, };
     121             : 
     122        9886 :                 status = dsdb_get_extended_dn_sid(dn, &sid, "SID");
     123        9886 :                 if (!NT_STATUS_IS_OK(status)) {
     124           0 :                         return WERR_INTERNAL_DB_CORRUPTION;
     125             :                 }
     126        9886 :                 (*sids)[i] = sid;
     127             :         }
     128        3090 :         *num_sids = i;
     129             : 
     130        3090 :         return WERR_OK;
     131             : }
     132             : 
     133        1551 : WERROR samdb_confirm_rodc_allowed_to_repl_to_sid_list(struct ldb_context *sam_ctx,
     134             :                                                       const struct dom_sid *rodc_machine_account_sid,
     135             :                                                       const struct ldb_message *rodc_msg,
     136             :                                                       const struct ldb_message *obj_msg,
     137             :                                                       uint32_t num_token_sids,
     138             :                                                       const struct dom_sid *token_sids)
     139             : {
     140           0 :         uint32_t num_never_reveal_sids, num_reveal_sids;
     141           0 :         struct dom_sid *never_reveal_sids, *reveal_sids;
     142        1551 :         TALLOC_CTX *frame = talloc_stackframe();
     143           0 :         WERROR werr;
     144           0 :         uint32_t rodc_uac;
     145             :         
     146             :         /*
     147             :          * We are not allowed to get anyone elses krbtgt secrets (and
     148             :          * in callers that don't shortcut before this, the RODC should
     149             :          * not deal with any krbtgt)
     150             :          */
     151        1551 :         if (samdb_result_dn(sam_ctx, frame,
     152             :                             obj_msg, "msDS-KrbTgtLinkBL", NULL)) {
     153           0 :                 TALLOC_FREE(frame);
     154           0 :                 DBG_INFO("Denied attempt to replicate to/act as a RODC krbtgt trust account %s using RODC: %s\n",
     155             :                          ldb_dn_get_linearized(obj_msg->dn),
     156             :                          ldb_dn_get_linearized(rodc_msg->dn));
     157           0 :                 return WERR_DS_DRA_SECRETS_DENIED;
     158             :         }
     159             : 
     160        1551 :         if (ldb_msg_find_attr_as_uint(obj_msg,
     161        1551 :                                       "userAccountControl", 0) &
     162             :             UF_INTERDOMAIN_TRUST_ACCOUNT) {
     163           0 :                 DBG_INFO("Denied attempt to replicate to/act as a inter-domain trust account %s using RODC: %s\n",
     164             :                          ldb_dn_get_linearized(obj_msg->dn),
     165             :                          ldb_dn_get_linearized(rodc_msg->dn));
     166           0 :                 TALLOC_FREE(frame);
     167           0 :                 return WERR_DS_DRA_SECRETS_DENIED;
     168             :         }
     169             : 
     170             :         /* Be very sure the RODC is really an RODC */
     171        1551 :         rodc_uac = ldb_msg_find_attr_as_uint(rodc_msg,
     172             :                                              "userAccountControl",
     173             :                                              0);
     174        1551 :         if ((rodc_uac & UF_PARTIAL_SECRETS_ACCOUNT)
     175             :             != UF_PARTIAL_SECRETS_ACCOUNT) {
     176           6 :                 DBG_ERR("Attempt to use an RODC account that is not an RODC: %s\n",
     177             :                         ldb_dn_get_linearized(rodc_msg->dn));
     178           6 :                 TALLOC_FREE(frame);
     179           6 :                 return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
     180             :         }
     181             : 
     182        1545 :         werr = samdb_result_sid_array_dn(sam_ctx, rodc_msg,
     183             :                                          frame, "msDS-NeverRevealGroup",
     184             :                                          &num_never_reveal_sids,
     185             :                                          &never_reveal_sids);
     186        1545 :         if (!W_ERROR_IS_OK(werr)) {
     187           0 :                 DBG_ERR("Failed to parse msDS-NeverRevealGroup on %s: %s\n",
     188             :                         ldb_dn_get_linearized(rodc_msg->dn),
     189             :                         win_errstr(werr));
     190           0 :                 TALLOC_FREE(frame);
     191           0 :                 return WERR_DS_DRA_SECRETS_DENIED;
     192             :         }
     193             : 
     194        1545 :         werr = samdb_result_sid_array_dn(sam_ctx, rodc_msg,
     195             :                                          frame, "msDS-RevealOnDemandGroup",
     196             :                                          &num_reveal_sids,
     197             :                                          &reveal_sids);
     198        1545 :         if (!W_ERROR_IS_OK(werr)) {
     199           0 :                 DBG_ERR("Failed to parse msDS-RevealOnDemandGroup on %s: %s\n",
     200             :                         ldb_dn_get_linearized(rodc_msg->dn),
     201             :                         win_errstr(werr));
     202           0 :                 TALLOC_FREE(frame);
     203           0 :                 return WERR_DS_DRA_SECRETS_DENIED;
     204             :         }
     205             : 
     206             :         /* The RODC can replicate and print tickets for itself. */
     207        1545 :         if (dom_sid_equal(&token_sids[PRIMARY_USER_SID_INDEX], rodc_machine_account_sid)) {
     208          47 :                 TALLOC_FREE(frame);
     209          47 :                 return WERR_OK;
     210             :         }
     211             : 
     212        2996 :         if (never_reveal_sids &&
     213        1498 :             sid_list_match(num_token_sids,
     214             :                            token_sids,
     215             :                            num_never_reveal_sids,
     216             :                            never_reveal_sids)) {
     217         933 :                 TALLOC_FREE(frame);
     218         933 :                 return WERR_DS_DRA_SECRETS_DENIED;
     219             :         }
     220             : 
     221        1130 :         if (reveal_sids &&
     222         565 :             sid_list_match(num_token_sids,
     223             :                            token_sids,
     224             :                            num_reveal_sids,
     225             :                            reveal_sids)) {
     226         159 :                 TALLOC_FREE(frame);
     227         159 :                 return WERR_OK;
     228             :         }
     229             : 
     230         406 :         TALLOC_FREE(frame);
     231         406 :         return WERR_DS_DRA_SECRETS_DENIED;
     232             : 
     233             : }
     234             : 
     235             : /*
     236             :  * This is a wrapper for the above that pulls in the tokenGroups
     237             :  * rather than relying on the caller providing those
     238             :  */
     239        1348 : WERROR samdb_confirm_rodc_allowed_to_repl_to(struct ldb_context *sam_ctx,
     240             :                                              struct dom_sid *rodc_machine_account_sid,
     241             :                                              struct ldb_message *rodc_msg,
     242             :                                              struct ldb_message *obj_msg)
     243             : {
     244        1348 :         TALLOC_CTX *frame = talloc_stackframe();
     245           0 :         WERROR werr;
     246           0 :         uint32_t num_token_sids;
     247           0 :         struct dom_sid *token_sids;
     248        1348 :         const struct dom_sid *object_sid = NULL;
     249             : 
     250        1348 :         object_sid = samdb_result_dom_sid(frame,
     251             :                                           obj_msg,
     252             :                                           "objectSid");
     253        1348 :         if (object_sid == NULL) {
     254           0 :                 return WERR_DS_DRA_BAD_DN;
     255             :         }
     256             :         
     257             :         /*
     258             :          * The SID list needs to include itself as well as the tokenGroups.
     259             :          *
     260             :          * TODO determine if sIDHistory is required for this check
     261             :          */
     262        1348 :         werr = samdb_result_sid_array_ndr(sam_ctx,
     263             :                                           obj_msg,
     264             :                                           frame, "tokenGroups",
     265             :                                           &num_token_sids,
     266             :                                           &token_sids,
     267             :                                           object_sid);
     268        1348 :         if (!W_ERROR_IS_OK(werr) || token_sids==NULL) {
     269           1 :                 DBG_ERR("Failed to get tokenGroups on %s to confirm access via RODC %s: %s\n",
     270             :                         ldb_dn_get_linearized(obj_msg->dn),
     271             :                         ldb_dn_get_linearized(rodc_msg->dn),
     272             :                         win_errstr(werr));
     273           1 :                 return WERR_DS_DRA_SECRETS_DENIED;
     274             :         }
     275             : 
     276        1347 :         werr = samdb_confirm_rodc_allowed_to_repl_to_sid_list(sam_ctx,
     277             :                                                               rodc_machine_account_sid,
     278             :                                                               rodc_msg,
     279             :                                                               obj_msg,
     280             :                                                               num_token_sids,
     281             :                                                               token_sids);
     282        1347 :         TALLOC_FREE(frame);
     283        1347 :         return werr;
     284             : }

Generated by: LCOV version 1.14