werror: replace WERR_INVALID_PARAM with WERR_INVALID_PARAMETER in source4/dsdb/
[metze/samba/wip.git] / source4 / dsdb / schema / schema_init.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    DSDB schema header
4    
5    Copyright (C) Stefan Metzmacher <metze@samba.org> 2006-2007
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2008
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
23 #include "includes.h"
24 #include "dsdb/samdb/samdb.h"
25 #include "dsdb/common/util.h"
26 #include <ldb_errors.h>
27 #include "../lib/util/dlinklist.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_drsuapi.h"
30 #include "librpc/gen_ndr/ndr_drsblobs.h"
31 #include "param/param.h"
32 #include <ldb_module.h>
33 #include "../lib/util/asn1.h"
34
35
36 struct dsdb_schema *dsdb_new_schema(TALLOC_CTX *mem_ctx)
37 {
38         struct dsdb_schema *schema = talloc_zero(mem_ctx, struct dsdb_schema);
39         if (!schema) {
40                 return NULL;
41         }
42
43         return schema;
44 }
45
46 struct dsdb_schema *dsdb_schema_copy_shallow(TALLOC_CTX *mem_ctx,
47                                              struct ldb_context *ldb,
48                                              const struct dsdb_schema *schema)
49 {
50         int ret;
51         struct dsdb_class *cls;
52         struct dsdb_attribute *attr;
53         struct dsdb_schema *schema_copy;
54
55         schema_copy = dsdb_new_schema(mem_ctx);
56         if (!schema_copy) {
57                 return NULL;
58         }
59
60         /* copy prexiMap & schemaInfo */
61         schema_copy->prefixmap = dsdb_schema_pfm_copy_shallow(schema_copy,
62                                                               schema->prefixmap);
63         if (!schema_copy->prefixmap) {
64                 goto failed;
65         }
66
67         schema_copy->schema_info = talloc(schema_copy, struct dsdb_schema_info);
68         if (!schema_copy->schema_info) {
69                 goto failed;
70         }
71         *schema_copy->schema_info = *schema->schema_info;
72
73         /* copy classes and attributes*/
74         for (cls = schema->classes; cls; cls = cls->next) {
75                 struct dsdb_class *class_copy = talloc_memdup(schema_copy,
76                                                               cls, sizeof(*cls));
77                 if (!class_copy) {
78                         goto failed;
79                 }
80                 DLIST_ADD(schema_copy->classes, class_copy);
81         }
82         schema_copy->num_classes = schema->num_classes;
83
84         for (attr = schema->attributes; attr; attr = attr->next) {
85                 struct dsdb_attribute *a_copy = talloc_memdup(schema_copy,
86                                                               attr, sizeof(*attr));
87                 if (!a_copy) {
88                         goto failed;
89                 }
90                 DLIST_ADD(schema_copy->attributes, a_copy);
91         }
92         schema_copy->num_attributes = schema->num_attributes;
93
94         /* rebuild indexes */
95         ret = dsdb_setup_sorted_accessors(ldb, schema_copy);
96         if (ret != LDB_SUCCESS) {
97                 goto failed;
98         }
99
100         /* leave reload_seq_number = 0 so it will be refresh ASAP */
101
102         return schema_copy;
103
104 failed:
105         talloc_free(schema_copy);
106         return NULL;
107 }
108
109
110 WERROR dsdb_load_prefixmap_from_drsuapi(struct dsdb_schema *schema,
111                                         const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
112 {
113         WERROR werr;
114         struct dsdb_schema_info *schema_info = NULL;
115         struct dsdb_schema_prefixmap *pfm = NULL;
116
117         werr = dsdb_schema_pfm_from_drsuapi_pfm(ctr, true, schema, &pfm, &schema_info);
118         W_ERROR_NOT_OK_RETURN(werr);
119
120         /* set loaded prefixMap */
121         talloc_free(schema->prefixmap);
122         schema->prefixmap = pfm;
123
124         talloc_free(schema->schema_info);
125         schema->schema_info = schema_info;
126
127         return WERR_OK;
128 }
129
130 static WERROR _dsdb_prefixmap_from_ldb_val(const struct ldb_val *pfm_ldb_val,
131                                            TALLOC_CTX *mem_ctx,
132                                            struct dsdb_schema_prefixmap **_pfm)
133 {
134         WERROR werr;
135         enum ndr_err_code ndr_err;
136         struct prefixMapBlob pfm_blob;
137
138         TALLOC_CTX *temp_ctx = talloc_new(mem_ctx);
139         W_ERROR_HAVE_NO_MEMORY(temp_ctx);
140
141         ndr_err = ndr_pull_struct_blob(pfm_ldb_val, temp_ctx,
142                                 &pfm_blob,
143                                 (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
144         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
145                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
146                 DEBUG(0,("_dsdb_prefixmap_from_ldb_val: Failed to parse prefixmap of length %u: %s\n",
147                          (unsigned int)pfm_ldb_val->length, ndr_map_error2string(ndr_err)));
148                 talloc_free(temp_ctx);
149                 return ntstatus_to_werror(nt_status);
150         }
151
152         if (pfm_blob.version != PREFIX_MAP_VERSION_DSDB) {
153                 DEBUG(0,("_dsdb_prefixmap_from_ldb_val: pfm_blob->version %u incorrect\n", (unsigned int)pfm_blob.version));
154                 talloc_free(temp_ctx);
155                 return WERR_VERSION_PARSE_ERROR;
156         }
157
158         /* call the drsuapi version */
159         werr = dsdb_schema_pfm_from_drsuapi_pfm(&pfm_blob.ctr.dsdb, false, mem_ctx, _pfm, NULL);
160         if (!W_ERROR_IS_OK(werr)) {
161                 DEBUG(0, (__location__ " dsdb_schema_pfm_from_drsuapi_pfm failed: %s\n", win_errstr(werr)));
162                 talloc_free(temp_ctx);
163                 return werr;
164         }
165
166         talloc_free(temp_ctx);
167
168         return werr;
169 }
170
171 WERROR dsdb_load_oid_mappings_ldb(struct dsdb_schema *schema,
172                                   const struct ldb_val *prefixMap,
173                                   const struct ldb_val *schemaInfo)
174 {
175         WERROR werr;
176         struct dsdb_schema_info *schema_info = NULL;
177         struct dsdb_schema_prefixmap *pfm = NULL;
178         TALLOC_CTX *mem_ctx;
179
180         /* verify schemaInfo blob is valid one */
181         if (!dsdb_schema_info_blob_is_valid(schemaInfo)) {
182                 DEBUG(0,(__location__": dsdb_schema_info_blob_is_valid() failed.\n"));
183                 return WERR_INVALID_PARAMETER;
184         }
185
186         mem_ctx = talloc_new(schema);
187         W_ERROR_HAVE_NO_MEMORY(mem_ctx);
188
189         /* fetch prefixMap */
190         werr = _dsdb_prefixmap_from_ldb_val(prefixMap,
191                                             mem_ctx, &pfm);
192         if (!W_ERROR_IS_OK(werr)) {
193                 DEBUG(0, (__location__ " _dsdb_prefixmap_from_ldb_val failed: %s\n", win_errstr(werr)));
194                 talloc_free(mem_ctx);
195                 return werr;
196         }
197
198         /* decode schema_info */
199         werr = dsdb_schema_info_from_blob(schemaInfo, mem_ctx, &schema_info);
200         if (!W_ERROR_IS_OK(werr)) {
201                 DEBUG(0, (__location__ " dsdb_schema_info_from_blob failed: %s\n", win_errstr(werr)));
202                 talloc_free(mem_ctx);
203                 return werr;
204         }
205
206         /* store prefixMap and schema_info into cached Schema */
207         talloc_free(schema->prefixmap);
208         schema->prefixmap = talloc_steal(schema, pfm);
209
210         talloc_free(schema->schema_info);
211         schema->schema_info = talloc_steal(schema, schema_info);
212
213         /* clean up locally allocated mem */
214         talloc_free(mem_ctx);
215
216         return WERR_OK;
217 }
218
219 WERROR dsdb_get_oid_mappings_drsuapi(const struct dsdb_schema *schema,
220                                      bool include_schema_info,
221                                      TALLOC_CTX *mem_ctx,
222                                      struct drsuapi_DsReplicaOIDMapping_Ctr **_ctr)
223 {
224         return dsdb_drsuapi_pfm_from_schema_pfm(schema->prefixmap,
225                                                 include_schema_info ? schema->schema_info : NULL,
226                                                 mem_ctx, _ctr);
227 }
228
229 WERROR dsdb_get_drsuapi_prefixmap_as_blob(const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr,
230                                           TALLOC_CTX *mem_ctx,
231                                           struct ldb_val *prefixMap)
232 {
233         struct prefixMapBlob pfm;
234         enum ndr_err_code ndr_err;
235         pfm.version     = PREFIX_MAP_VERSION_DSDB;
236         pfm.reserved    = 0;
237         pfm.ctr.dsdb    = *ctr;
238
239         ndr_err = ndr_push_struct_blob(prefixMap, mem_ctx, &pfm,
240                                         (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
241         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
242                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
243                 return ntstatus_to_werror(nt_status);
244         }
245         return WERR_OK;
246 }
247
248 WERROR dsdb_get_oid_mappings_ldb(const struct dsdb_schema *schema,
249                                  TALLOC_CTX *mem_ctx,
250                                  struct ldb_val *prefixMap,
251                                  struct ldb_val *schemaInfo)
252 {
253         WERROR status;
254         struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
255
256         status = dsdb_get_oid_mappings_drsuapi(schema, false, mem_ctx, &ctr);
257         W_ERROR_NOT_OK_RETURN(status);
258
259         status = dsdb_get_drsuapi_prefixmap_as_blob(ctr, mem_ctx, prefixMap);
260         talloc_free(ctr);
261         W_ERROR_NOT_OK_RETURN(status);
262
263         status = dsdb_blob_from_schema_info(schema->schema_info, mem_ctx, schemaInfo);
264         W_ERROR_NOT_OK_RETURN(status);
265
266         return WERR_OK;
267 }
268
269
270 /*
271  * this function is called from within a ldb transaction from the schema_fsmo module
272  */
273 WERROR dsdb_create_prefix_mapping(struct ldb_context *ldb, struct dsdb_schema *schema, const char *full_oid)
274 {
275         WERROR status;
276         uint32_t attid;
277         TALLOC_CTX *mem_ctx;
278         struct dsdb_schema_prefixmap *pfm;
279         struct dsdb_schema_prefixmap *orig_pfm = NULL;
280
281         mem_ctx = talloc_new(ldb);
282         W_ERROR_HAVE_NO_MEMORY(mem_ctx);
283
284         /* Read prefixes from disk*/
285         status = dsdb_read_prefixes_from_ldb(ldb, mem_ctx, &pfm);
286         if (!W_ERROR_IS_OK(status)) {
287                 DEBUG(0,("dsdb_create_prefix_mapping: dsdb_read_prefixes_from_ldb: %s\n",
288                         win_errstr(status)));
289                 talloc_free(mem_ctx);
290                 return status;
291         }
292
293         /* Check if there is a prefix for the oid in the prefixes array*/
294         status = dsdb_schema_pfm_find_oid(pfm, full_oid, NULL);
295         if (W_ERROR_IS_OK(status)) {
296                 /* prefix found*/
297                 talloc_free(mem_ctx);
298                 return status;
299         } else if (!W_ERROR_EQUAL(status, WERR_NOT_FOUND)) {
300                 /* error */
301                 DEBUG(0,("dsdb_create_prefix_mapping: dsdb_find_prefix_for_oid: %s\n",
302                         win_errstr(status)));
303                 talloc_free(mem_ctx);
304                 return status;
305         }
306
307         /* Create the new mapping for the prefix of full_oid */
308         status = dsdb_schema_pfm_make_attid(pfm, full_oid, &attid);
309         if (!W_ERROR_IS_OK(status)) {
310                 DEBUG(0,("dsdb_create_prefix_mapping: dsdb_schema_pfm_make_attid: %s\n",
311                         win_errstr(status)));
312                 talloc_free(mem_ctx);
313                 return status;
314         }
315
316         /*
317          * We temporary replcate schema->prefixmap.
318          */
319         orig_pfm = schema->prefixmap;
320         schema->prefixmap = pfm;
321
322         /* Update prefixMap in ldb*/
323         status = dsdb_write_prefixes_from_schema_to_ldb(mem_ctx, ldb, schema);
324         if (!W_ERROR_IS_OK(status)) {
325                 DEBUG(0,("dsdb_create_prefix_mapping: dsdb_write_prefixes_to_ldb: %s\n",
326                         win_errstr(status)));
327                 talloc_free(mem_ctx);
328                 return status;
329         }
330
331         DEBUG(2,(__location__ " Added prefixMap %s - now have %u prefixes\n",
332                  full_oid, schema->prefixmap->length));
333
334         /*
335          * We restore the original prefix map.
336          *
337          * The next schema reload should get an updated prefix map!
338          */
339         schema->prefixmap = orig_pfm;
340
341         talloc_free(mem_ctx);
342         return status;
343 }
344
345
346 WERROR dsdb_write_prefixes_from_schema_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
347                                               const struct dsdb_schema *schema)
348 {
349         WERROR status;
350         int ldb_ret;
351         struct ldb_message *msg;
352         struct ldb_dn *schema_dn;
353         struct prefixMapBlob pfm_blob;
354         struct ldb_val ndr_blob;
355         enum ndr_err_code ndr_err;
356         TALLOC_CTX *temp_ctx;
357         struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
358
359         schema_dn = ldb_get_schema_basedn(ldb);
360         if (!schema_dn) {
361                 DEBUG(0,("dsdb_write_prefixes_from_schema_to_ldb: no schema dn present\n"));
362                 return WERR_FOOBAR;
363         }
364
365         temp_ctx = talloc_new(mem_ctx);
366         W_ERROR_HAVE_NO_MEMORY(temp_ctx);
367
368         /* convert schema_prefixMap to prefixMap blob */
369         status = dsdb_get_oid_mappings_drsuapi(schema, false, temp_ctx, &ctr);
370         if (!W_ERROR_IS_OK(status)) {
371                 talloc_free(temp_ctx);
372                 return status;
373         }
374
375         pfm_blob.version        = PREFIX_MAP_VERSION_DSDB;
376         pfm_blob.ctr.dsdb       = *ctr;
377
378         ndr_err = ndr_push_struct_blob(&ndr_blob, temp_ctx,
379                                        &pfm_blob,
380                                        (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
381         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
382                 talloc_free(temp_ctx);
383                 return WERR_FOOBAR;
384         }
385  
386         /* write serialized prefixMap into LDB */
387         msg = ldb_msg_new(temp_ctx);
388         if (!msg) {
389                 talloc_free(temp_ctx);
390                 return WERR_NOT_ENOUGH_MEMORY;
391         }
392
393         msg->dn = schema_dn;
394         ldb_ret = ldb_msg_add_value(msg, "prefixMap", &ndr_blob, NULL);
395         if (ldb_ret != 0) {
396                 talloc_free(temp_ctx);
397                 DEBUG(0,("dsdb_write_prefixes_from_schema_to_ldb: ldb_msg_add_value failed\n"));        
398                 return WERR_NOT_ENOUGH_MEMORY;
399         }
400  
401         ldb_ret = dsdb_replace(ldb, msg, DSDB_FLAG_AS_SYSTEM);
402
403         talloc_free(temp_ctx);
404
405         if (ldb_ret != 0) {
406                 DEBUG(0,("dsdb_write_prefixes_from_schema_to_ldb: dsdb_replace failed\n"));
407                 return WERR_FOOBAR;
408         }
409  
410         return WERR_OK;
411 }
412
413 WERROR dsdb_read_prefixes_from_ldb(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct dsdb_schema_prefixmap **_pfm)
414 {
415         WERROR werr;
416         int ldb_ret;
417         const struct ldb_val *prefix_val;
418         struct ldb_dn *schema_dn;
419         struct ldb_result *schema_res = NULL;
420         static const char *schema_attrs[] = {
421                 "prefixMap",
422                 NULL
423         };
424
425         schema_dn = ldb_get_schema_basedn(ldb);
426         if (!schema_dn) {
427                 DEBUG(0,("dsdb_read_prefixes_from_ldb: no schema dn present\n"));
428                 return WERR_FOOBAR;
429         }
430
431         ldb_ret = ldb_search(ldb, mem_ctx, &schema_res, schema_dn, LDB_SCOPE_BASE, schema_attrs, NULL);
432         if (ldb_ret == LDB_ERR_NO_SUCH_OBJECT) {
433                 DEBUG(0,("dsdb_read_prefixes_from_ldb: no prefix map present\n"));
434                 talloc_free(schema_res);
435                 return WERR_FOOBAR;
436         } else if (ldb_ret != LDB_SUCCESS) {
437                 DEBUG(0,("dsdb_read_prefixes_from_ldb: failed to search the schema head\n"));
438                 talloc_free(schema_res);
439                 return WERR_FOOBAR;
440         }
441
442         prefix_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "prefixMap");
443         if (!prefix_val) {
444                 DEBUG(0,("dsdb_read_prefixes_from_ldb: no prefixMap attribute found\n"));
445                 talloc_free(schema_res);
446                 return WERR_FOOBAR;
447         }
448
449         werr = _dsdb_prefixmap_from_ldb_val(prefix_val,
450                                             mem_ctx,
451                                             _pfm);
452         talloc_free(schema_res);
453         W_ERROR_NOT_OK_RETURN(werr);
454
455         return WERR_OK;
456 }
457
458 /*
459   this will be replaced with something that looks at the right part of
460   the schema once we know where unique indexing information is hidden
461  */
462 static bool dsdb_schema_unique_attribute(const char *attr)
463 {
464         const char *attrs[] = { "objectGUID", "objectSid" , NULL };
465         unsigned int i;
466         for (i=0;attrs[i];i++) {
467                 if (ldb_attr_cmp(attr, attrs[i]) == 0) {
468                         return true;
469                 }
470         }
471         return false;
472 }
473
474
475 /*
476   setup the ldb_schema_attribute field for a dsdb_attribute
477  */
478 static int dsdb_schema_setup_ldb_schema_attribute(struct ldb_context *ldb, 
479                                                   struct dsdb_attribute *attr)
480 {
481         const char *syntax = attr->syntax->ldb_syntax;
482         const struct ldb_schema_syntax *s;
483         struct ldb_schema_attribute *a;
484
485         if (!syntax) {
486                 syntax = attr->syntax->ldap_oid;
487         }
488
489         s = ldb_samba_syntax_by_lDAPDisplayName(ldb, attr->lDAPDisplayName);
490         if (s == NULL) {
491                 s = ldb_samba_syntax_by_name(ldb, syntax);
492         }
493         if (s == NULL) {
494                 s = ldb_standard_syntax_by_name(ldb, syntax);
495         }
496
497         if (s == NULL) {
498                 return ldb_operr(ldb);
499         }
500
501         attr->ldb_schema_attribute = a = talloc(attr, struct ldb_schema_attribute);
502         if (attr->ldb_schema_attribute == NULL) {
503                 return ldb_oom(ldb);
504         }
505
506         a->name = attr->lDAPDisplayName;
507         a->flags = 0;
508         a->syntax = s;
509
510         if (dsdb_schema_unique_attribute(a->name)) {
511                 a->flags |= LDB_ATTR_FLAG_UNIQUE_INDEX;
512         }
513         if (attr->isSingleValued) {
514                 a->flags |= LDB_ATTR_FLAG_SINGLE_VALUE;
515         }
516         
517         
518         return LDB_SUCCESS;
519 }
520
521
522 #define GET_STRING_LDB(msg, attr, mem_ctx, p, elem, strict) do { \
523         const struct ldb_val *get_string_val = ldb_msg_find_ldb_val(msg, attr); \
524         if (get_string_val == NULL) { \
525                 if (strict) {                                     \
526                         d_printf("%s: %s == NULL in %s\n", __location__, attr, ldb_dn_get_linearized(msg->dn)); \
527                         return WERR_INVALID_PARAMETER;                  \
528                 } else {                                                \
529                         (p)->elem = NULL;                               \
530                 }                                                       \
531         } else {                                                        \
532                 (p)->elem = talloc_strndup(mem_ctx,                     \
533                                            (const char *)get_string_val->data, \
534                                            get_string_val->length); \
535                 if (!(p)->elem) {                                       \
536                         d_printf("%s: talloc_strndup failed for %s\n", __location__, attr); \
537                         return WERR_NOT_ENOUGH_MEMORY;                          \
538                 }                                                       \
539         }                                                               \
540 } while (0)
541
542 #define GET_STRING_LIST_LDB(msg, attr, mem_ctx, p, elem) do {   \
543         int get_string_list_counter;                                    \
544         struct ldb_message_element *get_string_list_el = ldb_msg_find_element(msg, attr); \
545         /* We may get empty attributes over the replication channel */  \
546         if (get_string_list_el == NULL || get_string_list_el->num_values == 0) {                                \
547                 (p)->elem = NULL;                                       \
548                 break;                                                  \
549         }                                                               \
550         (p)->elem = talloc_array(mem_ctx, const char *, get_string_list_el->num_values + 1); \
551         for (get_string_list_counter=0;                                 \
552              get_string_list_counter < get_string_list_el->num_values;  \
553              get_string_list_counter++) {                               \
554                 (p)->elem[get_string_list_counter] = talloc_strndup((p)->elem, \
555                                                                     (const char *)get_string_list_el->values[get_string_list_counter].data, \
556                                                                     get_string_list_el->values[get_string_list_counter].length); \
557                 if (!(p)->elem[get_string_list_counter]) {              \
558                         d_printf("%s: talloc_strndup failed for %s\n", __location__, attr); \
559                         return WERR_NOT_ENOUGH_MEMORY;                          \
560                 }                                                       \
561                 (p)->elem[get_string_list_counter+1] = NULL;            \
562         }                                                               \
563         talloc_steal(mem_ctx, (p)->elem);                               \
564 } while (0)
565
566 #define GET_BOOL_LDB(msg, attr, p, elem, strict) do { \
567         const char *str; \
568         str = ldb_msg_find_attr_as_string(msg, attr, NULL);\
569         if (str == NULL) { \
570                 if (strict) { \
571                         d_printf("%s: %s == NULL\n", __location__, attr); \
572                         return WERR_INVALID_PARAMETER; \
573                 } else { \
574                         (p)->elem = false; \
575                 } \
576         } else if (strcasecmp("TRUE", str) == 0) { \
577                 (p)->elem = true; \
578         } else if (strcasecmp("FALSE", str) == 0) { \
579                 (p)->elem = false; \
580         } else { \
581                 d_printf("%s: %s == %s\n", __location__, attr, str); \
582                 return WERR_INVALID_PARAMETER; \
583         } \
584 } while (0)
585
586 #define GET_UINT32_LDB(msg, attr, p, elem) do { \
587         (p)->elem = ldb_msg_find_attr_as_uint(msg, attr, 0);\
588 } while (0)
589
590 #define GET_UINT32_PTR_LDB(msg, attr, mem_ctx, p, elem) do {            \
591         uint64_t _v = ldb_msg_find_attr_as_uint64(msg, attr, UINT64_MAX);\
592         if (_v == UINT64_MAX) { \
593                 (p)->elem = NULL; \
594         } else if (_v > UINT32_MAX) { \
595                 d_printf("%s: %s == 0x%llX\n", __location__, \
596                          attr, (unsigned long long)_v); \
597                 return WERR_INVALID_PARAMETER; \
598         } else { \
599                 (p)->elem = talloc(mem_ctx, uint32_t); \
600                 if (!(p)->elem) { \
601                         d_printf("%s: talloc failed for %s\n", __location__, attr); \
602                         return WERR_NOT_ENOUGH_MEMORY; \
603                 } \
604                 *(p)->elem = (uint32_t)_v; \
605         } \
606 } while (0)
607
608 #define GET_GUID_LDB(msg, attr, p, elem) do { \
609         (p)->elem = samdb_result_guid(msg, attr);\
610 } while (0)
611
612 #define GET_BLOB_LDB(msg, attr, mem_ctx, p, elem) do { \
613         const struct ldb_val *_val;\
614         _val = ldb_msg_find_ldb_val(msg, attr);\
615         if (_val) {\
616                 (p)->elem = *_val;\
617                 talloc_steal(mem_ctx, (p)->elem.data);\
618         } else {\
619                 ZERO_STRUCT((p)->elem);\
620         }\
621 } while (0)
622
623 /** Create an dsdb_attribute out of ldb message, attr must be already talloced
624  */
625
626 WERROR dsdb_attribute_from_ldb(const struct dsdb_schema *schema,
627                                struct ldb_message *msg,
628                                struct dsdb_attribute *attr)
629 {
630         WERROR status;
631         if (attr == NULL) {
632                 DEBUG(0, ("%s: attr is null, it's expected not to be so\n", __location__));
633                 return WERR_INVALID_PARAMETER;
634         }
635
636         GET_STRING_LDB(msg, "cn", attr, attr, cn, false);
637
638         /*
639          * This allows for the fact that the CN attribute is not
640          * replicated over DRS, it is only replicated under the alias
641          * 'name'.
642          */
643         if (attr->cn == NULL) {
644                 GET_STRING_LDB(msg, "name", attr, attr, cn, true);
645         }
646
647         GET_STRING_LDB(msg, "lDAPDisplayName", attr, attr, lDAPDisplayName, true);
648         GET_STRING_LDB(msg, "attributeID", attr, attr, attributeID_oid, true);
649         if (!schema->prefixmap || schema->prefixmap->length == 0) {
650                 /* set an invalid value */
651                 attr->attributeID_id = DRSUAPI_ATTID_INVALID;
652         } else {
653                 status = dsdb_schema_pfm_attid_from_oid(schema->prefixmap,
654                                                     attr->attributeID_oid,
655                                                     &attr->attributeID_id);
656                 if (!W_ERROR_IS_OK(status)) {
657                         DEBUG(0,("%s: '%s': unable to map attributeID %s: %s\n",
658                                 __location__, attr->lDAPDisplayName, attr->attributeID_oid,
659                                 win_errstr(status)));
660                         return status;
661                 }
662         }
663         /* fetch msDS-IntId to be used in resolving ATTRTYP values */
664         GET_UINT32_LDB(msg, "msDS-IntId", attr, msDS_IntId);
665
666         GET_GUID_LDB(msg, "schemaIDGUID", attr, schemaIDGUID);
667         GET_UINT32_LDB(msg, "mAPIID", attr, mAPIID);
668
669         GET_GUID_LDB(msg, "attributeSecurityGUID", attr, attributeSecurityGUID);
670
671         GET_GUID_LDB(msg, "objectGUID", attr, objectGUID);
672
673         GET_UINT32_LDB(msg, "searchFlags", attr, searchFlags);
674         GET_UINT32_LDB(msg, "systemFlags", attr, systemFlags);
675         GET_BOOL_LDB(msg, "isMemberOfPartialAttributeSet", attr, isMemberOfPartialAttributeSet, false);
676         GET_UINT32_LDB(msg, "linkID", attr, linkID);
677
678         GET_STRING_LDB(msg, "attributeSyntax", attr, attr, attributeSyntax_oid, true);
679         if (!schema->prefixmap || schema->prefixmap->length == 0) {
680                 /* set an invalid value */
681                 attr->attributeSyntax_id = DRSUAPI_ATTID_INVALID;
682         } else {
683                 status = dsdb_schema_pfm_attid_from_oid(schema->prefixmap,
684                                                         attr->attributeSyntax_oid,
685                                                         &attr->attributeSyntax_id);
686                 if (!W_ERROR_IS_OK(status)) {
687                         DEBUG(0,("%s: '%s': unable to map attributeSyntax_ %s: %s\n",
688                                 __location__, attr->lDAPDisplayName, attr->attributeSyntax_oid,
689                                 win_errstr(status)));
690                         return status;
691                 }
692         }
693         GET_UINT32_LDB(msg, "oMSyntax", attr, oMSyntax);
694         GET_BLOB_LDB(msg, "oMObjectClass", attr, attr, oMObjectClass);
695
696         GET_BOOL_LDB(msg, "isSingleValued", attr, isSingleValued, true);
697         GET_UINT32_PTR_LDB(msg, "rangeLower", attr, attr, rangeLower);
698         GET_UINT32_PTR_LDB(msg, "rangeUpper", attr, attr, rangeUpper);
699         GET_BOOL_LDB(msg, "extendedCharsAllowed", attr, extendedCharsAllowed, false);
700
701         GET_UINT32_LDB(msg, "schemaFlagsEx", attr, schemaFlagsEx);
702         GET_BLOB_LDB(msg, "msDs-Schema-Extensions", attr, attr, msDs_Schema_Extensions);
703
704         GET_BOOL_LDB(msg, "showInAdvancedViewOnly", attr, showInAdvancedViewOnly, false);
705         GET_STRING_LDB(msg, "adminDisplayName", attr, attr, adminDisplayName, false);
706         GET_STRING_LDB(msg, "adminDescription", attr, attr, adminDescription, false);
707         GET_STRING_LDB(msg, "classDisplayName", attr, attr, classDisplayName, false);
708         GET_BOOL_LDB(msg, "isEphemeral", attr, isEphemeral, false);
709         GET_BOOL_LDB(msg, "isDefunct", attr, isDefunct, false);
710         GET_BOOL_LDB(msg, "systemOnly", attr, systemOnly, false);
711
712         return WERR_OK;
713 }
714
715 WERROR dsdb_set_attribute_from_ldb_dups(struct ldb_context *ldb,
716                                         struct dsdb_schema *schema,
717                                         struct ldb_message *msg,
718                                         bool checkdups)
719 {
720         WERROR status;
721         struct dsdb_attribute *attr = talloc_zero(schema, struct dsdb_attribute);
722         if (!attr) {
723                 return WERR_NOT_ENOUGH_MEMORY;
724         }
725
726         status = dsdb_attribute_from_ldb(schema, msg, attr);
727         if (!W_ERROR_IS_OK(status)) {
728                 return status;
729         }
730
731         attr->syntax = dsdb_syntax_for_attribute(attr);
732         if (!attr->syntax) {
733                 DEBUG(0,(__location__ ": Unknown schema syntax for %s\n",
734                          attr->lDAPDisplayName));
735                 return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
736         }
737
738         if (dsdb_schema_setup_ldb_schema_attribute(ldb, attr) != LDB_SUCCESS) {
739                 DEBUG(0,(__location__ ": Unknown schema syntax for %s - ldb_syntax: %s, ldap_oid: %s\n",
740                          attr->lDAPDisplayName,
741                          attr->syntax->ldb_syntax,
742                          attr->syntax->ldap_oid));
743                 return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
744         }
745
746         if (checkdups) {
747                 const struct dsdb_attribute *a2;
748                 struct dsdb_attribute **a;
749                 uint32_t i;
750
751                 a2 = dsdb_attribute_by_attributeID_id(schema,
752                                                       attr->attributeID_id);
753                 if (a2 == NULL) {
754                         goto done;
755                 }
756
757                 i = schema->attributes_to_remove_size;
758                 a = talloc_realloc(schema, schema->attributes_to_remove,
759                                    struct dsdb_attribute *, i + 1);
760                 if (a == NULL) {
761                         return WERR_NOT_ENOUGH_MEMORY;
762                 }
763                 /* Mark the old attribute as to be removed */
764                 a[i] = discard_const_p(struct dsdb_attribute, a2);
765                 schema->attributes_to_remove = a;
766                 schema->attributes_to_remove_size++;
767         }
768
769 done:
770         DLIST_ADD(schema->attributes, attr);
771         return WERR_OK;
772 }
773
774 WERROR dsdb_set_attribute_from_ldb(struct ldb_context *ldb,
775                                    struct dsdb_schema *schema,
776                                    struct ldb_message *msg)
777 {
778         return dsdb_set_attribute_from_ldb_dups(ldb, schema, msg, false);
779 }
780
781 WERROR dsdb_set_class_from_ldb_dups(struct dsdb_schema *schema,
782                                     struct ldb_message *msg,
783                                     bool checkdups)
784 {
785         WERROR status;
786         struct dsdb_class *obj = talloc_zero(schema, struct dsdb_class);
787         if (!obj) {
788                 return WERR_NOT_ENOUGH_MEMORY;
789         }
790         GET_STRING_LDB(msg, "cn", obj, obj, cn, false);
791
792         /*
793          * This allows for the fact that the CN attribute is not
794          * replicated over DRS, it is only replicated under the alias
795          * 'name'.
796          */
797         if (obj->cn == NULL) {
798                 GET_STRING_LDB(msg, "name", obj, obj, cn, true);
799         }
800
801         GET_STRING_LDB(msg, "lDAPDisplayName", obj, obj, lDAPDisplayName, true);
802         GET_STRING_LDB(msg, "governsID", obj, obj, governsID_oid, true);
803         if (!schema->prefixmap || schema->prefixmap->length == 0) {
804                 /* set an invalid value */
805                 obj->governsID_id = DRSUAPI_ATTID_INVALID;
806         } else {
807                 status = dsdb_schema_pfm_attid_from_oid(schema->prefixmap,
808                                                         obj->governsID_oid,
809                                                         &obj->governsID_id);
810                 if (!W_ERROR_IS_OK(status)) {
811                         DEBUG(0,("%s: '%s': unable to map governsID %s: %s\n",
812                                 __location__, obj->lDAPDisplayName, obj->governsID_oid,
813                                 win_errstr(status)));
814                         return status;
815                 }
816         }
817         GET_GUID_LDB(msg, "schemaIDGUID", obj, schemaIDGUID);
818         GET_GUID_LDB(msg, "objectGUID", obj, objectGUID);
819
820         GET_UINT32_LDB(msg, "objectClassCategory", obj, objectClassCategory);
821         GET_STRING_LDB(msg, "rDNAttID", obj, obj, rDNAttID, false);
822         GET_STRING_LDB(msg, "defaultObjectCategory", obj, obj, defaultObjectCategory, true);
823  
824         GET_STRING_LDB(msg, "subClassOf", obj, obj, subClassOf, true);
825
826         GET_STRING_LIST_LDB(msg, "systemAuxiliaryClass", obj, obj, systemAuxiliaryClass);
827         GET_STRING_LIST_LDB(msg, "auxiliaryClass", obj, obj, auxiliaryClass);
828
829         GET_STRING_LIST_LDB(msg, "systemMustContain", obj, obj, systemMustContain);
830         GET_STRING_LIST_LDB(msg, "systemMayContain", obj, obj, systemMayContain);
831         GET_STRING_LIST_LDB(msg, "mustContain", obj, obj, mustContain);
832         GET_STRING_LIST_LDB(msg, "mayContain", obj, obj, mayContain);
833
834         GET_STRING_LIST_LDB(msg, "systemPossSuperiors", obj, obj, systemPossSuperiors);
835         GET_STRING_LIST_LDB(msg, "possSuperiors", obj, obj, possSuperiors);
836
837         GET_STRING_LDB(msg, "defaultSecurityDescriptor", obj, obj, defaultSecurityDescriptor, false);
838
839         GET_UINT32_LDB(msg, "schemaFlagsEx", obj, schemaFlagsEx);
840         GET_UINT32_LDB(msg, "systemFlags", obj, systemFlags);
841         GET_BLOB_LDB(msg, "msDs-Schema-Extensions", obj, obj, msDs_Schema_Extensions);
842
843         GET_BOOL_LDB(msg, "showInAdvancedViewOnly", obj, showInAdvancedViewOnly, false);
844         GET_STRING_LDB(msg, "adminDisplayName", obj, obj, adminDisplayName, false);
845         GET_STRING_LDB(msg, "adminDescription", obj, obj, adminDescription, false);
846         GET_STRING_LDB(msg, "classDisplayName", obj, obj, classDisplayName, false);
847         GET_BOOL_LDB(msg, "defaultHidingValue", obj, defaultHidingValue, false);
848         GET_BOOL_LDB(msg, "isDefunct", obj, isDefunct, false);
849         GET_BOOL_LDB(msg, "systemOnly", obj, systemOnly, false);
850
851         if (checkdups) {
852                 const struct dsdb_class *c2;
853                 struct dsdb_class **c;
854                 uint32_t i;
855
856                 c2 = dsdb_class_by_governsID_id(schema, obj->governsID_id);
857                 if (c2 == NULL) {
858                         goto done;
859                 }
860
861                 i = schema->classes_to_remove_size;
862                 c = talloc_realloc(schema, schema->classes_to_remove,
863                                    struct dsdb_class *, i + 1);
864                 if (c == NULL) {
865                         return WERR_NOT_ENOUGH_MEMORY;
866                 }
867                 /* Mark the old class to be removed */
868                 c[i] = discard_const_p(struct dsdb_class, c2);
869                 schema->classes_to_remove = c;
870                 schema->classes_to_remove_size++;
871         }
872
873 done:
874         DLIST_ADD(schema->classes, obj);
875         return WERR_OK;
876 }
877
878 WERROR dsdb_set_class_from_ldb(struct dsdb_schema *schema,
879                                struct ldb_message *msg)
880 {
881         return dsdb_set_class_from_ldb_dups(schema, msg, false);
882 }
883
884 #define dsdb_oom(error_string, mem_ctx) *error_string = talloc_asprintf(mem_ctx, "dsdb out of memory at %s:%d\n", __FILE__, __LINE__)
885
886 /* 
887  Fill a DSDB schema from the ldb results provided.  This is called
888  directly when a schema must be created with a pre-initialised prefixMap
889 */
890
891 int dsdb_load_ldb_results_into_schema(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
892                                       struct dsdb_schema *schema,
893                                       struct ldb_result *attrs_class_res,
894                                       char **error_string)
895 {
896         unsigned int i;
897
898         schema->ts_last_change = 0;
899         for (i=0; i < attrs_class_res->count; i++) {
900                 WERROR status = dsdb_schema_set_el_from_ldb_msg(ldb, schema, attrs_class_res->msgs[i]);
901                 if (!W_ERROR_IS_OK(status)) {
902                         *error_string = talloc_asprintf(mem_ctx,
903                                       "dsdb_load_ldb_results_into_schema: failed to load attribute or class definition: %s:%s",
904                                       ldb_dn_get_linearized(attrs_class_res->msgs[i]->dn),
905                                       win_errstr(status));
906                         DEBUG(0,(__location__ ": %s\n", *error_string));
907                         return LDB_ERR_CONSTRAINT_VIOLATION;
908                 }
909         }
910
911         return LDB_SUCCESS;
912 }
913
914 /*
915  Create a DSDB schema from the ldb results provided.  This is called
916  directly when the schema is provisioned from an on-disk LDIF file, or
917  from dsdb_schema_from_schema_dn in schema_fsmo
918 */
919
920 int dsdb_schema_from_ldb_results(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
921                                  struct ldb_result *schema_res,
922                                  struct ldb_result *attrs_class_res,
923                                  struct dsdb_schema **schema_out,
924                                  char **error_string)
925 {
926         WERROR status;
927         const struct ldb_val *prefix_val;
928         const struct ldb_val *info_val;
929         struct ldb_val info_val_default;
930         struct dsdb_schema *schema;
931         void *lp_opaque = ldb_get_opaque(ldb, "loadparm");
932         int ret;
933
934         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
935         if (!tmp_ctx) {
936                 dsdb_oom(error_string, mem_ctx);
937                 return ldb_operr(ldb);
938         }
939
940         schema = dsdb_new_schema(tmp_ctx);
941         if (!schema) {
942                 dsdb_oom(error_string, mem_ctx);
943                 talloc_free(tmp_ctx);
944                 return ldb_operr(ldb);
945         }
946
947         if (lp_opaque) {
948                 struct loadparm_context *lp_ctx = talloc_get_type_abort(lp_opaque, struct loadparm_context);
949                 schema->fsmo.update_allowed = lpcfg_parm_bool(lp_ctx, NULL,
950                                                               "dsdb", "schema update allowed",
951                                                               false);
952         }
953
954         prefix_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "prefixMap");
955         if (!prefix_val) {
956                 *error_string = talloc_asprintf(mem_ctx, 
957                                                 "schema_fsmo_init: no prefixMap attribute found");
958                 DEBUG(0,(__location__ ": %s\n", *error_string));
959                 talloc_free(tmp_ctx);
960                 return LDB_ERR_CONSTRAINT_VIOLATION;
961         }
962         info_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo");
963         if (!info_val) {
964                 status = dsdb_schema_info_blob_new(mem_ctx, &info_val_default);
965                 if (!W_ERROR_IS_OK(status)) {
966                         *error_string = talloc_asprintf(mem_ctx,
967                                                         "schema_fsmo_init: dsdb_schema_info_blob_new() failed - %s",
968                                                         win_errstr(status));
969                         DEBUG(0,(__location__ ": %s\n", *error_string));
970                         talloc_free(tmp_ctx);
971                         return ldb_operr(ldb);
972                 }
973                 info_val = &info_val_default;
974         }
975
976         status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val);
977         if (!W_ERROR_IS_OK(status)) {
978                 *error_string = talloc_asprintf(mem_ctx, 
979                               "schema_fsmo_init: failed to load oid mappings: %s",
980                               win_errstr(status));
981                 DEBUG(0,(__location__ ": %s\n", *error_string));
982                 talloc_free(tmp_ctx);
983                 return LDB_ERR_CONSTRAINT_VIOLATION;
984         }
985
986         ret = dsdb_load_ldb_results_into_schema(mem_ctx, ldb, schema, attrs_class_res, error_string);
987         if (ret != LDB_SUCCESS) {
988                 talloc_free(tmp_ctx);
989                 return ret;
990         }
991
992         schema->fsmo.master_dn = ldb_msg_find_attr_as_dn(ldb, schema, schema_res->msgs[0], "fSMORoleOwner");
993         if (ldb_dn_compare(samdb_ntds_settings_dn(ldb, tmp_ctx), schema->fsmo.master_dn) == 0) {
994                 schema->fsmo.we_are_master = true;
995         } else {
996                 schema->fsmo.we_are_master = false;
997         }
998
999         DEBUG(5, ("schema_fsmo_init: we are master[%s] updates allowed[%s]\n",
1000                   (schema->fsmo.we_are_master?"yes":"no"),
1001                   (schema->fsmo.update_allowed?"yes":"no")));
1002
1003         *schema_out = talloc_steal(mem_ctx, schema);
1004         talloc_free(tmp_ctx);
1005         return LDB_SUCCESS;
1006 }