s4-dsdb: pass parent request to dsdb_module_*() functions
[samba.git] / source4 / dsdb / samdb / ldb_modules / schema_util.c
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 "lib/ldb/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 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         int ldb_err;
46         const struct ldb_val *blob_val;
47         struct ldb_dn *schema_dn;
48         struct ldb_result *schema_res = NULL;
49         static const char *schema_attrs[] = {
50                 "schemaInfo",
51                 NULL
52         };
53
54         schema_dn = ldb_get_schema_basedn(ldb_module_get_ctx(ldb_module));
55         if (!schema_dn) {
56                 DEBUG(0,("dsdb_module_schema_info_blob_read: no schema dn present!\n"));
57                 return ldb_operr(ldb_module_get_ctx(ldb_module));
58         }
59
60         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         if (ldb_err == LDB_ERR_NO_SUCH_OBJECT) {
64                 DEBUG(0,("dsdb_module_schema_info_blob_read: Schema DN not found!\n"));
65                 talloc_free(schema_res);
66                 return ldb_err;
67         } else if (ldb_err != LDB_SUCCESS) {
68                 DEBUG(0,("dsdb_module_schema_info_blob_read: failed to find schemaInfo attribute\n"));
69                 talloc_free(schema_res);
70                 return ldb_err;
71         }
72
73         blob_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo");
74         if (!blob_val) {
75                 ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module),
76                                        "dsdb_module_schema_info_blob_read: no schemaInfo attribute found");
77                 talloc_free(schema_res);
78                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
79         }
80
81         /* transfer .data ownership to mem_ctx */
82         schema_info_blob->length = blob_val->length;
83         schema_info_blob->data = talloc_steal(mem_ctx, blob_val->data);
84
85         talloc_free(schema_res);
86
87         return LDB_SUCCESS;
88 }
89
90 /**
91  * Prepares ldb_msg to be used for updating schemaInfo value in DB
92  */
93 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         int ldb_err;
99         struct ldb_message *msg;
100         struct ldb_dn *schema_dn;
101         struct ldb_message_element *return_el;
102
103         schema_dn = ldb_get_schema_basedn(ldb);
104         if (!schema_dn) {
105                 DEBUG(0,("dsdb_schema_info_write_prepare: no schema dn present\n"));
106                 return ldb_operr(ldb);
107         }
108
109         /* prepare ldb_msg to update schemaInfo */
110         msg = ldb_msg_new(mem_ctx);
111         if (msg == NULL) {
112                 return ldb_oom(ldb);
113         }
114
115         msg->dn = schema_dn;
116         ldb_err = ldb_msg_add_value(msg, "schemaInfo", schema_info_blob, &return_el);
117         if (ldb_err != 0) {
118                 ldb_asprintf_errstring(ldb, "dsdb_schema_info_write_prepare: ldb_msg_add_value failed - %s\n",
119                                        ldb_strerror(ldb_err));
120                 talloc_free(msg);
121                 return ldb_err;
122         }
123
124         /* mark schemaInfo element for replacement */
125         return_el->flags = LDB_FLAG_MOD_REPLACE;
126
127         *_msg = msg;
128
129         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 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         int ldb_err;
146         struct ldb_message *msg;
147         TALLOC_CTX *temp_ctx;
148
149         temp_ctx = talloc_new(ldb_module);
150         if (temp_ctx == NULL) {
151                 return ldb_module_oom(ldb_module);
152         }
153
154         /* write serialized schemaInfo into LDB */
155         ldb_err = dsdb_schema_info_write_prepare(ldb_module_get_ctx(ldb_module),
156                                                  schema_info_blob,
157                                                  temp_ctx, &msg);
158         if (ldb_err != LDB_SUCCESS) {
159                 talloc_free(temp_ctx);
160                 return ldb_err;
161         }
162
163
164         ldb_err = dsdb_module_modify(ldb_module, msg, dsdb_flags, parent);
165
166         talloc_free(temp_ctx);
167
168         if (ldb_err != LDB_SUCCESS) {
169                 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                 return ldb_err;
174         }
175
176         return LDB_SUCCESS;
177 }
178
179
180 /**
181  * Reads schema_info structure from schemaInfo
182  * attribute on SCHEMA partition
183  */
184 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         int ret;
191         DATA_BLOB ndr_blob;
192         TALLOC_CTX *temp_ctx;
193         WERROR werr;
194
195         temp_ctx = talloc_new(mem_ctx);
196         if (temp_ctx == NULL) {
197                 return ldb_module_oom(ldb_module);
198         }
199
200         /* read serialized schemaInfo from LDB  */
201         ret = dsdb_module_schema_info_blob_read(ldb_module, dsdb_flags, temp_ctx, &ndr_blob, parent);
202         if (ret != LDB_SUCCESS) {
203                 talloc_free(temp_ctx);
204                 return ret;
205         }
206
207         /* convert NDR blob to dsdb_schema_info object */
208         werr = dsdb_schema_info_from_blob(&ndr_blob,
209                                           mem_ctx,
210                                           _schema_info);
211         talloc_free(temp_ctx);
212
213         if (W_ERROR_EQUAL(werr, WERR_DS_NO_ATTRIBUTE_OR_VALUE)) {
214                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
215         }
216
217         if (!W_ERROR_IS_OK(werr)) {
218                 ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module), __location__ ": failed to get schema_info");
219                 return ldb_operr(ldb_module_get_ctx(ldb_module));
220         }
221
222         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 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         WERROR werr;
237         int ret;
238         DATA_BLOB ndr_blob;
239         TALLOC_CTX *temp_ctx;
240
241         temp_ctx = talloc_new(ldb_module);
242         if (temp_ctx == NULL) {
243                 return ldb_module_oom(temp_ctx);
244         }
245
246         /* convert schema_info to a blob */
247         werr = dsdb_blob_from_schema_info(schema_info, temp_ctx, &ndr_blob);
248         if (!W_ERROR_IS_OK(werr)) {
249                 talloc_free(temp_ctx);
250                 ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module), __location__ ": failed to get schema_info");
251                 return ldb_operr(ldb_module_get_ctx(ldb_module));
252         }
253
254         /* write serialized schemaInfo into LDB */
255         ret = dsdb_module_schema_info_blob_write(ldb_module, dsdb_flags, &ndr_blob, parent);
256
257         talloc_free(temp_ctx);
258
259         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 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         int ret;
278         const struct GUID *invocation_id;
279         DATA_BLOB ndr_blob;
280         struct dsdb_schema_info *schema_info;
281         const char *schema_info_str;
282         WERROR werr;
283         TALLOC_CTX *temp_ctx = talloc_new(schema);
284         if (temp_ctx == NULL) {
285                 return ldb_module_oom(ldb_module);
286         }
287
288         invocation_id = samdb_ntds_invocation_id(ldb_module_get_ctx(ldb_module));
289         if (!invocation_id) {
290                 talloc_free(temp_ctx);
291                 return ldb_operr(ldb_module_get_ctx(ldb_module));
292         }
293
294         /* read serialized schemaInfo from LDB  */
295         ret = dsdb_module_schema_info_read(ldb_module, dsdb_flags, temp_ctx, &schema_info, parent);
296         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
297                 /* make default value in case
298                  * we have no schemaInfo value yet */
299                 werr = dsdb_schema_info_new(temp_ctx, &schema_info);
300                 if (!W_ERROR_IS_OK(werr)) {
301                         talloc_free(temp_ctx);
302                         return ldb_module_oom(ldb_module);
303                 }
304                 ret = LDB_SUCCESS;
305         }
306         if (ret != LDB_SUCCESS) {
307                 talloc_free(temp_ctx);
308                 return ret;
309         }
310
311         /* update schemaInfo */
312         schema_info->revision++;
313         schema_info->invocation_id = *invocation_id;
314
315         ret = dsdb_module_schema_info_write(ldb_module, dsdb_flags, schema_info, parent);
316         if (ret != LDB_SUCCESS) {
317                 ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module),
318                                        "dsdb_module_schema_info_update: failed to save schemaInfo - %s\n",
319                                        ldb_strerror(ret));
320                 talloc_free(temp_ctx);
321                 return ret;
322         }
323
324         /* finally, update schema_info in the cache */
325         werr = dsdb_blob_from_schema_info(schema_info, temp_ctx, &ndr_blob);
326         if (!W_ERROR_IS_OK(werr)) {
327                 ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module), "Failed to get schema info");
328                 talloc_free(temp_ctx);
329                 return ldb_operr(ldb_module_get_ctx(ldb_module));
330         }
331
332         schema_info_str = hex_encode_talloc(schema, ndr_blob.data, ndr_blob.length);
333         if (!schema_info_str) {
334                 talloc_free(temp_ctx);
335                 return ldb_module_oom(ldb_module);
336         }
337
338         talloc_unlink(schema, discard_const(schema->schema_info));
339         schema->schema_info = schema_info_str;
340
341         talloc_free(temp_ctx);
342         return LDB_SUCCESS;
343 }