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 blob value.
34 * Initial schemaInfo values is with:
36 * invocationId = GUID_ZERO
38 WERROR dsdb_schema_info_blob_new(TALLOC_CTX *mem_ctx, DATA_BLOB *_schema_info_blob)
42 blob = data_blob_talloc_zero(mem_ctx, 21);
43 W_ERROR_HAVE_NO_MEMORY(blob.data);
45 /* Set the schemaInfo marker to 0xFF */
48 *_schema_info_blob = blob;
55 * Parse schemaInfo structure from a data_blob
56 * (DATA_BLOB or ldb_val).
57 * Suitable for parsing blobs that comes from
58 * DRS interface of from LDB database
60 WERROR dsdb_schema_info_from_blob(const DATA_BLOB *blob,
61 TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info)
64 enum ndr_err_code ndr_err;
65 struct dsdb_schema_info *schema_info;
66 struct schemaInfoBlob schema_info_blob;
68 if (!blob || !blob->data) {
69 return WERR_INVALID_PARAMETER;
72 if (blob->length != 21) {
73 return WERR_INVALID_PARAMETER;
76 /* schemaInfo blob should start with 0xFF */
77 if (blob->data[0] != 0xFF) {
78 return WERR_INVALID_PARAMETER;
81 temp_ctx = talloc_new(mem_ctx);
82 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
84 ndr_err = ndr_pull_struct_blob_all(blob, temp_ctx,
85 lp_iconv_convenience(NULL), &schema_info_blob,
86 (ndr_pull_flags_fn_t)ndr_pull_schemaInfoBlob);
87 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
88 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
89 talloc_free(temp_ctx);
90 return ntstatus_to_werror(nt_status);
93 schema_info = talloc(mem_ctx, struct dsdb_schema_info);
95 talloc_free(temp_ctx);
99 /* note that we accept revision numbers of zero now - w2k8r2
100 sends a revision of zero on initial vampire */
101 schema_info->revision = schema_info_blob.revision;
102 schema_info->invocation_id = schema_info_blob.invocation_id;
103 *_schema_info = schema_info;
105 talloc_free(temp_ctx);
110 * Creates a blob from schemaInfo structure
111 * Suitable for packing schemaInfo into a blob
112 * which is to be used in DRS interface of LDB database
114 WERROR dsdb_blob_from_schema_info(const struct dsdb_schema_info *schema_info,
115 TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
117 enum ndr_err_code ndr_err;
118 struct schemaInfoBlob schema_info_blob;
120 if (schema_info->revision < 1) {
121 return WERR_INVALID_PARAMETER;
124 schema_info_blob.marker = 0xFF;
125 schema_info_blob.revision = schema_info->revision;
126 schema_info_blob.invocation_id = schema_info->invocation_id;
128 ndr_err = ndr_push_struct_blob(blob, mem_ctx,
129 lp_iconv_convenience(NULL), &schema_info_blob,
130 (ndr_push_flags_fn_t)ndr_push_schemaInfoBlob);
131 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
132 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
133 return ntstatus_to_werror(nt_status);
141 * Reads schema_info structure from schemaInfo
142 * attribute on SCHEMA partition
144 * @param dsdb_flags DSDB_FLAG_... flag of 0
146 WERROR dsdb_module_schema_info_blob_read(struct ldb_module *ldb_module,
148 TALLOC_CTX *mem_ctx, DATA_BLOB *schema_info_blob)
151 const struct ldb_val *blob_val;
152 struct ldb_dn *schema_dn;
153 struct ldb_result *schema_res = NULL;
154 static const char *schema_attrs[] = {
159 schema_dn = ldb_get_schema_basedn(ldb_module_get_ctx(ldb_module));
161 DEBUG(0,("dsdb_module_schema_info_blob_read: no schema dn present!\n"));
162 return WERR_INTERNAL_DB_CORRUPTION;
165 ldb_err = dsdb_module_search(ldb_module, mem_ctx, &schema_res, schema_dn,
166 LDB_SCOPE_BASE, schema_attrs, dsdb_flags, NULL);
167 if (ldb_err == LDB_ERR_NO_SUCH_OBJECT) {
168 DEBUG(0,("dsdb_module_schema_info_blob_read: Schema DN not found!\n"));
169 talloc_free(schema_res);
170 return WERR_INTERNAL_DB_CORRUPTION;
171 } else if (ldb_err != LDB_SUCCESS) {
172 DEBUG(0,("dsdb_module_schema_info_blob_read: failed to find schemaInfo attribute\n"));
173 talloc_free(schema_res);
174 return WERR_INTERNAL_DB_CORRUPTION;
177 blob_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo");
179 DEBUG(0,("dsdb_module_schema_info_blob_read: no schemaInfo attribute found\n"));
180 talloc_free(schema_res);
181 return WERR_DS_NO_ATTRIBUTE_OR_VALUE;
184 /* transfer .data ownership to mem_ctx */
185 schema_info_blob->length = blob_val->length;
186 schema_info_blob->data = talloc_steal(mem_ctx, blob_val->data);
188 talloc_free(schema_res);
194 * Pepares ldb_msg to be used for updating schemaInfo value in DB
196 static WERROR _dsdb_schema_info_write_prepare(struct ldb_context *ldb,
197 DATA_BLOB *schema_info_blob,
199 struct ldb_message **_msg)
202 struct ldb_message *msg;
203 struct ldb_dn *schema_dn;
204 struct ldb_message_element *return_el;
206 schema_dn = ldb_get_schema_basedn(ldb);
208 DEBUG(0,("_dsdb_schema_info_write_prepare: no schema dn present\n"));
209 return WERR_INTERNAL_DB_CORRUPTION;
212 /* prepare ldb_msg to update schemaInfo */
213 msg = ldb_msg_new(mem_ctx);
214 W_ERROR_HAVE_NO_MEMORY(msg);
217 ldb_err = ldb_msg_add_value(msg, "schemaInfo", schema_info_blob, &return_el);
219 DEBUG(0,("_dsdb_schema_info_write_prepare: ldb_msg_add_value failed - %s\n",
220 ldb_strerror(ldb_err)));
222 return WERR_INTERNAL_ERROR;
225 /* mark schemaInfo element for replacement */
226 return_el->flags = LDB_FLAG_MOD_REPLACE;
234 * Writes schema_info structure into schemaInfo
235 * attribute on SCHEMA partition
237 * @param dsdb_flags DSDB_FLAG_... flag of 0
239 WERROR dsdb_module_schema_info_blob_write(struct ldb_module *ldb_module,
241 DATA_BLOB *schema_info_blob)
245 struct ldb_message *msg;
246 TALLOC_CTX *temp_ctx;
248 temp_ctx = talloc_new(ldb_module);
249 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
251 /* write serialized schemaInfo into LDB */
252 werr = _dsdb_schema_info_write_prepare(ldb_module_get_ctx(ldb_module),
255 if (!W_ERROR_IS_OK(werr)) {
256 talloc_free(temp_ctx);
261 ldb_err = dsdb_module_modify(ldb_module, msg, dsdb_flags);
263 talloc_free(temp_ctx);
266 DEBUG(0,("dsdb_module_schema_info_blob_write: dsdb_replace failed: %s (%s)\n",
267 ldb_strerror(ldb_err),
268 ldb_errstring(ldb_module_get_ctx(ldb_module))));
269 return WERR_INTERNAL_DB_ERROR;
277 * Reads schema_info structure from schemaInfo
278 * attribute on SCHEMA partition
280 static WERROR dsdb_module_schema_info_read(struct ldb_module *ldb_module,
283 struct dsdb_schema_info **_schema_info)
287 TALLOC_CTX *temp_ctx;
289 temp_ctx = talloc_new(mem_ctx);
290 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
292 /* read serialized schemaInfo from LDB */
293 werr = dsdb_module_schema_info_blob_read(ldb_module, dsdb_flags, temp_ctx, &ndr_blob);
294 if (!W_ERROR_IS_OK(werr)) {
295 talloc_free(temp_ctx);
299 /* convert NDR blob to dsdb_schema_info object */
300 werr = dsdb_schema_info_from_blob(&ndr_blob,
303 talloc_free(temp_ctx);
309 * Writes schema_info structure into schemaInfo
310 * attribute on SCHEMA partition
312 * @param dsdb_flags DSDB_FLAG_... flag of 0
314 static WERROR dsdb_module_schema_info_write(struct ldb_module *ldb_module,
316 const struct dsdb_schema_info *schema_info)
320 TALLOC_CTX *temp_ctx;
322 temp_ctx = talloc_new(ldb_module);
323 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
325 /* convert schema_info to a blob */
326 werr = dsdb_blob_from_schema_info(schema_info, temp_ctx, &ndr_blob);
327 if (!W_ERROR_IS_OK(werr)) {
328 talloc_free(temp_ctx);
332 /* write serialized schemaInfo into LDB */
333 werr = dsdb_module_schema_info_blob_write(ldb_module, dsdb_flags, &ndr_blob);
335 talloc_free(temp_ctx);
342 * Creates new dsdb_schema_info object using
343 * invocationId from supplied ldb
344 * @param check_invocation_id Error out if invocationId is not yet set
346 WERROR dsdb_schema_info_create(struct ldb_context *ldb, bool check_invocation_id,
347 TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info)
349 const struct GUID *invocation_id;
350 struct dsdb_schema_info *schema_info;
352 /* try to determine invocationId from ldb */
353 invocation_id = samdb_ntds_invocation_id(ldb);
354 if (check_invocation_id && !invocation_id) {
355 return WERR_INTERNAL_DB_CORRUPTION;
358 schema_info = talloc(mem_ctx, struct dsdb_schema_info);
363 schema_info->revision = 1;
365 schema_info->invocation_id = *invocation_id;
367 schema_info->invocation_id = GUID_zero();
370 *_schema_info = schema_info;
377 * Increments schemaInfo revision and save it to DB
378 * setting our invocationID in the process
379 * NOTE: this function should be called in a transaction
380 * much in the same way prefixMap update function is called
382 * @param ldb_module current module
383 * @param schema schema cache
384 * @param dsdb_flags DSDB_FLAG_... flag of 0
386 WERROR dsdb_module_schema_info_update(struct ldb_module *ldb_module,
387 struct dsdb_schema *schema,
391 const struct GUID *invocation_id;
392 struct dsdb_schema_info *schema_info;
394 TALLOC_CTX *mem_ctx = talloc_new(schema);
395 W_ERROR_HAVE_NO_MEMORY(mem_ctx);
397 invocation_id = samdb_ntds_invocation_id(ldb_module_get_ctx(ldb_module));
398 if (!invocation_id) {
399 return WERR_INTERNAL_DB_CORRUPTION;
402 werr = dsdb_module_schema_info_read(ldb_module, dsdb_flags,
403 mem_ctx, &schema_info);
404 if (!W_ERROR_IS_OK(werr)) {
405 DEBUG(0,("dsdb_module_schema_info_update: failed to reload schemaInfo - %s\n",
407 talloc_free(mem_ctx);
411 /* update schemaInfo */
412 schema_info->revision++;
413 schema_info->invocation_id = *invocation_id;
415 werr = dsdb_module_schema_info_write(ldb_module, dsdb_flags, schema_info);
416 if (!W_ERROR_IS_OK(werr)) {
417 DEBUG(0,("dsdb_module_schema_info_update: failed to save schemaInfo - %s\n",
419 talloc_free(mem_ctx);
423 /* finally, update schema_info in the cache */
424 /* TODO: update schema_info in dsdb_schema cache */
426 talloc_unlink(schema, discard_const(schema->schema_info));
427 schema->schema_info = talloc_steal(schema, schema_info);
430 talloc_free(mem_ctx);