79c0011c0c6d536798a3e9b69adffc7b4395de43
[abartlet/samba.git/.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 {
44         int ldb_err;
45         const struct ldb_val *blob_val;
46         struct ldb_dn *schema_dn;
47         struct ldb_result *schema_res = NULL;
48         static const char *schema_attrs[] = {
49                 "schemaInfo",
50                 NULL
51         };
52
53         schema_dn = ldb_get_schema_basedn(ldb_module_get_ctx(ldb_module));
54         if (!schema_dn) {
55                 DEBUG(0,("dsdb_module_schema_info_blob_read: no schema dn present!\n"));
56                 return ldb_operr(ldb_module_get_ctx(ldb_module));
57         }
58
59         ldb_err = dsdb_module_search(ldb_module, mem_ctx, &schema_res, schema_dn,
60                                      LDB_SCOPE_BASE, schema_attrs, dsdb_flags, NULL);
61         if (ldb_err == LDB_ERR_NO_SUCH_OBJECT) {
62                 DEBUG(0,("dsdb_module_schema_info_blob_read: Schema DN not found!\n"));
63                 talloc_free(schema_res);
64                 return ldb_err;
65         } else if (ldb_err != LDB_SUCCESS) {
66                 DEBUG(0,("dsdb_module_schema_info_blob_read: failed to find schemaInfo attribute\n"));
67                 talloc_free(schema_res);
68                 return ldb_err;
69         }
70
71         blob_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo");
72         if (!blob_val) {
73                 DEBUG(0,("dsdb_module_schema_info_blob_read: no schemaInfo attribute found\n"));
74                 talloc_free(schema_res);
75                 return ldb_operr(ldb_module_get_ctx(ldb_module));
76         }
77
78         /* transfer .data ownership to mem_ctx */
79         schema_info_blob->length = blob_val->length;
80         schema_info_blob->data = talloc_steal(mem_ctx, blob_val->data);
81
82         talloc_free(schema_res);
83
84         return LDB_SUCCESS;
85 }
86
87 /**
88  * Prepares ldb_msg to be used for updating schemaInfo value in DB
89  */
90 static int dsdb_schema_info_write_prepare(struct ldb_context *ldb,
91                                           struct ldb_val *schema_info_blob,
92                                           TALLOC_CTX *mem_ctx,
93                                           struct ldb_message **_msg)
94 {
95         int ldb_err;
96         struct ldb_message *msg;
97         struct ldb_dn *schema_dn;
98         struct ldb_message_element *return_el;
99
100         schema_dn = ldb_get_schema_basedn(ldb);
101         if (!schema_dn) {
102                 DEBUG(0,("dsdb_schema_info_write_prepare: no schema dn present\n"));
103                 return ldb_operr(ldb);
104         }
105
106         /* prepare ldb_msg to update schemaInfo */
107         msg = ldb_msg_new(mem_ctx);
108         if (msg == NULL) {
109                 return ldb_oom(ldb);
110         }
111
112         msg->dn = schema_dn;
113         ldb_err = ldb_msg_add_value(msg, "schemaInfo", schema_info_blob, &return_el);
114         if (ldb_err != 0) {
115                 ldb_asprintf_errstring(ldb, "dsdb_schema_info_write_prepare: ldb_msg_add_value failed - %s\n",
116                                        ldb_strerror(ldb_err));
117                 talloc_free(msg);
118                 return ldb_err;
119         }
120
121         /* mark schemaInfo element for replacement */
122         return_el->flags = LDB_FLAG_MOD_REPLACE;
123
124         *_msg = msg;
125
126         return LDB_SUCCESS;
127 }
128
129
130
131 /**
132  * Writes schema_info structure into schemaInfo
133  * attribute on SCHEMA partition
134  *
135  * @param dsdb_flags    DSDB_FLAG_... flag of 0
136  */
137 int dsdb_module_schema_info_blob_write(struct ldb_module *ldb_module,
138                                        uint32_t dsdb_flags,
139                                        struct ldb_val *schema_info_blob)
140 {
141         int ldb_err;
142         struct ldb_message *msg;
143         TALLOC_CTX *temp_ctx;
144
145         temp_ctx = talloc_new(ldb_module);
146         if (temp_ctx == NULL) {
147                 return ldb_module_oom(ldb_module);
148         }
149
150         /* write serialized schemaInfo into LDB */
151         ldb_err = dsdb_schema_info_write_prepare(ldb_module_get_ctx(ldb_module),
152                                                  schema_info_blob,
153                                                  temp_ctx, &msg);
154         if (ldb_err != LDB_SUCCESS) {
155                 talloc_free(temp_ctx);
156                 return ldb_err;
157         }
158
159
160         ldb_err = dsdb_module_modify(ldb_module, msg, dsdb_flags);
161
162         talloc_free(temp_ctx);
163
164         if (ldb_err != LDB_SUCCESS) {
165                 ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module),
166                                        "dsdb_module_schema_info_blob_write: dsdb_replace failed: %s (%s)\n",
167                                        ldb_strerror(ldb_err),
168                                        ldb_errstring(ldb_module_get_ctx(ldb_module)));
169                 return ldb_err;
170         }
171
172         return LDB_SUCCESS;
173 }
174
175
176 /**
177  * Reads schema_info structure from schemaInfo
178  * attribute on SCHEMA partition
179  */
180 static int dsdb_module_schema_info_read(struct ldb_module *ldb_module,
181                                         uint32_t dsdb_flags,
182                                         TALLOC_CTX *mem_ctx,
183                                         struct dsdb_schema_info **_schema_info)
184 {
185         int ret;
186         DATA_BLOB ndr_blob;
187         TALLOC_CTX *temp_ctx;
188         WERROR werr;
189
190         temp_ctx = talloc_new(mem_ctx);
191         if (temp_ctx == NULL) {
192                 return ldb_module_oom(ldb_module);
193         }
194
195         /* read serialized schemaInfo from LDB  */
196         ret = dsdb_module_schema_info_blob_read(ldb_module, dsdb_flags, temp_ctx, &ndr_blob);
197         if (ret != LDB_SUCCESS) {
198                 talloc_free(temp_ctx);
199                 return ret;
200         }
201
202         /* convert NDR blob to dsdb_schema_info object */
203         werr = dsdb_schema_info_from_blob(&ndr_blob,
204                                           mem_ctx,
205                                           _schema_info);
206         talloc_free(temp_ctx);
207
208         if (W_ERROR_EQUAL(werr, WERR_DS_NO_ATTRIBUTE_OR_VALUE)) {
209                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
210         }
211
212         if (!W_ERROR_IS_OK(werr)) {
213                 ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module), __location__ ": failed to get schema_info");
214                 return ldb_operr(ldb_module_get_ctx(ldb_module));
215         }
216
217         return LDB_SUCCESS;
218 }
219
220 /**
221  * Writes schema_info structure into schemaInfo
222  * attribute on SCHEMA partition
223  *
224  * @param dsdb_flags    DSDB_FLAG_... flag of 0
225  */
226 static int dsdb_module_schema_info_write(struct ldb_module *ldb_module,
227                                          uint32_t dsdb_flags,
228                                          const struct dsdb_schema_info *schema_info)
229 {
230         WERROR werr;
231         int ret;
232         DATA_BLOB ndr_blob;
233         TALLOC_CTX *temp_ctx;
234
235         temp_ctx = talloc_new(ldb_module);
236         if (temp_ctx == NULL) {
237                 return ldb_module_oom(temp_ctx);
238         }
239
240         /* convert schema_info to a blob */
241         werr = dsdb_blob_from_schema_info(schema_info, temp_ctx, &ndr_blob);
242         if (!W_ERROR_IS_OK(werr)) {
243                 talloc_free(temp_ctx);
244                 ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module), __location__ ": failed to get schema_info");
245                 return ldb_operr(ldb_module_get_ctx(ldb_module));
246         }
247
248         /* write serialized schemaInfo into LDB */
249         ret = dsdb_module_schema_info_blob_write(ldb_module, dsdb_flags, &ndr_blob);
250
251         talloc_free(temp_ctx);
252
253         return ret;
254 }
255
256
257 /**
258  * Increments schemaInfo revision and save it to DB
259  * setting our invocationID in the process
260  * NOTE: this function should be called in a transaction
261  * much in the same way prefixMap update function is called
262  *
263  * @param ldb_module    current module
264  * @param schema        schema cache
265  * @param dsdb_flags    DSDB_FLAG_... flag of 0
266  */
267 int dsdb_module_schema_info_update(struct ldb_module *ldb_module,
268                                    struct dsdb_schema *schema,
269                                    int dsdb_flags)
270 {
271         int ret;
272         const struct GUID *invocation_id;
273         DATA_BLOB ndr_blob;
274         struct dsdb_schema_info *schema_info;
275         const char *schema_info_str;
276         WERROR werr;
277         TALLOC_CTX *temp_ctx = talloc_new(schema);
278         if (temp_ctx == NULL) {
279                 return ldb_module_oom(ldb_module);
280         }
281
282         invocation_id = samdb_ntds_invocation_id(ldb_module_get_ctx(ldb_module));
283         if (!invocation_id) {
284                 talloc_free(temp_ctx);
285                 return ldb_operr(ldb_module_get_ctx(ldb_module));
286         }
287
288         /* read serialized schemaInfo from LDB  */
289         ret = dsdb_module_schema_info_read(ldb_module, dsdb_flags, temp_ctx, &schema_info);
290         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
291                 /* make default value in case
292                  * we have no schemaInfo value yet */
293                 werr = dsdb_schema_info_new(temp_ctx, &schema_info);
294                 if (!W_ERROR_IS_OK(werr)) {
295                         talloc_free(temp_ctx);
296                         return ldb_module_oom(ldb_module);
297                 }
298                 ret = LDB_SUCCESS;
299         }
300         if (ret != LDB_SUCCESS) {
301                 talloc_free(temp_ctx);
302                 return ret;
303         }
304
305         /* update schemaInfo */
306         schema_info->revision++;
307         schema_info->invocation_id = *invocation_id;
308
309         ret = dsdb_module_schema_info_write(ldb_module, dsdb_flags, schema_info);
310         if (ret != LDB_SUCCESS) {
311                 ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module),
312                                        "dsdb_module_schema_info_update: failed to save schemaInfo - %s\n",
313                                        ldb_strerror(ret));
314                 talloc_free(temp_ctx);
315                 return ret;
316         }
317
318         /* finally, update schema_info in the cache */
319         werr = dsdb_blob_from_schema_info(schema_info, temp_ctx, &ndr_blob);
320         if (!W_ERROR_IS_OK(werr)) {
321                 ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module), "Failed to get schema info");
322                 talloc_free(temp_ctx);
323                 return ldb_operr(ldb_module_get_ctx(ldb_module));
324         }
325
326         schema_info_str = hex_encode_talloc(schema, ndr_blob.data, ndr_blob.length);
327         if (!schema_info_str) {
328                 talloc_free(temp_ctx);
329                 return ldb_module_oom(ldb_module);
330         }
331
332         talloc_unlink(schema, discard_const(schema->schema_info));
333         schema->schema_info = schema_info_str;
334
335         talloc_free(temp_ctx);
336         return LDB_SUCCESS;
337 }