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 schema_info = talloc(mem_ctx, struct dsdb_schema_info);
73 talloc_free(temp_ctx);
77 /* note that we accept revision numbers of zero now - w2k8r2
78 sends a revision of zero on initial vampire */
79 schema_info->revision = schema_info_blob.revision;
80 schema_info->invocation_id = schema_info_blob.invocation_id;
81 *_schema_info = schema_info;
83 talloc_free(temp_ctx);
88 * Creates a blob from schemaInfo structure
89 * Suitable for packing schemaInfo into a blob
90 * which is to be used in DRS interface of LDB database
92 WERROR dsdb_blob_from_schema_info(const struct dsdb_schema_info *schema_info,
93 TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
95 enum ndr_err_code ndr_err;
96 struct schemaInfoBlob schema_info_blob;
98 if (schema_info->revision < 1) {
99 return WERR_INVALID_PARAMETER;
102 schema_info_blob.marker = 0xFF;
103 schema_info_blob.revision = schema_info->revision;
104 schema_info_blob.invocation_id = schema_info->invocation_id;
106 ndr_err = ndr_push_struct_blob(blob, mem_ctx,
107 lp_iconv_convenience(NULL), &schema_info_blob,
108 (ndr_push_flags_fn_t)ndr_push_schemaInfoBlob);
109 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
110 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
111 return ntstatus_to_werror(nt_status);
119 * Reads schema_info structure from schemaInfo
120 * attribute on SCHEMA partition
122 * @param dsdb_flags DSDB_FLAG_... flag of 0
124 WERROR dsdb_module_schema_info_blob_read(struct ldb_module *ldb_module,
126 TALLOC_CTX *mem_ctx, DATA_BLOB *schema_info_blob)
129 const struct ldb_val *blob_val;
130 struct ldb_dn *schema_dn;
131 struct ldb_result *schema_res = NULL;
132 static const char *schema_attrs[] = {
137 schema_dn = ldb_get_schema_basedn(ldb_module_get_ctx(ldb_module));
139 DEBUG(0,("dsdb_module_schema_info_blob_read: no schema dn present!\n"));
140 return WERR_INTERNAL_DB_CORRUPTION;
143 ldb_err = dsdb_module_search(ldb_module, mem_ctx, &schema_res, schema_dn,
144 LDB_SCOPE_BASE, schema_attrs, dsdb_flags, NULL);
145 if (ldb_err == LDB_ERR_NO_SUCH_OBJECT) {
146 DEBUG(0,("dsdb_module_schema_info_blob_read: Schema DN not found!\n"));
147 talloc_free(schema_res);
148 return WERR_INTERNAL_DB_CORRUPTION;
149 } else if (ldb_err != LDB_SUCCESS) {
150 DEBUG(0,("dsdb_module_schema_info_blob_read: failed to find schemaInfo attribute\n"));
151 talloc_free(schema_res);
152 return WERR_INTERNAL_DB_CORRUPTION;
155 blob_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo");
157 DEBUG(0,("dsdb_module_schema_info_blob_read: no schemaInfo attribute found\n"));
158 talloc_free(schema_res);
159 return WERR_DS_NO_ATTRIBUTE_OR_VALUE;
162 /* transfer .data ownership to mem_ctx */
163 schema_info_blob->length = blob_val->length;
164 schema_info_blob->data = talloc_steal(mem_ctx, blob_val->data);
166 talloc_free(schema_res);
172 * Pepares ldb_msg to be used for updating schemaInfo value in DB
174 static WERROR _dsdb_schema_info_write_prepare(struct ldb_context *ldb,
175 DATA_BLOB *schema_info_blob,
177 struct ldb_message **_msg)
180 struct ldb_message *msg;
181 struct ldb_dn *schema_dn;
182 struct ldb_message_element *return_el;
184 schema_dn = ldb_get_schema_basedn(ldb);
186 DEBUG(0,("_dsdb_schema_info_write_prepare: no schema dn present\n"));
187 return WERR_INTERNAL_DB_CORRUPTION;
190 /* prepare ldb_msg to update schemaInfo */
191 msg = ldb_msg_new(mem_ctx);
192 W_ERROR_HAVE_NO_MEMORY(msg);
195 ldb_err = ldb_msg_add_value(msg, "schemaInfo", schema_info_blob, &return_el);
197 DEBUG(0,("_dsdb_schema_info_write_prepare: ldb_msg_add_value failed - %s\n",
198 ldb_strerror(ldb_err)));
200 return WERR_INTERNAL_ERROR;
203 /* mark schemaInfo element for replacement */
204 return_el->flags = LDB_FLAG_MOD_REPLACE;
212 * Writes schema_info structure into schemaInfo
213 * attribute on SCHEMA partition
215 * @param dsdb_flags DSDB_FLAG_... flag of 0
217 WERROR dsdb_module_schema_info_blob_write(struct ldb_module *ldb_module,
219 DATA_BLOB *schema_info_blob)
223 struct ldb_message *msg;
224 TALLOC_CTX *temp_ctx;
226 temp_ctx = talloc_new(ldb_module);
227 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
229 /* write serialized schemaInfo into LDB */
230 werr = _dsdb_schema_info_write_prepare(ldb_module_get_ctx(ldb_module),
233 if (!W_ERROR_IS_OK(werr)) {
234 talloc_free(temp_ctx);
239 ldb_err = dsdb_module_modify(ldb_module, msg, dsdb_flags);
241 talloc_free(temp_ctx);
244 DEBUG(0,("dsdb_module_schema_info_blob_write: dsdb_replace failed: %s (%s)\n",
245 ldb_strerror(ldb_err),
246 ldb_errstring(ldb_module_get_ctx(ldb_module))));
247 return WERR_INTERNAL_DB_ERROR;
255 * Reads schema_info structure from schemaInfo
256 * attribute on SCHEMA partition
258 static WERROR dsdb_module_schema_info_read(struct ldb_module *ldb_module,
261 struct dsdb_schema_info **_schema_info)
265 TALLOC_CTX *temp_ctx;
267 temp_ctx = talloc_new(mem_ctx);
268 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
270 /* read serialized schemaInfo from LDB */
271 werr = dsdb_module_schema_info_blob_read(ldb_module, dsdb_flags, temp_ctx, &ndr_blob);
272 if (!W_ERROR_IS_OK(werr)) {
273 talloc_free(temp_ctx);
277 /* convert NDR blob to dsdb_schema_info object */
278 werr = dsdb_schema_info_from_blob(&ndr_blob,
281 talloc_free(temp_ctx);
287 * Writes schema_info structure into schemaInfo
288 * attribute on SCHEMA partition
290 * @param dsdb_flags DSDB_FLAG_... flag of 0
292 static WERROR dsdb_module_schema_info_write(struct ldb_module *ldb_module,
294 const struct dsdb_schema_info *schema_info)
298 TALLOC_CTX *temp_ctx;
300 temp_ctx = talloc_new(ldb_module);
301 W_ERROR_HAVE_NO_MEMORY(temp_ctx);
303 /* convert schema_info to a blob */
304 werr = dsdb_blob_from_schema_info(schema_info, temp_ctx, &ndr_blob);
305 if (!W_ERROR_IS_OK(werr)) {
306 talloc_free(temp_ctx);
310 /* write serialized schemaInfo into LDB */
311 werr = dsdb_module_schema_info_blob_write(ldb_module, dsdb_flags, &ndr_blob);
313 talloc_free(temp_ctx);
320 * Creates new dsdb_schema_info object using
321 * invocationId from supplied ldb
322 * @param check_invocation_id Error out if invocationId is not yet set
324 WERROR dsdb_schema_info_create(struct ldb_context *ldb, bool check_invocation_id,
325 TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info)
327 const struct GUID *invocation_id;
328 struct dsdb_schema_info *schema_info;
330 /* try to determine invocationId from ldb */
331 invocation_id = samdb_ntds_invocation_id(ldb);
332 if (check_invocation_id && !invocation_id) {
333 return WERR_INTERNAL_DB_CORRUPTION;
336 schema_info = talloc(mem_ctx, struct dsdb_schema_info);
341 schema_info->revision = 1;
343 schema_info->invocation_id = *invocation_id;
345 schema_info->invocation_id = GUID_zero();
348 *_schema_info = schema_info;
355 * Increments schemaInfo revision and save it to DB
356 * setting our invocationID in the process
357 * NOTE: this function should be called in a transaction
358 * much in the same way prefixMap update function is called
360 * @param ldb_module current module
361 * @param schema schema cache
362 * @param dsdb_flags DSDB_FLAG_... flag of 0
364 WERROR dsdb_module_schema_info_update(struct ldb_module *ldb_module,
365 struct dsdb_schema *schema,
369 const struct GUID *invocation_id;
370 struct dsdb_schema_info *schema_info;
372 TALLOC_CTX *mem_ctx = talloc_new(schema);
373 W_ERROR_HAVE_NO_MEMORY(mem_ctx);
375 invocation_id = samdb_ntds_invocation_id(ldb_module_get_ctx(ldb_module));
376 if (!invocation_id) {
377 return WERR_INTERNAL_DB_CORRUPTION;
380 werr = dsdb_module_schema_info_read(ldb_module, dsdb_flags,
381 mem_ctx, &schema_info);
382 if (!W_ERROR_IS_OK(werr)) {
383 DEBUG(0,("dsdb_module_schema_info_update: failed to reload schemaInfo - %s\n",
385 talloc_free(mem_ctx);
389 /* update schemaInfo */
390 schema_info->revision++;
391 schema_info->invocation_id = *invocation_id;
393 werr = dsdb_module_schema_info_write(ldb_module, dsdb_flags, schema_info);
394 if (!W_ERROR_IS_OK(werr)) {
395 DEBUG(0,("dsdb_module_schema_info_update: failed to save schemaInfo - %s\n",
397 talloc_free(mem_ctx);
401 /* finally, update schema_info in the cache */
402 /* TODO: update schema_info in dsdb_schema cache */
404 talloc_unlink(schema, discard_const(schema->schema_info));
405 schema->schema_info = talloc_steal(schema, schema_info);
408 talloc_free(mem_ctx);