Coverage Report

Created: 2026-01-16 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source4/dsdb/common/dsdb_access.c
Line
Count
Source
1
/*
2
  ldb database library
3
4
  Copyright (C) Nadezhda Ivanova 2010
5
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
8
  the Free Software Foundation; either version 3 of the License, or
9
  (at your option) any later version.
10
11
  This program is distributed in the hope that it will be useful,
12
  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
  GNU General Public License for more details.
15
16
  You should have received a copy of the GNU General Public License
17
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
*/
19
20
/*
21
 *  Name: dsdb_access
22
 *
23
 *  Description: utility functions for access checking on objects
24
 *
25
 *  Authors: Nadezhda Ivanova
26
 */
27
28
#include "includes.h"
29
#include "ldb.h"
30
#include "ldb_module.h"
31
#include "ldb_errors.h"
32
#include "libcli/security/security.h"
33
#include "librpc/gen_ndr/ndr_security.h"
34
#include "libcli/ldap/ldap_ndr.h"
35
#include "param/param.h"
36
#include "auth/auth.h"
37
#include "dsdb/samdb/samdb.h"
38
#include "dsdb/common/util.h"
39
40
void dsdb_acl_debug(struct security_descriptor *sd,
41
          struct security_token *token,
42
          struct ldb_dn *dn,
43
          bool denied,
44
          int level)
45
0
{
46
0
  if (denied) {
47
0
    DEBUG(level, ("Access on %s denied\n", ldb_dn_get_linearized(dn)));
48
0
  } else {
49
0
    DEBUG(level, ("Access on %s granted\n", ldb_dn_get_linearized(dn)));
50
0
  }
51
52
0
  DEBUG(level,("Security context: %s\n",
53
0
         ndr_print_struct_string(0,(ndr_print_fn_t)ndr_print_security_token,"", token)));
54
0
  DEBUG(level,("Security descriptor: %s\n",
55
0
         ndr_print_struct_string(0,(ndr_print_fn_t)ndr_print_security_descriptor,"", sd)));
56
0
}
57
58
int dsdb_get_sd_from_ldb_message(struct ldb_context *ldb,
59
         TALLOC_CTX *mem_ctx,
60
         struct ldb_message *acl_res,
61
         struct security_descriptor **sd)
62
0
{
63
0
  struct ldb_message_element *sd_element;
64
0
  enum ndr_err_code ndr_err;
65
66
0
  sd_element = ldb_msg_find_element(acl_res, "nTSecurityDescriptor");
67
0
  if (sd_element == NULL) {
68
0
    return ldb_error(ldb, LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS,
69
0
         "nTSecurityDescriptor is missing");
70
0
  }
71
0
  *sd = talloc(mem_ctx, struct security_descriptor);
72
0
  if(!*sd) {
73
0
    return ldb_oom(ldb);
74
0
  }
75
0
  ndr_err = ndr_pull_struct_blob(&sd_element->values[0], *sd, *sd,
76
0
               (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
77
78
0
  if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
79
0
    TALLOC_FREE(*sd);
80
0
    return ldb_operr(ldb);
81
0
  }
82
83
0
  return LDB_SUCCESS;
84
0
}
85
86
int dsdb_check_access_on_dn_internal(struct ldb_context *ldb,
87
             struct ldb_result *acl_res,
88
             TALLOC_CTX *mem_ctx,
89
             struct security_token *token,
90
             struct ldb_dn *dn,
91
             uint32_t access_mask,
92
             const struct GUID *guid)
93
0
{
94
0
  struct security_descriptor *sd = NULL;
95
0
  struct dom_sid *sid = NULL;
96
0
  struct object_tree *root = NULL;
97
0
  NTSTATUS status;
98
0
  uint32_t access_granted;
99
0
  int ret;
100
101
0
  ret = dsdb_get_sd_from_ldb_message(ldb, mem_ctx, acl_res->msgs[0], &sd);
102
0
  if (ret != LDB_SUCCESS) {
103
0
    return ldb_operr(ldb);
104
0
  }
105
106
0
  sid = samdb_result_dom_sid(mem_ctx, acl_res->msgs[0], "objectSid");
107
0
  if (guid) {
108
0
    if (!insert_in_object_tree(mem_ctx, guid, access_mask, NULL,
109
0
             &root)) {
110
0
      TALLOC_FREE(sd);
111
0
      TALLOC_FREE(sid);
112
0
      return ldb_operr(ldb);
113
0
    }
114
0
  }
115
0
  status = sec_access_check_ds(sd, token,
116
0
             access_mask,
117
0
             &access_granted,
118
0
             root,
119
0
             sid);
120
0
  if (!NT_STATUS_IS_OK(status)) {
121
0
    dsdb_acl_debug(sd,
122
0
             token,
123
0
             dn,
124
0
             true,
125
0
             10);
126
0
    ldb_asprintf_errstring(ldb,
127
0
               "dsdb_access: Access check failed on %s",
128
0
               ldb_dn_get_linearized(dn));
129
0
    TALLOC_FREE(sd);
130
0
    TALLOC_FREE(sid);
131
0
    return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
132
0
  }
133
0
  return LDB_SUCCESS;
134
0
}
135
136
/* performs an access check from outside the module stack
137
 * given the dn of the object to be checked, the required access
138
 * guid is either the guid of the extended right, or NULL
139
 */
140
141
int dsdb_check_access_on_dn(struct ldb_context *ldb,
142
          TALLOC_CTX *mem_ctx,
143
          struct ldb_dn *dn,
144
          struct security_token *token,
145
          uint32_t access_mask,
146
          const char *ext_right)
147
0
{
148
0
  int ret;
149
0
  struct GUID guid;
150
0
  struct ldb_result *acl_res;
151
0
  static const char *acl_attrs[] = {
152
0
    "nTSecurityDescriptor",
153
0
    "objectSid",
154
0
    NULL
155
0
  };
156
157
0
  if (ext_right != NULL) {
158
0
    NTSTATUS status = GUID_from_string(ext_right, &guid);
159
0
    if (!NT_STATUS_IS_OK(status)) {
160
0
      return LDB_ERR_OPERATIONS_ERROR;
161
0
    }
162
0
  }
163
164
  /*
165
   * We need AS_SYSTEM in order to get the nTSecurityDescriptor attribute.
166
   * Also the result of this search not controlled by the client
167
   * nor is the result exposed to the client.
168
   */
169
0
  ret = dsdb_search_dn(ldb, mem_ctx, &acl_res, dn, acl_attrs,
170
0
           DSDB_FLAG_AS_SYSTEM | DSDB_SEARCH_SHOW_RECYCLED);
171
0
  if (ret != LDB_SUCCESS) {
172
0
    DEBUG(10,("access_check: failed to find object %s\n", ldb_dn_get_linearized(dn)));
173
0
    return ret;
174
0
  }
175
176
0
  return dsdb_check_access_on_dn_internal(ldb, acl_res,
177
0
            mem_ctx,
178
0
            token,
179
0
            dn,
180
0
            access_mask,
181
0
            ext_right ? &guid : NULL);
182
0
}
183