s4/dsdb: Use default schemaInfo value when no such value is given
[metze/samba/wip.git] / source4 / dsdb / schema / schema_info_attr.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    SCHEMA::schemaInfo implementation
5
6    Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
7
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.
12
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.
17
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/>.
20 */
21
22 #include "includes.h"
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"
30
31
32 /**
33  * Creates and initializes new dsdb_schema_info blob value.
34  * Initial schemaInfo values is with:
35  *   revision = 0
36  *   invocationId = GUID_ZERO
37  */
38 WERROR dsdb_schema_info_blob_new(TALLOC_CTX *mem_ctx, DATA_BLOB *_schema_info_blob)
39 {
40         DATA_BLOB blob;
41
42         blob = data_blob_talloc_zero(mem_ctx, 21);
43         W_ERROR_HAVE_NO_MEMORY(blob.data);
44
45         /* Set the schemaInfo marker to 0xFF */
46         blob.data[0] = 0xFF;
47
48         *_schema_info_blob = blob;
49
50         return WERR_OK;
51 }
52
53
54 /**
55  * Parse schemaInfo structure from a data_blob
56  * (DATA_BLOB or ldb_val).
57  * Suitable for parsing blobs that comes from
58  * DRS interface of from LDB database
59  */
60 WERROR dsdb_schema_info_from_blob(const DATA_BLOB *blob,
61                                   TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info)
62 {
63         TALLOC_CTX *temp_ctx;
64         enum ndr_err_code ndr_err;
65         struct dsdb_schema_info *schema_info;
66         struct schemaInfoBlob schema_info_blob;
67
68         if (!blob || !blob->data) {
69                 return WERR_INVALID_PARAMETER;
70         }
71
72         if (blob->length != 21) {
73                 return WERR_INVALID_PARAMETER;
74         }
75
76         /* schemaInfo blob should start with 0xFF */
77         if (blob->data[0] != 0xFF) {
78                 return WERR_INVALID_PARAMETER;
79         }
80
81         temp_ctx = talloc_new(mem_ctx);
82         W_ERROR_HAVE_NO_MEMORY(temp_ctx);
83
84         ndr_err = ndr_pull_struct_blob_all(blob, temp_ctx,
85                                            lp_iconv_convenience(NULL), &schema_info_blob,
86                                            (ndr_pull_flags_fn_t)ndr_pull_schemaInfoBlob);
87         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
88                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
89                 talloc_free(temp_ctx);
90                 return ntstatus_to_werror(nt_status);
91         }
92
93         schema_info = talloc(mem_ctx, struct dsdb_schema_info);
94         if (!schema_info) {
95                 talloc_free(temp_ctx);
96                 return WERR_NOMEM;
97         }
98
99         /* note that we accept revision numbers of zero now - w2k8r2
100            sends a revision of zero on initial vampire */
101         schema_info->revision      = schema_info_blob.revision;
102         schema_info->invocation_id = schema_info_blob.invocation_id;
103         *_schema_info = schema_info;
104
105         talloc_free(temp_ctx);
106         return WERR_OK;
107 }
108
109 /**
110  * Creates a blob from schemaInfo structure
111  * Suitable for packing schemaInfo into a blob
112  * which is to be used in DRS interface of LDB database
113  */
114 WERROR dsdb_blob_from_schema_info(const struct dsdb_schema_info *schema_info,
115                                   TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
116 {
117         enum ndr_err_code ndr_err;
118         struct schemaInfoBlob schema_info_blob;
119
120         if (schema_info->revision < 1) {
121                 return WERR_INVALID_PARAMETER;
122         }
123
124         schema_info_blob.marker         = 0xFF;
125         schema_info_blob.revision       = schema_info->revision;
126         schema_info_blob.invocation_id  = schema_info->invocation_id;
127
128         ndr_err = ndr_push_struct_blob(blob, mem_ctx,
129                                        lp_iconv_convenience(NULL), &schema_info_blob,
130                                        (ndr_push_flags_fn_t)ndr_push_schemaInfoBlob);
131         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
132                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
133                 return ntstatus_to_werror(nt_status);
134         }
135
136         return WERR_OK;
137 }
138
139
140 /**
141  * Reads schema_info structure from schemaInfo
142  * attribute on SCHEMA partition
143  *
144  * @param dsdb_flags    DSDB_FLAG_... flag of 0
145  */
146 WERROR dsdb_module_schema_info_blob_read(struct ldb_module *ldb_module,
147                                          uint32_t dsdb_flags,
148                                          TALLOC_CTX *mem_ctx, DATA_BLOB *schema_info_blob)
149 {
150         int ldb_err;
151         const struct ldb_val *blob_val;
152         struct ldb_dn *schema_dn;
153         struct ldb_result *schema_res = NULL;
154         static const char *schema_attrs[] = {
155                 "schemaInfo",
156                 NULL
157         };
158
159         schema_dn = ldb_get_schema_basedn(ldb_module_get_ctx(ldb_module));
160         if (!schema_dn) {
161                 DEBUG(0,("dsdb_module_schema_info_blob_read: no schema dn present!\n"));
162                 return WERR_INTERNAL_DB_CORRUPTION;
163         }
164
165         ldb_err = dsdb_module_search(ldb_module, mem_ctx, &schema_res, schema_dn,
166                                      LDB_SCOPE_BASE, schema_attrs, dsdb_flags, NULL);
167         if (ldb_err == LDB_ERR_NO_SUCH_OBJECT) {
168                 DEBUG(0,("dsdb_module_schema_info_blob_read: Schema DN not found!\n"));
169                 talloc_free(schema_res);
170                 return WERR_INTERNAL_DB_CORRUPTION;
171         } else if (ldb_err != LDB_SUCCESS) {
172                 DEBUG(0,("dsdb_module_schema_info_blob_read: failed to find schemaInfo attribute\n"));
173                 talloc_free(schema_res);
174                 return WERR_INTERNAL_DB_CORRUPTION;
175         }
176
177         blob_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo");
178         if (!blob_val) {
179                 DEBUG(0,("dsdb_module_schema_info_blob_read: no schemaInfo attribute found\n"));
180                 talloc_free(schema_res);
181                 return WERR_DS_NO_ATTRIBUTE_OR_VALUE;
182         }
183
184         /* transfer .data ownership to mem_ctx */
185         schema_info_blob->length = blob_val->length;
186         schema_info_blob->data = talloc_steal(mem_ctx, blob_val->data);
187
188         talloc_free(schema_res);
189
190         return WERR_OK;
191 }
192
193 /**
194  * Pepares ldb_msg to be used for updating schemaInfo value in DB
195  */
196 static WERROR _dsdb_schema_info_write_prepare(struct ldb_context *ldb,
197                                               DATA_BLOB *schema_info_blob,
198                                               TALLOC_CTX *mem_ctx,
199                                               struct ldb_message **_msg)
200 {
201         int ldb_err;
202         struct ldb_message *msg;
203         struct ldb_dn *schema_dn;
204         struct ldb_message_element *return_el;
205
206         schema_dn = ldb_get_schema_basedn(ldb);
207         if (!schema_dn) {
208                 DEBUG(0,("_dsdb_schema_info_write_prepare: no schema dn present\n"));
209                 return WERR_INTERNAL_DB_CORRUPTION;
210         }
211
212         /* prepare ldb_msg to update schemaInfo */
213         msg = ldb_msg_new(mem_ctx);
214         W_ERROR_HAVE_NO_MEMORY(msg);
215
216         msg->dn = schema_dn;
217         ldb_err = ldb_msg_add_value(msg, "schemaInfo", schema_info_blob, &return_el);
218         if (ldb_err != 0) {
219                 DEBUG(0,("_dsdb_schema_info_write_prepare: ldb_msg_add_value failed - %s\n",
220                          ldb_strerror(ldb_err)));
221                 talloc_free(msg);
222                 return WERR_INTERNAL_ERROR;
223         }
224
225         /* mark schemaInfo element for replacement */
226         return_el->flags = LDB_FLAG_MOD_REPLACE;
227
228         *_msg = msg;
229
230         return WERR_OK;
231 }
232
233 /**
234  * Writes schema_info structure into schemaInfo
235  * attribute on SCHEMA partition
236  *
237  * @param dsdb_flags    DSDB_FLAG_... flag of 0
238  */
239 WERROR dsdb_module_schema_info_blob_write(struct ldb_module *ldb_module,
240                                           uint32_t dsdb_flags,
241                                           DATA_BLOB *schema_info_blob)
242 {
243         int ldb_err;
244         WERROR werr;
245         struct ldb_message *msg;
246         TALLOC_CTX *temp_ctx;
247
248         temp_ctx = talloc_new(ldb_module);
249         W_ERROR_HAVE_NO_MEMORY(temp_ctx);
250
251         /* write serialized schemaInfo into LDB */
252         werr = _dsdb_schema_info_write_prepare(ldb_module_get_ctx(ldb_module),
253                                                schema_info_blob,
254                                                temp_ctx, &msg);
255         if (!W_ERROR_IS_OK(werr)) {
256                 talloc_free(temp_ctx);
257                 return werr;
258         }
259
260
261         ldb_err = dsdb_module_modify(ldb_module, msg, dsdb_flags);
262
263         talloc_free(temp_ctx);
264
265         if (ldb_err != 0) {
266                 DEBUG(0,("dsdb_module_schema_info_blob_write: dsdb_replace failed: %s (%s)\n",
267                          ldb_strerror(ldb_err),
268                          ldb_errstring(ldb_module_get_ctx(ldb_module))));
269                 return WERR_INTERNAL_DB_ERROR;
270         }
271
272         return WERR_OK;
273 }
274
275
276 /**
277  * Reads schema_info structure from schemaInfo
278  * attribute on SCHEMA partition
279  */
280 static WERROR dsdb_module_schema_info_read(struct ldb_module *ldb_module,
281                                            uint32_t dsdb_flags,
282                                            TALLOC_CTX *mem_ctx,
283                                            struct dsdb_schema_info **_schema_info)
284 {
285         WERROR werr;
286         DATA_BLOB ndr_blob;
287         TALLOC_CTX *temp_ctx;
288
289         temp_ctx = talloc_new(mem_ctx);
290         W_ERROR_HAVE_NO_MEMORY(temp_ctx);
291
292         /* read serialized schemaInfo from LDB  */
293         werr = dsdb_module_schema_info_blob_read(ldb_module, dsdb_flags, temp_ctx, &ndr_blob);
294         if (!W_ERROR_IS_OK(werr)) {
295                 talloc_free(temp_ctx);
296                 return werr;
297         }
298
299         /* convert NDR blob to dsdb_schema_info object */
300         werr = dsdb_schema_info_from_blob(&ndr_blob,
301                                           mem_ctx,
302                                           _schema_info);
303         talloc_free(temp_ctx);
304
305         return werr;
306 }
307
308 /**
309  * Writes schema_info structure into schemaInfo
310  * attribute on SCHEMA partition
311  *
312  * @param dsdb_flags    DSDB_FLAG_... flag of 0
313  */
314 static WERROR dsdb_module_schema_info_write(struct ldb_module *ldb_module,
315                                             uint32_t dsdb_flags,
316                                             const struct dsdb_schema_info *schema_info)
317 {
318         WERROR werr;
319         DATA_BLOB ndr_blob;
320         TALLOC_CTX *temp_ctx;
321
322         temp_ctx = talloc_new(ldb_module);
323         W_ERROR_HAVE_NO_MEMORY(temp_ctx);
324
325         /* convert schema_info to a blob */
326         werr = dsdb_blob_from_schema_info(schema_info, temp_ctx, &ndr_blob);
327         if (!W_ERROR_IS_OK(werr)) {
328                 talloc_free(temp_ctx);
329                 return werr;
330         }
331
332         /* write serialized schemaInfo into LDB */
333         werr = dsdb_module_schema_info_blob_write(ldb_module, dsdb_flags, &ndr_blob);
334
335         talloc_free(temp_ctx);
336
337         return werr;
338 }
339
340
341 /**
342  * Creates new dsdb_schema_info object using
343  * invocationId from supplied ldb
344  * @param check_invocation_id Error out if invocationId is not yet set
345  */
346 WERROR dsdb_schema_info_create(struct ldb_context *ldb, bool check_invocation_id,
347                                TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info)
348 {
349         const struct GUID *invocation_id;
350         struct dsdb_schema_info *schema_info;
351
352         /* try to determine invocationId from ldb */
353         invocation_id = samdb_ntds_invocation_id(ldb);
354         if (check_invocation_id && !invocation_id) {
355                 return WERR_INTERNAL_DB_CORRUPTION;
356         }
357
358         schema_info = talloc(mem_ctx, struct dsdb_schema_info);
359         if (!schema_info) {
360                 return WERR_NOMEM;
361         }
362
363         schema_info->revision = 1;
364         if (invocation_id) {
365                 schema_info->invocation_id = *invocation_id;
366         } else {
367                 schema_info->invocation_id = GUID_zero();
368         }
369
370         *_schema_info = schema_info;
371
372         return WERR_OK;
373 }
374
375
376 /**
377  * Increments schemaInfo revision and save it to DB
378  * setting our invocationID in the process
379  * NOTE: this function should be called in a transaction
380  * much in the same way prefixMap update function is called
381  *
382  * @param ldb_module    current module
383  * @param schema        schema cache
384  * @param dsdb_flags    DSDB_FLAG_... flag of 0
385  */
386 WERROR dsdb_module_schema_info_update(struct ldb_module *ldb_module,
387                                       struct dsdb_schema *schema,
388                                       int dsdb_flags)
389 {
390         WERROR werr;
391         const struct GUID *invocation_id;
392         struct dsdb_schema_info *schema_info;
393
394         TALLOC_CTX *mem_ctx = talloc_new(schema);
395         W_ERROR_HAVE_NO_MEMORY(mem_ctx);
396
397         invocation_id = samdb_ntds_invocation_id(ldb_module_get_ctx(ldb_module));
398         if (!invocation_id) {
399                 return WERR_INTERNAL_DB_CORRUPTION;
400         }
401
402         werr = dsdb_module_schema_info_read(ldb_module, dsdb_flags,
403                                             mem_ctx, &schema_info);
404         if (!W_ERROR_IS_OK(werr)) {
405                 DEBUG(0,("dsdb_module_schema_info_update: failed to reload schemaInfo - %s\n",
406                          win_errstr(werr)));
407                 talloc_free(mem_ctx);
408                 return werr;
409         }
410
411         /* update schemaInfo */
412         schema_info->revision++;
413         schema_info->invocation_id = *invocation_id;
414
415         werr = dsdb_module_schema_info_write(ldb_module, dsdb_flags, schema_info);
416         if (!W_ERROR_IS_OK(werr)) {
417                 DEBUG(0,("dsdb_module_schema_info_update: failed to save schemaInfo - %s\n",
418                          win_errstr(werr)));
419                 talloc_free(mem_ctx);
420                 return werr;
421         }
422
423         /* finally, update schema_info in the cache */
424         /* TODO: update schema_info in dsdb_schema cache */
425 /*
426         talloc_unlink(schema, discard_const(schema->schema_info));
427         schema->schema_info = talloc_steal(schema, schema_info);
428 */
429
430         talloc_free(mem_ctx);
431         return WERR_OK;
432 }