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