Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : dsdb module schema utility functions
5 :
6 : Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
7 : Copyright (C) Andrew Tridgell 2010
8 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2010
9 :
10 : This program is free software; you can redistribute it and/or modify
11 : it under the terms of the GNU General Public License as published by
12 : the Free Software Foundation; either version 3 of the License, or
13 : (at your option) any later version.
14 :
15 : This program is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : GNU General Public License for more details.
19 :
20 : You should have received a copy of the GNU General Public License
21 : along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : #include "includes.h"
25 : #include "dsdb/common/util.h"
26 : #include "dsdb/samdb/samdb.h"
27 : #include "dsdb/samdb/ldb_modules/util.h"
28 : #include <ldb_module.h>
29 : #include "librpc/gen_ndr/ndr_drsuapi.h"
30 : #include "librpc/gen_ndr/ndr_drsblobs.h"
31 : #include "param/param.h"
32 :
33 : /**
34 : * Reads schema_info structure from schemaInfo
35 : * attribute on SCHEMA partition
36 : *
37 : * @param dsdb_flags DSDB_FLAG_... flag of 0
38 : */
39 1818 : int dsdb_module_schema_info_blob_read(struct ldb_module *ldb_module,
40 : uint32_t dsdb_flags,
41 : TALLOC_CTX *mem_ctx,
42 : struct ldb_val *schema_info_blob,
43 : struct ldb_request *parent)
44 : {
45 3 : int ldb_err;
46 3 : const struct ldb_val *blob_val;
47 3 : struct ldb_dn *schema_dn;
48 1818 : struct ldb_result *schema_res = NULL;
49 3 : static const char *schema_attrs[] = {
50 : "schemaInfo",
51 : NULL
52 : };
53 :
54 1818 : schema_dn = ldb_get_schema_basedn(ldb_module_get_ctx(ldb_module));
55 1818 : if (!schema_dn) {
56 0 : DEBUG(0,("dsdb_module_schema_info_blob_read: no schema dn present!\n"));
57 0 : return ldb_operr(ldb_module_get_ctx(ldb_module));
58 : }
59 :
60 1818 : ldb_err = dsdb_module_search(ldb_module, mem_ctx, &schema_res, schema_dn,
61 : LDB_SCOPE_BASE, schema_attrs, dsdb_flags, parent,
62 : NULL);
63 1818 : if (ldb_err == LDB_ERR_NO_SUCH_OBJECT) {
64 0 : DEBUG(0,("dsdb_module_schema_info_blob_read: Schema DN not found!\n"));
65 0 : talloc_free(schema_res);
66 0 : return ldb_err;
67 1818 : } else if (ldb_err != LDB_SUCCESS) {
68 0 : DEBUG(0,("dsdb_module_schema_info_blob_read: failed to find schemaInfo attribute\n"));
69 0 : talloc_free(schema_res);
70 0 : return ldb_err;
71 : }
72 :
73 1818 : blob_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo");
74 1818 : if (!blob_val) {
75 18 : ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module),
76 : "dsdb_module_schema_info_blob_read: no schemaInfo attribute found");
77 18 : talloc_free(schema_res);
78 18 : return LDB_ERR_NO_SUCH_ATTRIBUTE;
79 : }
80 :
81 : /* transfer .data ownership to mem_ctx */
82 1800 : schema_info_blob->length = blob_val->length;
83 1800 : schema_info_blob->data = talloc_steal(mem_ctx, blob_val->data);
84 :
85 1800 : talloc_free(schema_res);
86 :
87 1800 : return LDB_SUCCESS;
88 : }
89 :
90 : /**
91 : * Prepares ldb_msg to be used for updating schemaInfo value in DB
92 : */
93 1817 : static int dsdb_schema_info_write_prepare(struct ldb_context *ldb,
94 : struct ldb_val *schema_info_blob,
95 : TALLOC_CTX *mem_ctx,
96 : struct ldb_message **_msg)
97 : {
98 2 : int ldb_err;
99 2 : struct ldb_message *msg;
100 2 : struct ldb_dn *schema_dn;
101 2 : struct ldb_message_element *return_el;
102 :
103 1817 : schema_dn = ldb_get_schema_basedn(ldb);
104 1817 : if (!schema_dn) {
105 0 : DEBUG(0,("dsdb_schema_info_write_prepare: no schema dn present\n"));
106 0 : return ldb_operr(ldb);
107 : }
108 :
109 : /* prepare ldb_msg to update schemaInfo */
110 1817 : msg = ldb_msg_new(mem_ctx);
111 1817 : if (msg == NULL) {
112 0 : return ldb_oom(ldb);
113 : }
114 :
115 1817 : msg->dn = schema_dn;
116 1817 : ldb_err = ldb_msg_add_value(msg, "schemaInfo", schema_info_blob, &return_el);
117 1817 : if (ldb_err != 0) {
118 0 : ldb_asprintf_errstring(ldb, "dsdb_schema_info_write_prepare: ldb_msg_add_value failed - %s\n",
119 : ldb_strerror(ldb_err));
120 0 : talloc_free(msg);
121 0 : return ldb_err;
122 : }
123 :
124 : /* mark schemaInfo element for replacement */
125 1817 : return_el->flags = LDB_FLAG_MOD_REPLACE;
126 :
127 1817 : *_msg = msg;
128 :
129 1817 : return LDB_SUCCESS;
130 : }
131 :
132 :
133 :
134 : /**
135 : * Writes schema_info structure into schemaInfo
136 : * attribute on SCHEMA partition
137 : *
138 : * @param dsdb_flags DSDB_FLAG_... flag of 0
139 : */
140 1817 : int dsdb_module_schema_info_blob_write(struct ldb_module *ldb_module,
141 : uint32_t dsdb_flags,
142 : struct ldb_val *schema_info_blob,
143 : struct ldb_request *parent)
144 : {
145 2 : int ldb_err;
146 1817 : struct ldb_message *msg = NULL;
147 2 : TALLOC_CTX *temp_ctx;
148 :
149 1817 : temp_ctx = talloc_new(ldb_module);
150 1817 : if (temp_ctx == NULL) {
151 0 : return ldb_module_oom(ldb_module);
152 : }
153 :
154 : /* write serialized schemaInfo into LDB */
155 1817 : ldb_err = dsdb_schema_info_write_prepare(ldb_module_get_ctx(ldb_module),
156 : schema_info_blob,
157 : temp_ctx, &msg);
158 1817 : if (ldb_err != LDB_SUCCESS) {
159 0 : talloc_free(temp_ctx);
160 0 : return ldb_err;
161 : }
162 :
163 :
164 1817 : ldb_err = dsdb_module_modify(ldb_module, msg, dsdb_flags, parent);
165 :
166 1817 : talloc_free(temp_ctx);
167 :
168 1817 : if (ldb_err != LDB_SUCCESS) {
169 0 : ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module),
170 : "dsdb_module_schema_info_blob_write: dsdb_replace failed: %s (%s)\n",
171 : ldb_strerror(ldb_err),
172 : ldb_errstring(ldb_module_get_ctx(ldb_module)));
173 0 : return ldb_err;
174 : }
175 :
176 1815 : return LDB_SUCCESS;
177 : }
178 :
179 :
180 : /**
181 : * Reads schema_info structure from schemaInfo
182 : * attribute on SCHEMA partition
183 : */
184 1816 : static int dsdb_module_schema_info_read(struct ldb_module *ldb_module,
185 : uint32_t dsdb_flags,
186 : TALLOC_CTX *mem_ctx,
187 : struct dsdb_schema_info **_schema_info,
188 : struct ldb_request *parent)
189 : {
190 1 : int ret;
191 1 : DATA_BLOB ndr_blob;
192 1 : TALLOC_CTX *temp_ctx;
193 1 : WERROR werr;
194 :
195 1816 : temp_ctx = talloc_new(mem_ctx);
196 1816 : if (temp_ctx == NULL) {
197 0 : return ldb_module_oom(ldb_module);
198 : }
199 :
200 : /* read serialized schemaInfo from LDB */
201 1816 : ret = dsdb_module_schema_info_blob_read(ldb_module, dsdb_flags, temp_ctx, &ndr_blob, parent);
202 1816 : if (ret != LDB_SUCCESS) {
203 18 : talloc_free(temp_ctx);
204 18 : return ret;
205 : }
206 :
207 : /* convert NDR blob to dsdb_schema_info object */
208 1798 : werr = dsdb_schema_info_from_blob(&ndr_blob,
209 : mem_ctx,
210 : _schema_info);
211 1798 : talloc_free(temp_ctx);
212 :
213 1798 : if (W_ERROR_EQUAL(werr, WERR_DS_NO_ATTRIBUTE_OR_VALUE)) {
214 0 : return LDB_ERR_NO_SUCH_ATTRIBUTE;
215 : }
216 :
217 1798 : if (!W_ERROR_IS_OK(werr)) {
218 0 : ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module), __location__ ": failed to get schema_info");
219 0 : return ldb_operr(ldb_module_get_ctx(ldb_module));
220 : }
221 :
222 1797 : return LDB_SUCCESS;
223 : }
224 :
225 : /**
226 : * Writes schema_info structure into schemaInfo
227 : * attribute on SCHEMA partition
228 : *
229 : * @param dsdb_flags DSDB_FLAG_... flag of 0
230 : */
231 1816 : static int dsdb_module_schema_info_write(struct ldb_module *ldb_module,
232 : uint32_t dsdb_flags,
233 : const struct dsdb_schema_info *schema_info,
234 : struct ldb_request *parent)
235 : {
236 1 : WERROR werr;
237 1 : int ret;
238 1 : DATA_BLOB ndr_blob;
239 1 : TALLOC_CTX *temp_ctx;
240 :
241 1816 : temp_ctx = talloc_new(ldb_module);
242 1816 : if (temp_ctx == NULL) {
243 0 : return ldb_module_oom(ldb_module);
244 : }
245 :
246 : /* convert schema_info to a blob */
247 1816 : werr = dsdb_blob_from_schema_info(schema_info, temp_ctx, &ndr_blob);
248 1816 : if (!W_ERROR_IS_OK(werr)) {
249 0 : talloc_free(temp_ctx);
250 0 : ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module), __location__ ": failed to get schema_info");
251 0 : return ldb_operr(ldb_module_get_ctx(ldb_module));
252 : }
253 :
254 : /* write serialized schemaInfo into LDB */
255 1816 : ret = dsdb_module_schema_info_blob_write(ldb_module, dsdb_flags, &ndr_blob, parent);
256 :
257 1816 : talloc_free(temp_ctx);
258 :
259 1816 : return ret;
260 : }
261 :
262 :
263 : /**
264 : * Increments schemaInfo revision and save it to DB
265 : * setting our invocationID in the process
266 : * NOTE: this function should be called in a transaction
267 : * much in the same way prefixMap update function is called
268 : *
269 : * @param ldb_module current module
270 : * @param schema schema cache
271 : * @param dsdb_flags DSDB_FLAG_... flag of 0
272 : */
273 1816 : int dsdb_module_schema_info_update(struct ldb_module *ldb_module,
274 : struct dsdb_schema *schema,
275 : int dsdb_flags, struct ldb_request *parent)
276 : {
277 1 : int ret;
278 1 : const struct GUID *invocation_id;
279 1 : struct dsdb_schema_info *schema_info;
280 1 : WERROR werr;
281 1816 : TALLOC_CTX *temp_ctx = talloc_new(schema);
282 1816 : if (temp_ctx == NULL) {
283 0 : return ldb_module_oom(ldb_module);
284 : }
285 :
286 1816 : invocation_id = samdb_ntds_invocation_id(ldb_module_get_ctx(ldb_module));
287 1816 : if (!invocation_id) {
288 0 : talloc_free(temp_ctx);
289 0 : return ldb_operr(ldb_module_get_ctx(ldb_module));
290 : }
291 :
292 : /* read serialized schemaInfo from LDB */
293 1816 : ret = dsdb_module_schema_info_read(ldb_module, dsdb_flags, temp_ctx, &schema_info, parent);
294 1816 : if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
295 : /* make default value in case
296 : * we have no schemaInfo value yet */
297 18 : werr = dsdb_schema_info_new(temp_ctx, &schema_info);
298 18 : if (!W_ERROR_IS_OK(werr)) {
299 0 : talloc_free(temp_ctx);
300 0 : return ldb_module_oom(ldb_module);
301 : }
302 18 : ret = LDB_SUCCESS;
303 : }
304 1816 : if (ret != LDB_SUCCESS) {
305 0 : talloc_free(temp_ctx);
306 0 : return ret;
307 : }
308 :
309 : /* update schemaInfo */
310 1816 : schema_info->revision++;
311 1816 : schema_info->invocation_id = *invocation_id;
312 :
313 1816 : ret = dsdb_module_schema_info_write(ldb_module, dsdb_flags, schema_info, parent);
314 1816 : if (ret != LDB_SUCCESS) {
315 0 : ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module),
316 : "dsdb_module_schema_info_update: failed to save schemaInfo - %s\n",
317 : ldb_strerror(ret));
318 0 : talloc_free(temp_ctx);
319 0 : return ret;
320 : }
321 :
322 : /*
323 : * We don't update the schema->schema_info!
324 : * as that would not represent the other information
325 : * in schema->*
326 : *
327 : * We're not sure if the current transaction will go through!
328 : * E.g. schema changes are only allowed on the schema master,
329 : * otherwise they result in a UNWILLING_TO_PERFORM and a
330 : *
331 : * Note that schema might a global variable shared between
332 : * multiple ldb_contexts. With process model "single" it
333 : * means the drsuapi server also uses it.
334 : *
335 : * We keep it simple and just try to update the
336 : * stored value.
337 : *
338 : * The next schema reload will pick it up, which
339 : * then works for originating and replicated changes
340 : * in the same way.
341 : */
342 :
343 1816 : talloc_free(temp_ctx);
344 1816 : return LDB_SUCCESS;
345 : }
|