Coverage Report

Created: 2025-11-16 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source4/dsdb/schema/schema_info_attr.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
4
   SCHEMA::schemaInfo implementation
5
6
   Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
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 "dsdb/common/util.h"
24
#include "dsdb/samdb/samdb.h"
25
#include "dsdb/samdb/ldb_modules/util.h"
26
#include <ldb_module.h>
27
#include "librpc/gen_ndr/ndr_drsuapi.h"
28
#include "librpc/gen_ndr/ndr_drsblobs.h"
29
#include "param/param.h"
30
31
32
/**
33
 * Creates and initializes new dsdb_schema_info value.
34
 * Initial schemaInfo values is with:
35
 *   revision = 0
36
 *   invocationId = GUID_ZERO
37
 */
38
WERROR dsdb_schema_info_new(TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info)
39
0
{
40
0
  struct dsdb_schema_info *schema_info;
41
42
0
  schema_info = talloc_zero(mem_ctx, struct dsdb_schema_info);
43
0
  W_ERROR_HAVE_NO_MEMORY(schema_info);
44
45
0
  *_schema_info = schema_info;
46
47
0
  return WERR_OK;
48
0
}
49
50
/**
51
 * Creates and initializes new dsdb_schema_info blob value.
52
 * Initial schemaInfo values is with:
53
 *   revision = 0
54
 *   invocationId = GUID_ZERO
55
 */
56
WERROR dsdb_schema_info_blob_new(TALLOC_CTX *mem_ctx, DATA_BLOB *_schema_info_blob)
57
0
{
58
0
  DATA_BLOB blob;
59
60
0
  blob = data_blob_talloc_zero(mem_ctx, 21);
61
0
  W_ERROR_HAVE_NO_MEMORY(blob.data);
62
63
  /* Set the schemaInfo marker to 0xFF */
64
0
  blob.data[0] = 0xFF;
65
66
0
  *_schema_info_blob = blob;
67
68
0
  return WERR_OK;
69
0
}
70
71
72
/**
73
 * Verify the 'blob' is a valid schemaInfo blob
74
 */
75
bool dsdb_schema_info_blob_is_valid(const DATA_BLOB *blob)
76
0
{
77
0
  if (!blob || !blob->data) {
78
0
    return false;
79
0
  }
80
81
  /* schemaInfo blob must be 21 bytes long */
82
0
  if (blob->length != 21) {
83
0
    return false;
84
0
  }
85
86
  /* schemaInfo blob should start with 0xFF */
87
0
  if (blob->data[0] != 0xFF) {
88
0
    return false;
89
0
  }
90
91
0
  return true;
92
0
}
93
94
/**
95
 * Parse schemaInfo structure from a data_blob
96
 * (DATA_BLOB or ldb_val).
97
 * Suitable for parsing blobs that come from
98
 * DRS interface or from LDB database
99
 */
100
WERROR dsdb_schema_info_from_blob(const DATA_BLOB *blob,
101
          TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info)
102
0
{
103
0
  TALLOC_CTX *temp_ctx;
104
0
  enum ndr_err_code ndr_err;
105
0
  struct dsdb_schema_info *schema_info;
106
0
  struct schemaInfoBlob schema_info_blob;
107
108
  /* verify schemaInfo blob is valid */
109
0
  if (!dsdb_schema_info_blob_is_valid(blob)) {
110
0
    return WERR_INVALID_PARAMETER;
111
0
  }
112
113
0
  temp_ctx = talloc_new(mem_ctx);
114
0
  W_ERROR_HAVE_NO_MEMORY(temp_ctx);
115
116
0
  ndr_err = ndr_pull_struct_blob_all(blob, temp_ctx,
117
0
                                     &schema_info_blob,
118
0
                                     (ndr_pull_flags_fn_t)ndr_pull_schemaInfoBlob);
119
0
  if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
120
0
    NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
121
0
    talloc_free(temp_ctx);
122
0
    return ntstatus_to_werror(nt_status);
123
0
  }
124
125
0
  schema_info = talloc(mem_ctx, struct dsdb_schema_info);
126
0
  if (!schema_info) {
127
0
    talloc_free(temp_ctx);
128
0
    return WERR_NOT_ENOUGH_MEMORY;
129
0
  }
130
131
  /* note that we accept revision numbers of zero now - w2k8r2
132
     sends a revision of zero on initial vampire */
