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