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