133
0
  schema_info->revision      = schema_info_blob.revision;
134
0
  schema_info->invocation_id = schema_info_blob.invocation_id;
135
0
  *_schema_info = schema_info;
136
137
0
  talloc_free(temp_ctx);
138
0
  return WERR_OK;
139
0
}
140
141
/**
142
 * Creates a blob from schemaInfo structure
143
 * Suitable for packing schemaInfo into a blob
144
 * which is to be used in DRS interface of LDB database
145
 */
146
WERROR dsdb_blob_from_schema_info(const struct dsdb_schema_info *schema_info,
147
          TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
148
0
{
149
0
  enum ndr_err_code ndr_err;
150
0
  struct schemaInfoBlob schema_info_blob;
151
152
0
  schema_info_blob.marker   = 0xFF;
153
0
  schema_info_blob.revision = schema_info->revision;
154
0
  schema_info_blob.invocation_id  = schema_info->invocation_id;
155
156
0
  ndr_err = ndr_push_struct_blob(blob, mem_ctx,
157
0
                                 &schema_info_blob,
158
0
                                 (ndr_push_flags_fn_t)ndr_push_schemaInfoBlob);
159
0
  if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
160
0
    NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
161
0
    return ntstatus_to_werror(nt_status);
162
0
  }
163
164
0
  return WERR_OK;
165
0
}
166
167
/**
168
 * Compares schemaInfo signatures in dsdb_schema and prefixMap.
169
 * NOTE: At present function compares schemaInfo values
170
 * as string without taking into account schemaVersion field
171
 *
172
 * @return WERR_OK if schemaInfos are equal
173
 *     WERR_DS_DRA_SCHEMA_MISMATCH if schemaInfos are different
174
 */
175
WERROR dsdb_schema_info_cmp(const struct dsdb_schema *schema,
176
          const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
177
0
{
178
0
  TALLOC_CTX *frame = NULL;
179
0
  DATA_BLOB blob = data_blob_null;
180
0
  struct dsdb_schema_info *schema_info = NULL;
181
0
  const struct drsuapi_DsReplicaOIDMapping *mapping = NULL;
182
0
  WERROR werr;
183
184
  /* we should have at least schemaInfo element */
185
0
  if (ctr->num_mappings < 1) {
186
0
    return WERR_INVALID_PARAMETER;
187
0
  }
188
189
  /* verify schemaInfo element is valid */
190
0
  mapping = &ctr->mappings[ctr->num_mappings - 1];
191
0
  if (mapping->id_prefix != 0) {
192
0
    return WERR_INVALID_PARAMETER;
193
0
  }
194
195
0
  blob = data_blob_const(mapping->oid.binary_oid, mapping->oid.length);
196
0
  if (!dsdb_schema_info_blob_is_valid(&blob)) {
197
0
    return WERR_INVALID_PARAMETER;
198
0
  }
199
200
0
  frame = talloc_stackframe();
201
0
  werr = dsdb_schema_info_from_blob(&blob, frame, &schema_info);
202
0
  if (!W_ERROR_IS_OK(werr)) {
203
0
    TALLOC_FREE(frame);
204
0
    return werr;
205
0
  }
206
207
  /*
208
   * shouldn't really be possible is dsdb_schema_info_from_blob
209
   * succeeded, this check is just to satisfy static checker
210
   */
211
0
  if (schema_info == NULL) {
212
0
    TALLOC_FREE(frame);
213
0
    return WERR_INVALID_PARAMETER;
214
0
  }
215
216
0
  if (schema->schema_info->revision > schema_info->revision) {
217
    /*
218
     * It's ok if our schema is newer than the remote one
219
     */
220
0
    werr = WERR_OK;
221
0
  } else if (schema->schema_info->revision < schema_info->revision) {
222
0
    werr = WERR_DS_DRA_SCHEMA_MISMATCH;
223
0
  } else if (!GUID_equal(&schema->schema_info->invocation_id,
224
0
       &schema_info->invocation_id))
225
0
  {
226
0
    werr = WERR_DS_DRA_SCHEMA_CONFLICT;
227
0
  } else {
228
0
    werr = WERR_OK;
229
0
  }
230
231
  TALLOC_FREE(frame);
232
0
  return werr;
233
0
}
234
235