2 Unix SMB/CIFS implementation.
4 SCHEMA::schemaInfo implementation
6 Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
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.
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.
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/>.
23 #include "dsdb/common/util.h"
24 #include "dsdb/samdb/samdb.h"
25 #include "dsdb/samdb/ldb_modules/util.h"
26 #include "lib/ldb/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"
33 * Creates and initializes new dsdb_schema_info value.
34 * Initial schemaInfo values is with:
36 * invocationId = GUID_ZERO
38 WERROR dsdb_schema_info_new(TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info)
40 struct dsdb_schema_info *schema_info;
42 schema_info = talloc_zero(mem_ctx, struct dsdb_schema_info);
43 W_ERROR_HAVE_NO_MEMORY(schema_info);
45 *_schema_info = schema_info;
51 * Creates and initializes new dsdb_schema_info blob value.
52 * Initial schemaInfo values is with:
54 * invocationId = GUID_ZERO
56 WERROR dsdb_schema_info_blob_new(TALLOC_CTX *mem_ctx, DATA_BLOB *_schema_info_blob)
60 blob = data_blob_talloc_zero(mem_ctx, 21);
61 W_ERROR_HAVE_NO_MEMORY(blob.data);
63 /* Set the schemaInfo marker to 0xFF */
66 *_schema_info_blob = blob;
73 * Verify the 'blob' is a valid schemaInfo blob
75 bool dsdb_schema_info_blob_is_valid(const DATA_BLOB *blob)
77 if (!blob || !blob->data) {
81 /* schemaInfo blob must be 21 bytes long */
82 if (blob->length != 21) {
86 /* schemaInfo blob should start with 0xFF */
87 if (blob->data[0] != 0xFF) {
95 * Parse schemaInfo structure from a data_blob
96 * (DATA_BLOB or ldb_val).
97 * Suitable for parsing blobs that comes from
98 * DRS interface of from LDB database
100 WERROR dsdb_schema_info_from_blob(const DATA_BLOB *blob,
101 TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info)
103 TALLOC_CTX *temp_ctx;
104 enum ndr_err_code ndr_err;
105 struct dsdb_schema_info *schema_info;
106 struct schemaInfoBlob schema_info_blob;
108 /* verify schemaInfo blob is valid */
109 if (!dsdb_schema_info_blob_is_valid(blob)) {
110 return WERR_INVALID_PARAMETER;
113 temp_ctx = talloc_new(mem_ctx);
114 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
116 ndr_err = ndr_pull_struct_blob_all(blob, temp_ctx,
118 (ndr_pull_flags_fn_t)ndr_pull_schemaInfoBlob);
119 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
120 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
121 talloc_free(temp_ctx);
122 return ntstatus_to_werror(nt_status);
125 schema_info = talloc(mem_ctx, struct dsdb_schema_info);
127 talloc_free(temp_ctx);
131 /* note that we accept revision numbers of zero now - w2k8r2
132 sends a revision of zero on initial vampire */
133 schema_info->revision = schema_info_blob.revision;
134 schema_info->invocation_id = schema_info_blob.invocation_id;
135 *_schema_info = schema_info;
137 talloc_free(temp_ctx);
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
146 WERROR dsdb_blob_from_schema_info(const struct dsdb_schema_info *schema_info,
147 TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
149 enum ndr_err_code ndr_err;
150 struct schemaInfoBlob schema_info_blob;
152 schema_info_blob.marker = 0xFF;
153 schema_info_blob.revision = schema_info->revision;
154 schema_info_blob.invocation_id = schema_info->invocation_id;
156 ndr_err = ndr_push_struct_blob(blob, mem_ctx,
158 (ndr_push_flags_fn_t)ndr_push_schemaInfoBlob);
159 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
160 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
161 return ntstatus_to_werror(nt_status);
168 * Compares schemaInfo signatures in dsdb_schema and prefixMap.
169 * NOTE: At present function compares schemaInfo values
170 * as string without taking into account schemVersion field
172 * @return WERR_OK if schemaInfos are equal
173 * WERR_DS_DRA_SCHEMA_MISMATCH if schemaInfos are different
175 WERROR dsdb_schema_info_cmp(const struct dsdb_schema *schema,
176 const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
180 char *schema_info_str;
181 struct drsuapi_DsReplicaOIDMapping *mapping;
183 /* we should have at least schemaInfo element */
184 if (ctr->num_mappings < 1) {
185 return WERR_INVALID_PARAMETER;
188 /* verify schemaInfo element is valid */
189 mapping = &ctr->mappings[ctr->num_mappings - 1];
190 if (mapping->id_prefix != 0) {
191 return WERR_INVALID_PARAMETER;
194 blob = data_blob_const(mapping->oid.binary_oid, mapping->oid.length);
195 if (!dsdb_schema_info_blob_is_valid(&blob)) {
196 return WERR_INVALID_PARAMETER;
199 schema_info_str = hex_encode_talloc(NULL, blob.data, blob.length);
200 W_ERROR_HAVE_NO_MEMORY(schema_info_str);
202 bres = strequal(schema->schema_info, schema_info_str);
203 talloc_free(schema_info_str);
205 return bres ? WERR_OK : WERR_DS_DRA_SCHEMA_MISMATCH;
210 * Reads schema_info structure from schemaInfo
211 * attribute on SCHEMA partition
213 * @param dsdb_flags DSDB_FLAG_... flag of 0
215 WERROR dsdb_module_schema_info_blob_read(struct ldb_module *ldb_module,
217 TALLOC_CTX *mem_ctx, DATA_BLOB *schema_info_blob)
220 const struct ldb_val *blob_val;
221 struct ldb_dn *schema_dn;
222 struct ldb_result *schema_res = NULL;
223 static const char *schema_attrs[] = {
228 schema_dn = ldb_get_schema_basedn(ldb_module_get_ctx(ldb_module));
230 DEBUG(0,("dsdb_module_schema_info_blob_read: no schema dn present!\n"));
231 return WERR_INTERNAL_DB_CORRUPTION;
234 ldb_err = dsdb_module_search(ldb_module, mem_ctx, &schema_res, schema_dn,
235 LDB_SCOPE_BASE, schema_attrs, dsdb_flags, NULL);
236 if (ldb_err == LDB_ERR_NO_SUCH_OBJECT) {
237 DEBUG(0,("dsdb_module_schema_info_blob_read: Schema DN not found!\n"));
238 talloc_free(schema_res);
239 return WERR_INTERNAL_DB_CORRUPTION;
240 } else if (ldb_err != LDB_SUCCESS) {
241 DEBUG(0,("dsdb_module_schema_info_blob_read: failed to find schemaInfo attribute\n"));
242 talloc_free(schema_res);
243 return WERR_INTERNAL_DB_CORRUPTION;
246 blob_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo");
248 DEBUG(0,("dsdb_module_schema_info_blob_read: no schemaInfo attribute found\n"));
249 talloc_free(schema_res);
250 return WERR_DS_NO_ATTRIBUTE_OR_VALUE;
253 /* transfer .data ownership to mem_ctx */
254 schema_info_blob->length = blob_val->length;
255 schema_info_blob->data = talloc_steal(mem_ctx, blob_val->data);
257 talloc_free(schema_res);
263 * Prepares ldb_msg to be used for updating schemaInfo value in DB
265 static WERROR _dsdb_schema_info_write_prepare(struct ldb_context *ldb,
266 DATA_BLOB *schema_info_blob,
268 struct ldb_message **_msg)
271 struct ldb_message *msg;
272 struct ldb_dn *schema_dn;
273 struct ldb_message_element *return_el;
275 schema_dn = ldb_get_schema_basedn(ldb);
277 DEBUG(0,("_dsdb_schema_info_write_prepare: no schema dn present\n"));
278 return WERR_INTERNAL_DB_CORRUPTION;
281 /* prepare ldb_msg to update schemaInfo */
282 msg = ldb_msg_new(mem_ctx);
283 W_ERROR_HAVE_NO_MEMORY(msg);
286 ldb_err = ldb_msg_add_value(msg, "schemaInfo", schema_info_blob, &return_el);
288 DEBUG(0,("_dsdb_schema_info_write_prepare: ldb_msg_add_value failed - %s\n",
289 ldb_strerror(ldb_err)));
291 return WERR_INTERNAL_ERROR;
294 /* mark schemaInfo element for replacement */
295 return_el->flags = LDB_FLAG_MOD_REPLACE;
303 * Writes schema_info structure into schemaInfo
304 * attribute on SCHEMA partition
306 * @param dsdb_flags DSDB_FLAG_... flag of 0
308 WERROR dsdb_module_schema_info_blob_write(struct ldb_module *ldb_module,
310 DATA_BLOB *schema_info_blob)
314 struct ldb_message *msg;
315 TALLOC_CTX *temp_ctx;
317 temp_ctx = talloc_new(ldb_module);
318 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
320 /* write serialized schemaInfo into LDB */
321 werr = _dsdb_schema_info_write_prepare(ldb_module_get_ctx(ldb_module),
324 if (!W_ERROR_IS_OK(werr)) {
325 talloc_free(temp_ctx);
330 ldb_err = dsdb_module_modify(ldb_module, msg, dsdb_flags);
332 talloc_free(temp_ctx);
335 DEBUG(0,("dsdb_module_schema_info_blob_write: dsdb_replace failed: %s (%s)\n",
336 ldb_strerror(ldb_err),
337 ldb_errstring(ldb_module_get_ctx(ldb_module))));
338 return WERR_INTERNAL_DB_ERROR;
346 * Reads schema_info structure from schemaInfo
347 * attribute on SCHEMA partition
349 static WERROR dsdb_module_schema_info_read(struct ldb_module *ldb_module,
352 struct dsdb_schema_info **_schema_info)
356 TALLOC_CTX *temp_ctx;
358 temp_ctx = talloc_new(mem_ctx);
359 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
361 /* read serialized schemaInfo from LDB */
362 werr = dsdb_module_schema_info_blob_read(ldb_module, dsdb_flags, temp_ctx, &ndr_blob);
363 if (!W_ERROR_IS_OK(werr)) {
364 talloc_free(temp_ctx);
368 /* convert NDR blob to dsdb_schema_info object */
369 werr = dsdb_schema_info_from_blob(&ndr_blob,
372 talloc_free(temp_ctx);
378 * Writes schema_info structure into schemaInfo
379 * attribute on SCHEMA partition
381 * @param dsdb_flags DSDB_FLAG_... flag of 0
383 static WERROR dsdb_module_schema_info_write(struct ldb_module *ldb_module,
385 const struct dsdb_schema_info *schema_info)
389 TALLOC_CTX *temp_ctx;
391 temp_ctx = talloc_new(ldb_module);
392 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
394 /* convert schema_info to a blob */
395 werr = dsdb_blob_from_schema_info(schema_info, temp_ctx, &ndr_blob);
396 if (!W_ERROR_IS_OK(werr)) {
397 talloc_free(temp_ctx);
401 /* write serialized schemaInfo into LDB */
402 werr = dsdb_module_schema_info_blob_write(ldb_module, dsdb_flags, &ndr_blob);
404 talloc_free(temp_ctx);
411 * Increments schemaInfo revision and save it to DB
412 * setting our invocationID in the process
413 * NOTE: this function should be called in a transaction
414 * much in the same way prefixMap update function is called
416 * @param ldb_module current module
417 * @param schema schema cache
418 * @param dsdb_flags DSDB_FLAG_... flag of 0
420 WERROR dsdb_module_schema_info_update(struct ldb_module *ldb_module,
421 struct dsdb_schema *schema,
425 const struct GUID *invocation_id;
427 struct dsdb_schema_info *schema_info;
428 const char *schema_info_str;
430 TALLOC_CTX *temp_ctx = talloc_new(schema);
431 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
433 invocation_id = samdb_ntds_invocation_id(ldb_module_get_ctx(ldb_module));
434 if (!invocation_id) {
435 return WERR_INTERNAL_DB_CORRUPTION;
438 /* read serialized schemaInfo from LDB */
439 werr = dsdb_module_schema_info_read(ldb_module, dsdb_flags, temp_ctx, &schema_info);
440 if (W_ERROR_EQUAL(werr, WERR_DS_NO_ATTRIBUTE_OR_VALUE)) {
441 /* make default value in case
442 * we have no schemaInfo value yet */
443 werr = dsdb_schema_info_new(temp_ctx, &schema_info);
445 if (!W_ERROR_IS_OK(werr)) {
446 DEBUG(0,("dsdb_module_schema_info_update: failed to reload schemaInfo - %s\n",
448 talloc_free(temp_ctx);
452 /* update schemaInfo */
453 schema_info->revision++;
454 schema_info->invocation_id = *invocation_id;
456 werr = dsdb_module_schema_info_write(ldb_module, dsdb_flags, schema_info);
457 if (!W_ERROR_IS_OK(werr)) {
458 DEBUG(0,("dsdb_module_schema_info_update: failed to save schemaInfo - %s\n",
460 talloc_free(temp_ctx);
464 /* finally, update schema_info in the cache */
465 werr = dsdb_blob_from_schema_info(schema_info, temp_ctx, &ndr_blob);
466 W_ERROR_NOT_OK_RETURN(werr);
468 schema_info_str = hex_encode_talloc(schema, ndr_blob.data, ndr_blob.length);
469 W_ERROR_HAVE_NO_MEMORY(schema_info_str);
471 talloc_unlink(schema, discard_const(schema->schema_info));
472 schema->schema_info = schema_info_str;
474 talloc_free(temp_ctx);