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 * Writes schema_info structure into schemaInfo
176 * attribute on SCHEMA partition
178 * @param dsdb_flags DSDB_FLAG_... flag of 0
180 WERROR dsdb_module_schema_info_blob_write(struct ldb_module *ldb_module,
182 DATA_BLOB *schema_info_blob)
185 struct ldb_message *msg;
186 struct ldb_dn *schema_dn;
187 struct ldb_message_element *return_el;
188 TALLOC_CTX *temp_ctx;
190 schema_dn = samdb_schema_dn(ldb_module_get_ctx(ldb_module));
192 DEBUG(0,("dsdb_module_schema_info_blob_write: no schema dn present\n"));
193 return WERR_INTERNAL_DB_CORRUPTION;
196 temp_ctx = talloc_new(ldb_module);
197 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
199 /* write serialized schemaInfo into LDB */
200 msg = ldb_msg_new(temp_ctx);
202 talloc_free(temp_ctx);
207 ldb_err = ldb_msg_add_value(msg, "schemaInfo", schema_info_blob, &return_el);
209 talloc_free(temp_ctx);
210 DEBUG(0,("dsdb_module_schema_info_blob_write: ldb_msg_add_value failed\n"));
214 /* mark schemaInfo element for replacement */
215 return_el->flags = LDB_FLAG_MOD_REPLACE;
217 ldb_err = dsdb_module_modify(ldb_module, msg, dsdb_flags | DSDB_MODIFY_PERMISSIVE);
219 talloc_free(temp_ctx);
222 DEBUG(0,("dsdb_module_schema_info_blob_write: dsdb_replace failed: %s (%s)\n",
223 ldb_strerror(ldb_err),
224 ldb_errstring(ldb_module_get_ctx(ldb_module))));
225 return WERR_INTERNAL_DB_ERROR;
233 * Reads schema_info structure from schemaInfo
234 * attribute on SCHEMA partition
236 static WERROR dsdb_module_schema_info_read(struct ldb_module *ldb_module,
239 struct dsdb_schema_info **_schema_info)
243 TALLOC_CTX *temp_ctx;
245 temp_ctx = talloc_new(mem_ctx);
246 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
248 /* read serialized schemaInfo from LDB */
249 werr = dsdb_module_schema_info_blob_read(ldb_module, dsdb_flags, temp_ctx, &ndr_blob);
250 if (!W_ERROR_IS_OK(werr)) {
251 talloc_free(temp_ctx);
255 /* convert NDR blob to dsdb_schema_info object */
256 werr = dsdb_schema_info_from_blob(&ndr_blob,
259 talloc_free(temp_ctx);
265 * Writes schema_info structure into schemaInfo
266 * attribute on SCHEMA partition
268 * @param dsdb_flags DSDB_FLAG_... flag of 0
270 static WERROR dsdb_module_schema_info_write(struct ldb_module *ldb_module,
272 const struct dsdb_schema_info *schema_info)
276 TALLOC_CTX *temp_ctx;
278 temp_ctx = talloc_new(ldb_module);
279 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
281 /* convert schema_info to a blob */
282 werr = dsdb_blob_from_schema_info(schema_info, temp_ctx, &ndr_blob);
283 if (!W_ERROR_IS_OK(werr)) {
284 talloc_free(temp_ctx);
288 /* write serialized schemaInfo into LDB */
289 werr = dsdb_module_schema_info_blob_write(ldb_module, dsdb_flags, &ndr_blob);
291 talloc_free(temp_ctx);
298 * Creates new dsdb_schema_info object using
299 * invocationId from supplied ldb
300 * @param check_invocation_id Error out if invocationId is not yet set
302 WERROR dsdb_schema_info_create(struct ldb_context *ldb, bool check_invocation_id,
303 TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info)
305 const struct GUID *invocation_id;
306 struct dsdb_schema_info *schema_info;
308 /* try to determine invocationId from ldb */
309 invocation_id = samdb_ntds_invocation_id(ldb);
310 if (check_invocation_id && !invocation_id) {
311 return WERR_INTERNAL_DB_CORRUPTION;
314 schema_info = talloc(mem_ctx, struct dsdb_schema_info);
319 schema_info->revision = 1;
321 schema_info->invocation_id = *invocation_id;
323 schema_info->invocation_id = GUID_zero();
326 *_schema_info = schema_info;
333 * Increments schemaInfo revision and save it to DB
334 * setting our invocationID in the process
335 * NOTE: this function should be called in a transaction
336 * much in the same way prefixMap update function is called
338 * @param ldb_module current module
339 * @param schema schema cache
340 * @param dsdb_flags DSDB_FLAG_... flag of 0
342 WERROR dsdb_module_schema_info_update(struct ldb_module *ldb_module,
343 struct dsdb_schema *schema,
347 const struct GUID *invocation_id;
348 struct dsdb_schema_info *schema_info;
350 TALLOC_CTX *mem_ctx = talloc_new(schema);
351 W_ERROR_HAVE_NO_MEMORY(mem_ctx);
353 invocation_id = samdb_ntds_invocation_id(ldb_module_get_ctx(ldb_module));
354 if (!invocation_id) {
355 return WERR_INTERNAL_DB_CORRUPTION;
358 werr = dsdb_module_schema_info_read(ldb_module, dsdb_flags,
359 mem_ctx, &schema_info);
360 if (!W_ERROR_IS_OK(werr)) {
361 DEBUG(0,("dsdb_module_schema_info_update: failed to reload schemaInfo - %s\n",
363 talloc_free(mem_ctx);
367 /* update schemaInfo */
368 schema_info->revision++;
369 schema_info->invocation_id = *invocation_id;
371 werr = dsdb_module_schema_info_write(ldb_module, dsdb_flags, schema_info);
372 if (!W_ERROR_IS_OK(werr)) {
373 DEBUG(0,("dsdb_module_schema_info_update: failed to save schemaInfo - %s\n",
375 talloc_free(mem_ctx);
379 /* finally, update schema_info in the cache */
380 /* TODO: update schema_info in dsdb_schema cache */
382 talloc_unlink(schema, discard_const(schema->schema_info));
383 schema->schema_info = talloc_steal(schema, schema_info);
386 talloc_free(mem_ctx);