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 * Parse schemaInfo structure from a data_blob
34 * (DATA_BLOB or ldb_val).
35 * Suitable for parsing blobs that comes from
36 * DRS interface of from LDB database
38 WERROR dsdb_schema_info_from_blob(const DATA_BLOB *blob,
39 TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info)
42 enum ndr_err_code ndr_err;
43 struct dsdb_schema_info *schema_info;
44 struct schemaInfoBlob schema_info_blob;
46 if (!blob || !blob->data) {
47 return WERR_INVALID_PARAMETER;
50 if (blob->length != 21) {
51 return WERR_INVALID_PARAMETER;
54 /* schemaInfo blob should start with 0xFF */
55 if (blob->data[0] != 0xFF) {
56 return WERR_INVALID_PARAMETER;
59 temp_ctx = talloc_new(mem_ctx);
60 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
62 ndr_err = ndr_pull_struct_blob_all(blob, temp_ctx,
63 lp_iconv_convenience(NULL), &schema_info_blob,
64 (ndr_pull_flags_fn_t)ndr_pull_schemaInfoBlob);
65 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
66 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
67 talloc_free(temp_ctx);
68 return ntstatus_to_werror(nt_status);
71 /* revision must be not less than 1 */
72 if (schema_info_blob.revision < 1) {
73 talloc_free(temp_ctx);
74 return WERR_INVALID_PARAMETER;
77 schema_info = talloc(mem_ctx, struct dsdb_schema_info);
79 talloc_free(temp_ctx);
82 schema_info->revision = schema_info_blob.revision;
83 schema_info->invocation_id = schema_info_blob.invocation_id;
84 *_schema_info = schema_info;
86 talloc_free(temp_ctx);
91 * Creates a blob from schemaInfo structure
92 * Suitable for packing schemaInfo into a blob
93 * which is to be used in DRS interface of LDB database
95 WERROR dsdb_blob_from_schema_info(const struct dsdb_schema_info *schema_info,
96 TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
98 enum ndr_err_code ndr_err;
99 struct schemaInfoBlob schema_info_blob;
101 if (schema_info->revision < 1) {
102 return WERR_INVALID_PARAMETER;
105 schema_info_blob.marker = 0xFF;
106 schema_info_blob.revision = schema_info->revision;
107 schema_info_blob.invocation_id = schema_info->invocation_id;
109 ndr_err = ndr_push_struct_blob(blob, mem_ctx,
110 lp_iconv_convenience(NULL), &schema_info_blob,
111 (ndr_push_flags_fn_t)ndr_push_schemaInfoBlob);
112 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
113 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
114 return ntstatus_to_werror(nt_status);
122 * Reads schema_info structure from schemaInfo
123 * attribute on SCHEMA partition
125 * @param dsdb_flags DSDB_FLAG_... flag of 0
127 WERROR dsdb_module_schema_info_blob_read(struct ldb_module *ldb_module,
129 TALLOC_CTX *mem_ctx, DATA_BLOB *schema_info_blob)
132 const struct ldb_val *blob_val;
133 struct ldb_dn *schema_dn;
134 struct ldb_result *schema_res = NULL;
135 static const char *schema_attrs[] = {
140 schema_dn = samdb_schema_dn(ldb_module_get_ctx(ldb_module));
142 DEBUG(0,("dsdb_module_schema_info_blob_read: no schema dn present!\n"));
143 return WERR_INTERNAL_DB_CORRUPTION;
146 ldb_err = dsdb_module_search(ldb_module, mem_ctx, &schema_res, schema_dn,
147 LDB_SCOPE_BASE, schema_attrs, dsdb_flags, NULL);
148 if (ldb_err == LDB_ERR_NO_SUCH_OBJECT) {
149 DEBUG(0,("dsdb_module_schema_info_blob_read: Schema DN not found!\n"));
150 talloc_free(schema_res);
151 return WERR_INTERNAL_DB_CORRUPTION;
152 } else if (ldb_err != LDB_SUCCESS) {
153 DEBUG(0,("dsdb_module_schema_info_blob_read: failed to find schemaInfo attribute\n"));
154 talloc_free(schema_res);
155 return WERR_INTERNAL_DB_CORRUPTION;
158 blob_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo");
160 DEBUG(0,("dsdb_module_schema_info_blob_read: no schemaInfo attribute found\n"));
161 talloc_free(schema_res);
162 return WERR_DS_NO_ATTRIBUTE_OR_VALUE;
165 /* transfer .data ownership to mem_ctx */
166 schema_info_blob->length = blob_val->length;
167 schema_info_blob->data = talloc_steal(mem_ctx, blob_val->data);
169 talloc_free(schema_res);
175 * Pepares ldb_msg to be used for updating schemaInfo value in DB
177 static WERROR _dsdb_schema_info_write_prepare(struct ldb_context *ldb,
178 DATA_BLOB *schema_info_blob,
180 struct ldb_message **_msg)
183 struct ldb_message *msg;
184 struct ldb_dn *schema_dn;
185 struct ldb_message_element *return_el;
187 schema_dn = samdb_schema_dn(ldb);
189 DEBUG(0,("_dsdb_schema_info_write_prepare: no schema dn present\n"));
190 return WERR_INTERNAL_DB_CORRUPTION;
193 /* prepare ldb_msg to update schemaInfo */
194 msg = ldb_msg_new(mem_ctx);
195 W_ERROR_HAVE_NO_MEMORY(msg);
198 ldb_err = ldb_msg_add_value(msg, "schemaInfo", schema_info_blob, &return_el);
200 DEBUG(0,("_dsdb_schema_info_write_prepare: ldb_msg_add_value failed - %s\n",
201 ldb_strerror(ldb_err)));
203 return WERR_INTERNAL_ERROR;
206 /* mark schemaInfo element for replacement */
207 return_el->flags = LDB_FLAG_MOD_REPLACE;
215 * Writes schema_info structure into schemaInfo
216 * attribute on SCHEMA partition
218 * @param dsdb_flags DSDB_FLAG_... flag of 0
220 WERROR dsdb_module_schema_info_blob_write(struct ldb_module *ldb_module,
222 DATA_BLOB *schema_info_blob)
226 struct ldb_message *msg;
227 TALLOC_CTX *temp_ctx;
229 temp_ctx = talloc_new(ldb_module);
230 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
232 /* write serialized schemaInfo into LDB */
233 werr = _dsdb_schema_info_write_prepare(ldb_module_get_ctx(ldb_module),
236 if (!W_ERROR_IS_OK(werr)) {
237 talloc_free(temp_ctx);
242 ldb_err = dsdb_module_modify(ldb_module, msg, dsdb_flags | DSDB_MODIFY_PERMISSIVE);
244 talloc_free(temp_ctx);
247 DEBUG(0,("dsdb_module_schema_info_blob_write: dsdb_replace failed: %s (%s)\n",
248 ldb_strerror(ldb_err),
249 ldb_errstring(ldb_module_get_ctx(ldb_module))));
250 return WERR_INTERNAL_DB_ERROR;
258 * Reads schema_info structure from schemaInfo
259 * attribute on SCHEMA partition
261 static WERROR dsdb_module_schema_info_read(struct ldb_module *ldb_module,
264 struct dsdb_schema_info **_schema_info)
268 TALLOC_CTX *temp_ctx;
270 temp_ctx = talloc_new(mem_ctx);
271 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
273 /* read serialized schemaInfo from LDB */
274 werr = dsdb_module_schema_info_blob_read(ldb_module, dsdb_flags, temp_ctx, &ndr_blob);
275 if (!W_ERROR_IS_OK(werr)) {
276 talloc_free(temp_ctx);
280 /* convert NDR blob to dsdb_schema_info object */
281 werr = dsdb_schema_info_from_blob(&ndr_blob,
284 talloc_free(temp_ctx);
290 * Writes schema_info structure into schemaInfo
291 * attribute on SCHEMA partition
293 * @param dsdb_flags DSDB_FLAG_... flag of 0
295 static WERROR dsdb_module_schema_info_write(struct ldb_module *ldb_module,
297 const struct dsdb_schema_info *schema_info)
301 TALLOC_CTX *temp_ctx;
303 temp_ctx = talloc_new(ldb_module);
304 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
306 /* convert schema_info to a blob */
307 werr = dsdb_blob_from_schema_info(schema_info, temp_ctx, &ndr_blob);
308 if (!W_ERROR_IS_OK(werr)) {
309 talloc_free(temp_ctx);
313 /* write serialized schemaInfo into LDB */
314 werr = dsdb_module_schema_info_blob_write(ldb_module, dsdb_flags, &ndr_blob);
316 talloc_free(temp_ctx);
323 * Creates new dsdb_schema_info object using
324 * invocationId from supplied ldb
325 * @param check_invocation_id Error out if invocationId is not yet set
327 WERROR dsdb_schema_info_create(struct ldb_context *ldb, bool check_invocation_id,
328 TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info)
330 const struct GUID *invocation_id;
331 struct dsdb_schema_info *schema_info;
333 /* try to determine invocationId from ldb */
334 invocation_id = samdb_ntds_invocation_id(ldb);
335 if (check_invocation_id && !invocation_id) {
336 return WERR_INTERNAL_DB_CORRUPTION;
339 schema_info = talloc(mem_ctx, struct dsdb_schema_info);
344 schema_info->revision = 1;
346 schema_info->invocation_id = *invocation_id;
348 schema_info->invocation_id = GUID_zero();
351 *_schema_info = schema_info;
358 * Increments schemaInfo revision and save it to DB
359 * setting our invocationID in the process
360 * NOTE: this function should be called in a transaction
361 * much in the same way prefixMap update function is called
363 * @param ldb_module current module
364 * @param schema schema cache
365 * @param dsdb_flags DSDB_FLAG_... flag of 0
367 WERROR dsdb_module_schema_info_update(struct ldb_module *ldb_module,
368 struct dsdb_schema *schema,
372 const struct GUID *invocation_id;
373 struct dsdb_schema_info *schema_info;
375 TALLOC_CTX *mem_ctx = talloc_new(schema);
376 W_ERROR_HAVE_NO_MEMORY(mem_ctx);
378 invocation_id = samdb_ntds_invocation_id(ldb_module_get_ctx(ldb_module));
379 if (!invocation_id) {
380 return WERR_INTERNAL_DB_CORRUPTION;
383 werr = dsdb_module_schema_info_read(ldb_module, dsdb_flags,
384 mem_ctx, &schema_info);
385 if (!W_ERROR_IS_OK(werr)) {
386 DEBUG(0,("dsdb_module_schema_info_update: failed to reload schemaInfo - %s\n",
388 talloc_free(mem_ctx);
392 /* update schemaInfo */
393 schema_info->revision++;
394 schema_info->invocation_id = *invocation_id;
396 werr = dsdb_module_schema_info_write(ldb_module, dsdb_flags, schema_info);
397 if (!W_ERROR_IS_OK(werr)) {
398 DEBUG(0,("dsdb_module_schema_info_update: failed to save schemaInfo - %s\n",
400 talloc_free(mem_ctx);
404 /* finally, update schema_info in the cache */
405 /* TODO: update schema_info in dsdb_schema cache */
407 talloc_unlink(schema, discard_const(schema->schema_info));
408 schema->schema_info = talloc_steal(schema, schema_info);
411 talloc_free(mem_ctx);