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