a9ddbe69be7b3c911a0d5d1627c65b6d9a2d8f00
[gd/samba-autobuild/.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
6     
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20    
21 */
22
23 #include "includes.h"
24 #include "dsdb/samdb/samdb.h"
25 #include "lib/ldb/include/ldb_errors.h"
26 #include "lib/util/dlinklist.h"
27 #include "librpc/gen_ndr/ndr_misc.h"
28 #include "librpc/gen_ndr/ndr_drsuapi.h"
29 #include "librpc/gen_ndr/ndr_drsblobs.h"
30
31 WERROR dsdb_load_oid_mappings_drsuapi(struct dsdb_schema *schema, const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
32 {
33         uint32_t i,j;
34
35         schema->prefixes = talloc_array(schema, struct dsdb_schema_oid_prefix, ctr->num_mappings);
36         W_ERROR_HAVE_NO_MEMORY(schema->prefixes);
37
38         for (i=0, j=0; i < ctr->num_mappings; i++) {
39                 if (ctr->mappings[i].oid.oid == NULL) {
40                         return WERR_INVALID_PARAM;
41                 }
42
43                 if (strncasecmp(ctr->mappings[i].oid.oid, "ff", 2) == 0) {
44                         if (ctr->mappings[i].id_prefix != 0) {
45                                 return WERR_INVALID_PARAM;
46                         }
47
48                         /* the magic value should be in the last array member */
49                         if (i != (ctr->num_mappings - 1)) {
50                                 return WERR_INVALID_PARAM;
51                         }
52
53                         if (ctr->mappings[i].oid.__ndr_size != 21) {
54                                 return WERR_INVALID_PARAM;
55                         }
56
57                         schema->schema_info = talloc_strdup(schema, ctr->mappings[i].oid.oid);
58                         W_ERROR_HAVE_NO_MEMORY(schema->schema_info);
59                 } else {
60                         /* the last array member should contain the magic value not a oid */
61                         if (i == (ctr->num_mappings - 1)) {
62                                 return WERR_INVALID_PARAM;
63                         }
64
65                         schema->prefixes[j].id  = ctr->mappings[i].id_prefix<<16;
66                         schema->prefixes[j].oid = talloc_asprintf(schema->prefixes, "%s.",
67                                                                   ctr->mappings[i].oid.oid);
68                         W_ERROR_HAVE_NO_MEMORY(schema->prefixes[j].oid);
69                         schema->prefixes[j].oid_len = strlen(schema->prefixes[j].oid);
70                         j++;
71                 }
72         }
73
74         schema->num_prefixes = j;
75         return WERR_OK;
76 }
77
78 WERROR dsdb_load_oid_mappings_ldb(struct dsdb_schema *schema,
79                                   const struct ldb_val *prefixMap,
80                                   const struct ldb_val *schemaInfo)
81 {
82         WERROR status;
83         NTSTATUS nt_status;
84         struct prefixMapBlob pfm;
85         char *schema_info;
86
87         nt_status = ndr_pull_struct_blob(prefixMap, schema, &pfm,
88                                          (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
89         if (!NT_STATUS_IS_OK(nt_status)) {
90                 return ntstatus_to_werror(nt_status);
91         }
92
93         if (pfm.version != PREFIX_MAP_VERSION_DSDB) {
94                 return WERR_FOOBAR;
95         }
96
97         if (schemaInfo->length != 21 && schemaInfo->data[0] == 0xFF) {
98                 return WERR_FOOBAR;
99         }
100
101         /* append the schema info as last element */
102         pfm.ctr.dsdb.num_mappings++;
103         pfm.ctr.dsdb.mappings = talloc_realloc(schema, pfm.ctr.dsdb.mappings,
104                                                struct drsuapi_DsReplicaOIDMapping,
105                                                pfm.ctr.dsdb.num_mappings);
106         W_ERROR_HAVE_NO_MEMORY(pfm.ctr.dsdb.mappings);
107
108         schema_info = data_blob_hex_string(pfm.ctr.dsdb.mappings, schemaInfo);
109         W_ERROR_HAVE_NO_MEMORY(schema_info);
110
111         pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].id_prefix          = 0;    
112         pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].oid.__ndr_size     = schemaInfo->length;
113         pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].oid.oid            = schema_info;
114
115         /* call the drsuapi version */
116         status = dsdb_load_oid_mappings_drsuapi(schema, &pfm.ctr.dsdb);
117         talloc_free(pfm.ctr.dsdb.mappings);
118         W_ERROR_NOT_OK_RETURN(status);
119
120         return WERR_OK;
121 }
122
123 WERROR dsdb_get_oid_mappings_drsuapi(const struct dsdb_schema *schema,
124                                      bool include_schema_info,
125                                      TALLOC_CTX *mem_ctx,
126                                      struct drsuapi_DsReplicaOIDMapping_Ctr **_ctr)
127 {
128         struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
129         uint32_t i;
130
131         ctr = talloc(mem_ctx, struct drsuapi_DsReplicaOIDMapping_Ctr);
132         W_ERROR_HAVE_NO_MEMORY(ctr);
133
134         ctr->num_mappings       = schema->num_prefixes;
135         if (include_schema_info) ctr->num_mappings++;
136         ctr->mappings = talloc_array(schema, struct drsuapi_DsReplicaOIDMapping, ctr->num_mappings);
137         W_ERROR_HAVE_NO_MEMORY(ctr->mappings);
138
139         for (i=0; i < schema->num_prefixes; i++) {
140                 ctr->mappings[i].id_prefix      = schema->prefixes[i].id>>16;
141                 ctr->mappings[i].oid.oid        = talloc_strndup(ctr->mappings,
142                                                                  schema->prefixes[i].oid,
143                                                                  schema->prefixes[i].oid_len - 1);
144                 W_ERROR_HAVE_NO_MEMORY(ctr->mappings[i].oid.oid);
145         }
146
147         if (include_schema_info) {
148                 ctr->mappings[i].id_prefix      = 0;
149                 ctr->mappings[i].oid.oid        = talloc_strdup(ctr->mappings,
150                                                                 schema->schema_info);
151                 W_ERROR_HAVE_NO_MEMORY(ctr->mappings[i].oid.oid);
152         }
153
154         *_ctr = ctr;
155         return WERR_OK;
156 }
157
158 WERROR dsdb_get_oid_mappings_ldb(const struct dsdb_schema *schema,
159                                  TALLOC_CTX *mem_ctx,
160                                  struct ldb_val *prefixMap,
161                                  struct ldb_val *schemaInfo)
162 {
163         WERROR status;
164         NTSTATUS nt_status;
165         struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
166         struct prefixMapBlob pfm;
167
168         status = dsdb_get_oid_mappings_drsuapi(schema, false, mem_ctx, &ctr);
169         W_ERROR_NOT_OK_RETURN(status);
170
171         pfm.version     = PREFIX_MAP_VERSION_DSDB;
172         pfm.reserved    = 0;
173         pfm.ctr.dsdb    = *ctr;
174
175         nt_status = ndr_push_struct_blob(prefixMap, mem_ctx, &pfm,
176                                          (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
177         talloc_free(ctr);
178         if (!NT_STATUS_IS_OK(nt_status)) {
179                 return ntstatus_to_werror(nt_status);
180         }
181
182         *schemaInfo = strhex_to_data_blob(schema->schema_info);
183         W_ERROR_HAVE_NO_MEMORY(schemaInfo->data);
184         talloc_steal(mem_ctx, schemaInfo->data);
185
186         return WERR_OK;
187 }
188
189 WERROR dsdb_verify_oid_mappings_drsuapi(const struct dsdb_schema *schema, const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
190 {
191         uint32_t i,j;
192
193         for (i=0; i < ctr->num_mappings; i++) {
194                 if (ctr->mappings[i].oid.oid == NULL) {
195                         return WERR_INVALID_PARAM;
196                 }
197
198                 if (strncasecmp(ctr->mappings[i].oid.oid, "ff", 2) == 0) {
199                         if (ctr->mappings[i].id_prefix != 0) {
200                                 return WERR_INVALID_PARAM;
201                         }
202
203                         /* the magic value should be in the last array member */
204                         if (i != (ctr->num_mappings - 1)) {
205                                 return WERR_INVALID_PARAM;
206                         }
207
208                         if (ctr->mappings[i].oid.__ndr_size != 21) {
209                                 return WERR_INVALID_PARAM;
210                         }
211
212                         if (strcasecmp(schema->schema_info, ctr->mappings[i].oid.oid) != 0) {
213                                 return WERR_DS_DRA_SCHEMA_MISMATCH;
214                         }
215                 } else {
216                         /* the last array member should contain the magic value not a oid */
217                         if (i == (ctr->num_mappings - 1)) {
218                                 return WERR_INVALID_PARAM;
219                         }
220
221                         for (j=0; j < schema->num_prefixes; j++) {
222                                 size_t oid_len;
223                                 if (schema->prefixes[j].id != (ctr->mappings[i].id_prefix<<16)) {
224                                         continue;
225                                 }
226
227                                 oid_len = strlen(ctr->mappings[i].oid.oid);
228
229                                 if (oid_len != (schema->prefixes[j].oid_len - 1)) {
230                                         return WERR_DS_DRA_SCHEMA_MISMATCH;
231                                 }
232
233                                 if (strncmp(ctr->mappings[i].oid.oid, schema->prefixes[j].oid, oid_len) != 0) {
234                                         return WERR_DS_DRA_SCHEMA_MISMATCH;                             
235                                 }
236
237                                 break;
238                         }
239
240                         if (j == schema->num_prefixes) {
241                                 return WERR_DS_DRA_SCHEMA_MISMATCH;                             
242                         }
243                 }
244         }
245
246         return WERR_OK;
247 }
248
249 WERROR dsdb_map_oid2int(const struct dsdb_schema *schema, const char *in, uint32_t *out)
250 {
251         uint32_t i;
252
253         for (i=0; i < schema->num_prefixes; i++) {
254                 const char *val_str;
255                 char *end_str;
256                 unsigned val;
257
258                 if (strncmp(schema->prefixes[i].oid, in, schema->prefixes[i].oid_len) != 0) {
259                         continue;
260                 }
261
262                 val_str = in + schema->prefixes[i].oid_len;
263                 end_str = NULL;
264                 errno = 0;
265
266                 if (val_str[0] == '\0') {
267                         return WERR_INVALID_PARAM;
268                 }
269
270                 /* two '.' chars are invalid */
271                 if (val_str[0] == '.') {
272                         return WERR_INVALID_PARAM;
273                 }
274
275                 val = strtoul(val_str, &end_str, 10);
276                 if (end_str[0] == '.' && end_str[1] != '\0') {
277                         /*
278                          * if it's a '.' and not the last char
279                          * then maybe an other mapping apply
280                          */
281                         continue;
282                 } else if (end_str[0] != '\0') {
283                         return WERR_INVALID_PARAM;
284                 } else if (val > 0xFFFF) {
285                         return WERR_INVALID_PARAM;
286                 }
287
288                 *out = schema->prefixes[i].id | val;
289                 return WERR_OK;
290         }
291
292         return WERR_DS_NO_MSDS_INTID;
293 }
294
295 WERROR dsdb_map_int2oid(const struct dsdb_schema *schema, uint32_t in, TALLOC_CTX *mem_ctx, const char **out)
296 {
297         uint32_t i;
298
299         for (i=0; i < schema->num_prefixes; i++) {
300                 const char *val;
301                 if (schema->prefixes[i].id != (in & 0xFFFF0000)) {
302                         continue;
303                 }
304
305                 val = talloc_asprintf(mem_ctx, "%s%u",
306                                       schema->prefixes[i].oid,
307                                       in & 0xFFFF);
308                 W_ERROR_HAVE_NO_MEMORY(val);
309
310                 *out = val;
311                 return WERR_OK;
312         }
313
314         return WERR_DS_NO_MSDS_INTID;
315 }
316
317 #define GET_STRING_LDB(msg, attr, mem_ctx, p, elem, strict) do { \
318         (p)->elem = samdb_result_string(msg, attr, NULL);\
319         if (strict && (p)->elem == NULL) { \
320                 d_printf("%s: %s == NULL\n", __location__, attr); \
321                 return WERR_INVALID_PARAM; \
322         } \
323         talloc_steal(mem_ctx, (p)->elem); \
324 } while (0)
325
326 #define GET_STRING_LIST_LDB(msg, attr, mem_ctx, p, elem, strict) do {   \
327         int get_string_list_counter;                                    \
328         struct ldb_message_element *get_string_list_el = ldb_msg_find_element(msg, attr); \
329         if (get_string_list_el == NULL) {                               \
330                 if (strict) {                                           \
331                         d_printf("%s: %s == NULL\n", __location__, attr); \
332                         return WERR_INVALID_PARAM;                      \
333                 } else {                                                \
334                         (p)->elem = NULL;                               \
335                         break;                                          \
336                 }                                                       \
337         }                                                               \
338         (p)->elem = talloc_array(mem_ctx, const char *, get_string_list_el->num_values + 1); \
339         for (get_string_list_counter=0;                                 \
340              get_string_list_counter < get_string_list_el->num_values;  \
341              get_string_list_counter++) {                               \
342                 (p)->elem[get_string_list_counter] = talloc_strndup((p)->elem, \
343                                                                     (const char *)get_string_list_el->values[get_string_list_counter].data, \
344                                                                     get_string_list_el->values[get_string_list_counter].length); \
345                 if (!(p)->elem[get_string_list_counter]) {              \
346                         d_printf("%s: talloc_strndup failed for %s\n", __location__, attr); \
347                         return WERR_NOMEM;                              \
348                 }                                                       \
349                 (p)->elem[get_string_list_counter+1] = NULL;            \
350         }                                                               \
351         talloc_steal(mem_ctx, (p)->elem);                               \
352 } while (0)
353
354 #define GET_BOOL_LDB(msg, attr, p, elem, strict) do { \
355         const char *str; \
356         str = samdb_result_string(msg, attr, NULL);\
357         if (str == NULL) { \
358                 if (strict) { \
359                         d_printf("%s: %s == NULL\n", __location__, attr); \
360                         return WERR_INVALID_PARAM; \
361                 } else { \
362                         (p)->elem = False; \
363                 } \
364         } else if (strcasecmp("TRUE", str) == 0) { \
365                 (p)->elem = True; \
366         } else if (strcasecmp("FALSE", str) == 0) { \
367                 (p)->elem = False; \
368         } else { \
369                 d_printf("%s: %s == %s\n", __location__, attr, str); \
370                 return WERR_INVALID_PARAM; \
371         } \
372 } while (0)
373
374 #define GET_UINT32_LDB(msg, attr, p, elem) do { \
375         (p)->elem = samdb_result_uint(msg, attr, 0);\
376 } while (0)
377
378 #define GET_GUID_LDB(msg, attr, p, elem) do { \
379         (p)->elem = samdb_result_guid(msg, attr);\
380 } while (0)
381
382 #define GET_BLOB_LDB(msg, attr, mem_ctx, p, elem) do { \
383         const struct ldb_val *_val;\
384         _val = ldb_msg_find_ldb_val(msg, attr);\
385         if (_val) {\
386                 (p)->elem = *_val;\
387                 talloc_steal(mem_ctx, (p)->elem.data);\
388         } else {\
389                 ZERO_STRUCT((p)->elem);\
390         }\
391 } while (0)
392
393 WERROR dsdb_attribute_from_ldb(const struct dsdb_schema *schema,
394                                struct ldb_message *msg,
395                                TALLOC_CTX *mem_ctx,
396                                struct dsdb_attribute *attr)
397 {
398         WERROR status;
399
400         GET_STRING_LDB(msg, "cn", mem_ctx, attr, cn, False);
401         GET_STRING_LDB(msg, "lDAPDisplayName", mem_ctx, attr, lDAPDisplayName, True);
402         GET_STRING_LDB(msg, "attributeID", mem_ctx, attr, attributeID_oid, True);
403         if (schema->num_prefixes == 0) {
404                 /* set an invalid value */
405                 attr->attributeID_id = 0xFFFFFFFF;
406         } else {
407                 status = dsdb_map_oid2int(schema, attr->attributeID_oid, &attr->attributeID_id);
408                 if (!W_ERROR_IS_OK(status)) {
409                         DEBUG(0,("%s: '%s': unable to map attributeID %s: %s\n",
410                                 __location__, attr->lDAPDisplayName, attr->attributeID_oid,
411                                 win_errstr(status)));
412                         return status;
413                 }
414         }
415         GET_GUID_LDB(msg, "schemaIDGUID", attr, schemaIDGUID);
416         GET_UINT32_LDB(msg, "mAPIID", attr, mAPIID);
417
418         GET_GUID_LDB(msg, "attributeSecurityGUID", attr, attributeSecurityGUID);
419
420         GET_UINT32_LDB(msg, "searchFlags", attr, searchFlags);
421         GET_UINT32_LDB(msg, "systemFlags", attr, systemFlags);
422         GET_BOOL_LDB(msg, "isMemberOfPartialAttributeSet", attr, isMemberOfPartialAttributeSet, False);
423         GET_UINT32_LDB(msg, "linkID", attr, linkID);
424
425         GET_STRING_LDB(msg, "attributeSyntax", mem_ctx, attr, attributeSyntax_oid, True);
426         if (schema->num_prefixes == 0) {
427                 /* set an invalid value */
428                 attr->attributeSyntax_id = 0xFFFFFFFF;
429         } else {
430                 status = dsdb_map_oid2int(schema, attr->attributeSyntax_oid, &attr->attributeSyntax_id);
431                 if (!W_ERROR_IS_OK(status)) {
432                         DEBUG(0,("%s: '%s': unable to map attributeSyntax_ %s: %s\n",
433                                 __location__, attr->lDAPDisplayName, attr->attributeSyntax_oid,
434                                 win_errstr(status)));
435                         return status;
436                 }
437         }
438         GET_UINT32_LDB(msg, "oMSyntax", attr, oMSyntax);
439         GET_BLOB_LDB(msg, "oMObjectClass", mem_ctx, attr, oMObjectClass);
440
441         GET_BOOL_LDB(msg, "isSingleValued", attr, isSingleValued, True);
442         GET_UINT32_LDB(msg, "rangeLower", attr, rangeLower);
443         GET_UINT32_LDB(msg, "rangeUpper", attr, rangeUpper);
444         GET_BOOL_LDB(msg, "extendedCharsAllowed", attr, extendedCharsAllowed, False);
445
446         GET_UINT32_LDB(msg, "schemaFlagsEx", attr, schemaFlagsEx);
447         GET_BLOB_LDB(msg, "msDs-Schema-Extensions", mem_ctx, attr, msDs_Schema_Extensions);
448
449         GET_BOOL_LDB(msg, "showInAdvancedViewOnly", attr, showInAdvancedViewOnly, False);
450         GET_STRING_LDB(msg, "adminDisplayName", mem_ctx, attr, adminDisplayName, False);
451         GET_STRING_LDB(msg, "adminDescription", mem_ctx, attr, adminDescription, False);
452         GET_STRING_LDB(msg, "classDisplayName", mem_ctx, attr, classDisplayName, False);
453         GET_BOOL_LDB(msg, "isEphemeral", attr, isEphemeral, False);
454         GET_BOOL_LDB(msg, "isDefunct", attr, isDefunct, False);
455         GET_BOOL_LDB(msg, "systemOnly", attr, systemOnly, False);
456
457         attr->syntax = dsdb_syntax_for_attribute(attr);
458         if (!attr->syntax) {
459                 return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
460         }
461
462         return WERR_OK;
463 }
464
465 WERROR dsdb_class_from_ldb(const struct dsdb_schema *schema,
466                            struct ldb_message *msg,
467                            TALLOC_CTX *mem_ctx,
468                            struct dsdb_class *obj)
469 {
470         WERROR status;
471
472         GET_STRING_LDB(msg, "cn", mem_ctx, obj, cn, False);
473         GET_STRING_LDB(msg, "lDAPDisplayName", mem_ctx, obj, lDAPDisplayName, True);
474         GET_STRING_LDB(msg, "governsID", mem_ctx, obj, governsID_oid, True);
475         if (schema->num_prefixes == 0) {
476                 /* set an invalid value */
477                 obj->governsID_id = 0xFFFFFFFF;
478         } else {
479                 status = dsdb_map_oid2int(schema, obj->governsID_oid, &obj->governsID_id);
480                 if (!W_ERROR_IS_OK(status)) {
481                         DEBUG(0,("%s: '%s': unable to map governsID %s: %s\n",
482                                 __location__, obj->lDAPDisplayName, obj->governsID_oid,
483                                 win_errstr(status)));
484                         return status;
485                 }
486         }
487         GET_GUID_LDB(msg, "schemaIDGUID", obj, schemaIDGUID);
488
489         GET_UINT32_LDB(msg, "objectClassCategory", obj, objectClassCategory);
490         GET_STRING_LDB(msg, "rDNAttID", mem_ctx, obj, rDNAttID, False);
491         GET_STRING_LDB(msg, "defaultObjectCategory", mem_ctx, obj, defaultObjectCategory, True);
492  
493         GET_STRING_LDB(msg, "subClassOf", mem_ctx, obj, subClassOf, True);
494
495         obj->systemAuxiliaryClass       = NULL;
496         obj->systemPossSuperiors        = NULL;
497
498         obj->auxiliaryClass             = NULL;
499         obj->possSuperiors              = NULL;
500
501         GET_STRING_LIST_LDB(msg, "systemMustContain", mem_ctx, obj, systemMustContain, False);
502         GET_STRING_LIST_LDB(msg, "systemMayContain", mem_ctx, obj, systemMayContain, False);
503         GET_STRING_LIST_LDB(msg, "mustContain", mem_ctx, obj, mustContain, False);
504         GET_STRING_LIST_LDB(msg, "mayContain", mem_ctx, obj, mayContain, False);
505
506         GET_STRING_LDB(msg, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, False);
507
508         GET_UINT32_LDB(msg, "schemaFlagsEx", obj, schemaFlagsEx);
509         GET_BLOB_LDB(msg, "msDs-Schema-Extensions", mem_ctx, obj, msDs_Schema_Extensions);
510
511         GET_BOOL_LDB(msg, "showInAdvancedViewOnly", obj, showInAdvancedViewOnly, False);
512         GET_STRING_LDB(msg, "adminDisplayName", mem_ctx, obj, adminDisplayName, False);
513         GET_STRING_LDB(msg, "adminDescription", mem_ctx, obj, adminDescription, False);
514         GET_STRING_LDB(msg, "classDisplayName", mem_ctx, obj, classDisplayName, False);
515         GET_BOOL_LDB(msg, "defaultHidingValue", obj, defaultHidingValue, False);
516         GET_BOOL_LDB(msg, "isDefunct", obj, isDefunct, False);
517         GET_BOOL_LDB(msg, "systemOnly", obj, systemOnly, False);
518
519         return WERR_OK;
520 }
521
522 static const struct {
523         const char *name;
524         const char *oid;
525 } name_mappings[] = {
526         { "cn",                                 "2.5.4.3" },
527         { "name",                               "1.2.840.113556.1.4.1" },
528         { "lDAPDisplayName",                    "1.2.840.113556.1.2.460" },
529         { "attributeID",                        "1.2.840.113556.1.2.30" },
530         { "schemaIDGUID",                       "1.2.840.113556.1.4.148" },
531         { "mAPIID",                             "1.2.840.113556.1.2.49" },
532         { "attributeSecurityGUID",              "1.2.840.113556.1.4.149" },
533         { "searchFlags",                        "1.2.840.113556.1.2.334" },
534         { "systemFlags",                        "1.2.840.113556.1.4.375" },
535         { "isMemberOfPartialAttributeSet",      "1.2.840.113556.1.4.639" },
536         { "linkID",                             "1.2.840.113556.1.2.50" },
537         { "attributeSyntax",                    "1.2.840.113556.1.2.32" },
538         { "oMSyntax",                           "1.2.840.113556.1.2.231" },
539         { "oMObjectClass",                      "1.2.840.113556.1.2.218" },
540         { "isSingleValued",                     "1.2.840.113556.1.2.33" },
541         { "rangeLower",                         "1.2.840.113556.1.2.34" },
542         { "rangeUpper",                         "1.2.840.113556.1.2.35" },
543         { "extendedCharsAllowed",               "1.2.840.113556.1.2.380" },
544         { "schemaFlagsEx",                      "1.2.840.113556.1.4.120" },
545         { "msDs-Schema-Extensions",             "1.2.840.113556.1.4.1440" },
546         { "showInAdvancedViewOnly",             "1.2.840.113556.1.2.169" },
547         { "adminDisplayName",                   "1.2.840.113556.1.2.194" },
548         { "adminDescription",                   "1.2.840.113556.1.2.226" },
549         { "classDisplayName",                   "1.2.840.113556.1.4.610" },
550         { "isEphemeral",                        "1.2.840.113556.1.4.1212" },
551         { "isDefunct",                          "1.2.840.113556.1.4.661" },
552         { "systemOnly",                         "1.2.840.113556.1.4.170" },
553         { "governsID",                          "1.2.840.113556.1.2.22" },
554         { "objectClassCategory",                "1.2.840.113556.1.2.370" },
555         { "rDNAttID",                           "1.2.840.113556.1.2.26" },
556         { "defaultObjectCategory",              "1.2.840.113556.1.4.783" },
557         { "subClassOf",                         "1.2.840.113556.1.2.21" },
558         { "systemAuxiliaryClass",               "1.2.840.113556.1.4.198" },
559         { "systemPossSuperiors",                "1.2.840.113556.1.4.195" },
560         { "systemMustContain",                  "1.2.840.113556.1.4.197" },
561         { "systemMayContain",                   "1.2.840.113556.1.4.196" },
562         { "auxiliaryClass",                     "1.2.840.113556.1.2.351" },
563         { "possSuperiors",                      "1.2.840.113556.1.2.8" },
564         { "mustContain",                        "1.2.840.113556.1.2.24" },
565         { "mayContain",                         "1.2.840.113556.1.2.25" },
566         { "defaultSecurityDescriptor",          "1.2.840.113556.1.4.224" },
567         { "defaultHidingValue",                 "1.2.840.113556.1.4.518" },
568 };
569
570 static struct drsuapi_DsReplicaAttribute *dsdb_find_object_attr_name(struct dsdb_schema *schema,
571                                                                      struct drsuapi_DsReplicaObject *obj,
572                                                                      const char *name,
573                                                                      uint32_t *idx)
574 {
575         WERROR status;
576         uint32_t i, id;
577         const char *oid = NULL;
578
579         for(i=0; i < ARRAY_SIZE(name_mappings); i++) {
580                 if (strcmp(name_mappings[i].name, name) != 0) continue;
581
582                 oid = name_mappings[i].oid;
583                 break;
584         }
585
586         if (!oid) {
587                 return NULL;
588         }
589
590         status = dsdb_map_oid2int(schema, oid, &id);
591         if (!W_ERROR_IS_OK(status)) {
592                 return NULL;
593         }
594
595         for (i=0; i < obj->attribute_ctr.num_attributes; i++) {
596                 if (obj->attribute_ctr.attributes[i].attid != id) continue;
597
598                 if (idx) *idx = i;
599                 return &obj->attribute_ctr.attributes[i];
600         }
601
602         return NULL;
603 }
604
605 #define GET_STRING_DS(s, r, attr, mem_ctx, p, elem, strict) do { \
606         struct drsuapi_DsReplicaAttribute *_a; \
607         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
608         if (strict && !_a) { \
609                 d_printf("%s: %s == NULL\n", __location__, attr); \
610                 return WERR_INVALID_PARAM; \
611         } \
612         if (strict && _a->value_ctr.num_values != 1) { \
613                 d_printf("%s: %s num_values == %u\n", __location__, attr, \
614                         _a->value_ctr.num_values); \
615                 return WERR_INVALID_PARAM; \
616         } \
617         if (_a && _a->value_ctr.num_values >= 1) { \
618                 ssize_t _ret; \
619                 _ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, \
620                                              _a->value_ctr.values[0].blob->data, \
621                                              _a->value_ctr.values[0].blob->length, \
622                                              (void **)discard_const(&(p)->elem)); \
623                 if (_ret == -1) { \
624                         DEBUG(0,("%s: invalid data!\n", attr)); \
625                         dump_data(0, \
626                                      _a->value_ctr.values[0].blob->data, \
627                                      _a->value_ctr.values[0].blob->length); \
628                         return WERR_FOOBAR; \
629                 } \
630         } else { \
631                 (p)->elem = NULL; \
632         } \
633 } while (0)
634
635 #define GET_DN_DS(s, r, attr, mem_ctx, p, elem, strict) do { \
636         struct drsuapi_DsReplicaAttribute *_a; \
637         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
638         if (strict && !_a) { \
639                 d_printf("%s: %s == NULL\n", __location__, attr); \
640                 return WERR_INVALID_PARAM; \
641         } \
642         if (strict && _a->value_ctr.num_values != 1) { \
643                 d_printf("%s: %s num_values == %u\n", __location__, attr, \
644                         _a->value_ctr.num_values); \
645                 return WERR_INVALID_PARAM; \
646         } \
647         if (strict && !_a->value_ctr.values[0].blob) { \
648                 d_printf("%s: %s data == NULL\n", __location__, attr); \
649                 return WERR_INVALID_PARAM; \
650         } \
651         if (_a && _a->value_ctr.num_values >= 1 \
652             && _a->value_ctr.values[0].blob) { \
653                 struct drsuapi_DsReplicaObjectIdentifier3 _id3; \
654                 NTSTATUS _nt_status; \
655                 _nt_status = ndr_pull_struct_blob_all(_a->value_ctr.values[0].blob, \
656                                                       mem_ctx, &_id3,\
657                                                       (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);\
658                 if (!NT_STATUS_IS_OK(_nt_status)) { \
659                         return ntstatus_to_werror(_nt_status); \
660                 } \
661                 (p)->elem = _id3.dn; \
662         } else { \
663                 (p)->elem = NULL; \
664         } \
665 } while (0)
666
667 #define GET_BOOL_DS(s, r, attr, p, elem, strict) do { \
668         struct drsuapi_DsReplicaAttribute *_a; \
669         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
670         if (strict && !_a) { \
671                 d_printf("%s: %s == NULL\n", __location__, attr); \
672                 return WERR_INVALID_PARAM; \
673         } \
674         if (strict && _a->value_ctr.num_values != 1) { \
675                 d_printf("%s: %s num_values == %u\n", __location__, attr, \
676                         _a->value_ctr.num_values); \
677                 return WERR_INVALID_PARAM; \
678         } \
679         if (strict && !_a->value_ctr.values[0].blob) { \
680                 d_printf("%s: %s data == NULL\n", __location__, attr); \
681                 return WERR_INVALID_PARAM; \
682         } \
683         if (strict && _a->value_ctr.values[0].blob->length != 4) { \
684                 d_printf("%s: %s length == %u\n", __location__, attr, \
685                         _a->value_ctr.values[0].blob->length); \
686                 return WERR_INVALID_PARAM; \
687         } \
688         if (_a && _a->value_ctr.num_values >= 1 \
689             && _a->value_ctr.values[0].blob \
690             && _a->value_ctr.values[0].blob->length == 4) { \
691                 (p)->elem = (IVAL(_a->value_ctr.values[0].blob->data,0)?True:False);\
692         } else { \
693                 (p)->elem = False; \
694         } \
695 } while (0)
696
697 #define GET_UINT32_DS(s, r, attr, p, elem) do { \
698         struct drsuapi_DsReplicaAttribute *_a; \
699         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
700         if (_a && _a->value_ctr.num_values >= 1 \
701             && _a->value_ctr.values[0].blob \
702             && _a->value_ctr.values[0].blob->length == 4) { \
703                 (p)->elem = IVAL(_a->value_ctr.values[0].blob->data,0);\
704         } else { \
705                 (p)->elem = 0; \
706         } \
707 } while (0)
708
709 #define GET_GUID_DS(s, r, attr, mem_ctx, p, elem) do { \
710         struct drsuapi_DsReplicaAttribute *_a; \
711         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
712         if (_a && _a->value_ctr.num_values >= 1 \
713             && _a->value_ctr.values[0].blob \
714             && _a->value_ctr.values[0].blob->length == 16) { \
715                 NTSTATUS _nt_status; \
716                 _nt_status = ndr_pull_struct_blob_all(_a->value_ctr.values[0].blob, \
717                                                       mem_ctx, &(p)->elem, \
718                                                       (ndr_pull_flags_fn_t)ndr_pull_GUID); \
719                 if (!NT_STATUS_IS_OK(_nt_status)) { \
720                         return ntstatus_to_werror(_nt_status); \
721                 } \
722         } else { \
723                 ZERO_STRUCT((p)->elem);\
724         } \
725 } while (0)
726
727 #define GET_BLOB_DS(s, r, attr, mem_ctx, p, elem) do { \
728         struct drsuapi_DsReplicaAttribute *_a; \
729         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
730         if (_a && _a->value_ctr.num_values >= 1 \
731             && _a->value_ctr.values[0].blob) { \
732                 (p)->elem = *_a->value_ctr.values[0].blob;\
733                 talloc_steal(mem_ctx, (p)->elem.data); \
734         } else { \
735                 ZERO_STRUCT((p)->elem);\
736         }\
737 } while (0)
738
739 WERROR dsdb_attribute_from_drsuapi(struct dsdb_schema *schema,
740                                    struct drsuapi_DsReplicaObject *r,
741                                    TALLOC_CTX *mem_ctx,
742                                    struct dsdb_attribute *attr)
743 {
744         WERROR status;
745
746         GET_STRING_DS(schema, r, "name", mem_ctx, attr, cn, True);
747         GET_STRING_DS(schema, r, "lDAPDisplayName", mem_ctx, attr, lDAPDisplayName, True);
748         GET_UINT32_DS(schema, r, "attributeID", attr, attributeID_id);
749         status = dsdb_map_int2oid(schema, attr->attributeID_id, mem_ctx, &attr->attributeID_oid);
750         if (!W_ERROR_IS_OK(status)) {
751                 DEBUG(0,("%s: '%s': unable to map attributeID 0x%08X: %s\n",
752                         __location__, attr->lDAPDisplayName, attr->attributeID_id,
753                         win_errstr(status)));
754                 return status;
755         }
756         GET_GUID_DS(schema, r, "schemaIDGUID", mem_ctx, attr, schemaIDGUID);
757         GET_UINT32_DS(schema, r, "mAPIID", attr, mAPIID);
758
759         GET_GUID_DS(schema, r, "attributeSecurityGUID", mem_ctx, attr, attributeSecurityGUID);
760
761         GET_UINT32_DS(schema, r, "searchFlags", attr, searchFlags);
762         GET_UINT32_DS(schema, r, "systemFlags", attr, systemFlags);
763         GET_BOOL_DS(schema, r, "isMemberOfPartialAttributeSet", attr, isMemberOfPartialAttributeSet, False);
764         GET_UINT32_DS(schema, r, "linkID", attr, linkID);
765
766         GET_UINT32_DS(schema, r, "attributeSyntax", attr, attributeSyntax_id);
767         status = dsdb_map_int2oid(schema, attr->attributeSyntax_id, mem_ctx, &attr->attributeSyntax_oid);
768         if (!W_ERROR_IS_OK(status)) {
769                 DEBUG(0,("%s: '%s': unable to map attributeSyntax 0x%08X: %s\n",
770                         __location__, attr->lDAPDisplayName, attr->attributeSyntax_id,
771                         win_errstr(status)));
772                 return status;
773         }
774         GET_UINT32_DS(schema, r, "oMSyntax", attr, oMSyntax);
775         GET_BLOB_DS(schema, r, "oMObjectClass", mem_ctx, attr, oMObjectClass);
776
777         GET_BOOL_DS(schema, r, "isSingleValued", attr, isSingleValued, True);
778         GET_UINT32_DS(schema, r, "rangeLower", attr, rangeLower);
779         GET_UINT32_DS(schema, r, "rangeUpper", attr, rangeUpper);
780         GET_BOOL_DS(schema, r, "extendedCharsAllowed", attr, extendedCharsAllowed, False);
781
782         GET_UINT32_DS(schema, r, "schemaFlagsEx", attr, schemaFlagsEx);
783         GET_BLOB_DS(schema, r, "msDs-Schema-Extensions", mem_ctx, attr, msDs_Schema_Extensions);
784
785         GET_BOOL_DS(schema, r, "showInAdvancedViewOnly", attr, showInAdvancedViewOnly, False);
786         GET_STRING_DS(schema, r, "adminDisplayName", mem_ctx, attr, adminDisplayName, False);
787         GET_STRING_DS(schema, r, "adminDescription", mem_ctx, attr, adminDescription, False);
788         GET_STRING_DS(schema, r, "classDisplayName", mem_ctx, attr, classDisplayName, False);
789         GET_BOOL_DS(schema, r, "isEphemeral", attr, isEphemeral, False);
790         GET_BOOL_DS(schema, r, "isDefunct", attr, isDefunct, False);
791         GET_BOOL_DS(schema, r, "systemOnly", attr, systemOnly, False);
792
793         attr->syntax = dsdb_syntax_for_attribute(attr);
794         if (!attr->syntax) {
795                 return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
796         }
797
798         return WERR_OK;
799 }
800
801 WERROR dsdb_class_from_drsuapi(struct dsdb_schema *schema,
802                                struct drsuapi_DsReplicaObject *r,
803                                TALLOC_CTX *mem_ctx,
804                                struct dsdb_class *obj)
805 {
806         WERROR status;
807
808         GET_STRING_DS(schema, r, "name", mem_ctx, obj, cn, True);
809         GET_STRING_DS(schema, r, "lDAPDisplayName", mem_ctx, obj, lDAPDisplayName, True);
810         GET_UINT32_DS(schema, r, "governsID", obj, governsID_id);
811         status = dsdb_map_int2oid(schema, obj->governsID_id, mem_ctx, &obj->governsID_oid);
812         if (!W_ERROR_IS_OK(status)) {
813                 DEBUG(0,("%s: '%s': unable to map governsID 0x%08X: %s\n",
814                         __location__, obj->lDAPDisplayName, obj->governsID_id,
815                         win_errstr(status)));
816                 return status;
817         }
818         GET_GUID_DS(schema, r, "schemaIDGUID", mem_ctx, obj, schemaIDGUID);
819
820         GET_UINT32_DS(schema, r, "objectClassCategory", obj, objectClassCategory);
821         GET_STRING_DS(schema, r, "rDNAttID", mem_ctx, obj, rDNAttID, False);
822         GET_DN_DS(schema, r, "defaultObjectCategory", mem_ctx, obj, defaultObjectCategory, True);
823
824         GET_STRING_DS(schema, r, "subClassOf", mem_ctx, obj, subClassOf, True);
825
826         obj->systemAuxiliaryClass       = NULL;
827         obj->systemPossSuperiors        = NULL;
828         obj->systemMustContain          = NULL;
829         obj->systemMayContain           = NULL;
830
831         obj->auxiliaryClass             = NULL;
832         obj->possSuperiors              = NULL;
833         obj->mustContain                = NULL;
834         obj->mayContain                 = NULL;
835
836         GET_STRING_DS(schema, r, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, False);
837
838         GET_UINT32_DS(schema, r, "schemaFlagsEx", obj, schemaFlagsEx);
839         GET_BLOB_DS(schema, r, "msDs-Schema-Extensions", mem_ctx, obj, msDs_Schema_Extensions);
840
841         GET_BOOL_DS(schema, r, "showInAdvancedViewOnly", obj, showInAdvancedViewOnly, False);
842         GET_STRING_DS(schema, r, "adminDisplayName", mem_ctx, obj, adminDisplayName, False);
843         GET_STRING_DS(schema, r, "adminDescription", mem_ctx, obj, adminDescription, False);
844         GET_STRING_DS(schema, r, "classDisplayName", mem_ctx, obj, classDisplayName, False);
845         GET_BOOL_DS(schema, r, "defaultHidingValue", obj, defaultHidingValue, False);
846         GET_BOOL_DS(schema, r, "isDefunct", obj, isDefunct, False);
847         GET_BOOL_DS(schema, r, "systemOnly", obj, systemOnly, False);
848
849         return WERR_OK;
850 }
851
852 const struct dsdb_attribute *dsdb_attribute_by_attributeID_id(const struct dsdb_schema *schema,
853                                                               uint32_t id)
854 {
855         struct dsdb_attribute *cur;
856
857         /*
858          * 0xFFFFFFFF is used as value when no mapping table is available,
859          * so don't try to match with it
860          */
861         if (id == 0xFFFFFFFF) return NULL;
862
863         /* TODO: add binary search */
864         for (cur = schema->attributes; cur; cur = cur->next) {
865                 if (cur->attributeID_id != id) continue;
866
867                 return cur;
868         }
869
870         return NULL;
871 }
872
873 const struct dsdb_attribute *dsdb_attribute_by_attributeID_oid(const struct dsdb_schema *schema,
874                                                                const char *oid)
875 {
876         struct dsdb_attribute *cur;
877
878         if (!oid) return NULL;
879
880         /* TODO: add binary search */
881         for (cur = schema->attributes; cur; cur = cur->next) {
882                 if (strcmp(cur->attributeID_oid, oid) != 0) continue;
883
884                 return cur;
885         }
886
887         return NULL;
888 }
889
890 const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema *schema,
891                                                                const char *name)
892 {
893         struct dsdb_attribute *cur;
894
895         if (!name) return NULL;
896
897         /* TODO: add binary search */
898         for (cur = schema->attributes; cur; cur = cur->next) {
899                 if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue;
900
901                 return cur;
902         }
903
904         return NULL;
905 }
906
907 const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *schema,
908                                                     uint32_t id)
909 {
910         struct dsdb_class *cur;
911
912         /*
913          * 0xFFFFFFFF is used as value when no mapping table is available,
914          * so don't try to match with it
915          */
916         if (id == 0xFFFFFFFF) return NULL;
917
918         /* TODO: add binary search */
919         for (cur = schema->classes; cur; cur = cur->next) {
920                 if (cur->governsID_id != id) continue;
921
922                 return cur;
923         }
924
925         return NULL;
926 }
927
928 const struct dsdb_class *dsdb_class_by_governsID_oid(const struct dsdb_schema *schema,
929                                                      const char *oid)
930 {
931         struct dsdb_class *cur;
932
933         if (!oid) return NULL;
934
935         /* TODO: add binary search */
936         for (cur = schema->classes; cur; cur = cur->next) {
937                 if (strcmp(cur->governsID_oid, oid) != 0) continue;
938
939                 return cur;
940         }
941
942         return NULL;
943 }
944
945 const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema *schema,
946                                                        const char *name)
947 {
948         struct dsdb_class *cur;
949
950         if (!name) return NULL;
951
952         /* TODO: add binary search */
953         for (cur = schema->classes; cur; cur = cur->next) {
954                 if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue;
955
956                 return cur;
957         }
958
959         return NULL;
960 }
961
962 const struct dsdb_class *dsdb_class_by_cn(const struct dsdb_schema *schema,
963                                           const char *cn)
964 {
965         struct dsdb_class *cur;
966
967         if (!cn) return NULL;
968
969         /* TODO: add binary search */
970         for (cur = schema->classes; cur; cur = cur->next) {
971                 if (strcasecmp(cur->cn, cn) != 0) continue;
972
973                 return cur;
974         }
975
976         return NULL;
977 }
978
979 const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
980                                        uint32_t id)
981 {
982         const struct dsdb_attribute *a;
983         const struct dsdb_class *c;
984
985         /* TODO: add binary search */
986         a = dsdb_attribute_by_attributeID_id(schema, id);
987         if (a) {
988                 return a->lDAPDisplayName;
989         }
990
991         c = dsdb_class_by_governsID_id(schema, id);
992         if (c) {
993                 return c->lDAPDisplayName;
994         }
995
996         return NULL;
997 }
998
999 int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
1000 {
1001         int ret;
1002
1003         ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
1004         if (ret != LDB_SUCCESS) {
1005                 return ret;
1006         }
1007
1008         talloc_steal(ldb, schema);
1009
1010         return LDB_SUCCESS;
1011 }
1012
1013 static struct dsdb_schema *global_schema;
1014
1015 int dsdb_set_global_schema(struct ldb_context *ldb)
1016 {
1017         int ret;
1018         if (!global_schema) {
1019                 return LDB_SUCCESS;
1020         }
1021         ret = ldb_set_opaque(ldb, "dsdb_schema", global_schema);
1022         if (ret != LDB_SUCCESS) {
1023                 return ret;
1024         }
1025
1026         return LDB_SUCCESS;
1027 }
1028
1029 const struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb)
1030 {
1031         const void *p;
1032         const struct dsdb_schema *schema;
1033
1034         /* see if we have a cached copy */
1035         p = ldb_get_opaque(ldb, "dsdb_schema");
1036         if (!p) {
1037                 return NULL;
1038         }
1039
1040         schema = talloc_get_type(p, struct dsdb_schema);
1041         if (!schema) {
1042                 return NULL;
1043         }
1044
1045         return schema;
1046 }
1047
1048 void dsdb_make_schema_global(struct ldb_context *ldb)
1049 {
1050         const void *p;
1051         const struct dsdb_schema *schema;
1052
1053         /* see if we have a cached copy */
1054         p = ldb_get_opaque(ldb, "dsdb_schema");
1055         if (!p) {
1056                 return;
1057         }
1058
1059         schema = talloc_get_type(p, struct dsdb_schema);
1060         if (!schema) {
1061                 return;
1062         }
1063
1064         talloc_steal(talloc_autofree_context(), schema);
1065         global_schema = schema;
1066
1067         dsdb_set_global_schema(ldb);
1068 }
1069
1070 WERROR dsdb_attach_schema_from_ldif_file(struct ldb_context *ldb, const char *pf, const char *df)
1071 {
1072         struct ldb_ldif *ldif;
1073         struct ldb_message *msg;
1074         TALLOC_CTX *mem_ctx;
1075         WERROR status;
1076         int ret;
1077         struct dsdb_schema *schema;
1078         const struct ldb_val *prefix_val;
1079         const struct ldb_val *info_val;
1080         struct ldb_val info_val_default;
1081
1082         mem_ctx = talloc_new(ldb);
1083         if (!mem_ctx) {
1084                 goto nomem;
1085         }
1086
1087         schema = talloc_zero(mem_ctx, struct dsdb_schema);
1088         if (!schema) {
1089                 goto nomem;
1090         }
1091
1092         /*
1093          * load the prefixMap attribute from pf
1094          */
1095         ldif = ldb_ldif_read_string(ldb, &pf);
1096         if (!ldif) {
1097                 status = WERR_INVALID_PARAM;
1098                 goto failed;
1099         }
1100         talloc_steal(mem_ctx, ldif);
1101
1102         msg = ldb_msg_canonicalize(ldb, ldif->msg);
1103         if (!msg) {
1104                 goto nomem;
1105         }
1106
1107         prefix_val = ldb_msg_find_ldb_val(msg, "prefixMap");
1108         if (!prefix_val) {
1109                 status = WERR_INVALID_PARAM;
1110                 goto failed;
1111         }
1112
1113         info_val = ldb_msg_find_ldb_val(msg, "schemaInfo");
1114         if (!info_val) {
1115                 info_val_default = strhex_to_data_blob("FF0000000000000000000000000000000000000000");
1116                 if (!info_val_default.data) {
1117                         goto nomem;
1118                 }
1119                 talloc_steal(mem_ctx, info_val_default.data);
1120                 info_val = &info_val_default;
1121         }
1122
1123         status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val);
1124         if (!W_ERROR_IS_OK(status)) {
1125                 goto failed;
1126         }
1127
1128         /*
1129          * load the attribute and class definitions outof df
1130          */
1131         while ((ldif = ldb_ldif_read_string(ldb, &df))) {
1132                 bool is_sa;
1133                 bool is_sc;
1134
1135                 talloc_steal(mem_ctx, ldif);
1136
1137                 msg = ldb_msg_canonicalize(ldb, ldif->msg);
1138                 if (!msg) {
1139                         goto nomem;
1140                 }
1141
1142                 is_sa = ldb_msg_check_string_attribute(msg, "objectClass", "attributeSchema");
1143                 is_sc = ldb_msg_check_string_attribute(msg, "objectClass", "classSchema");
1144
1145                 if (is_sa) {
1146                         struct dsdb_attribute *sa;
1147
1148                         sa = talloc_zero(schema, struct dsdb_attribute);
1149                         if (!sa) {
1150                                 goto nomem;
1151                         }
1152
1153                         status = dsdb_attribute_from_ldb(schema, msg, sa, sa);
1154                         if (!W_ERROR_IS_OK(status)) {
1155                                 goto failed;
1156                         }
1157
1158                         DLIST_ADD_END(schema->attributes, sa, struct dsdb_attribute *);
1159                 } else if (is_sc) {
1160                         struct dsdb_class *sc;
1161
1162                         sc = talloc_zero(schema, struct dsdb_class);
1163                         if (!sc) {
1164                                 goto nomem;
1165                         }
1166
1167                         status = dsdb_class_from_ldb(schema, msg, sc, sc);
1168                         if (!W_ERROR_IS_OK(status)) {
1169                                 goto failed;
1170                         }
1171
1172                         DLIST_ADD_END(schema->classes, sc, struct dsdb_class *);
1173                 }
1174         }
1175
1176         ret = dsdb_set_schema(ldb, schema);
1177         if (ret != LDB_SUCCESS) {
1178                 status = WERR_FOOBAR;
1179                 goto failed;
1180         }
1181
1182         goto done;
1183
1184 nomem:
1185         status = WERR_NOMEM;
1186 failed:
1187 done:
1188         talloc_free(mem_ctx);
1189         return status;
1190 }