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