r20733: add a function to load the oid mappings from ldb_val's
[kai/samba.git] / source4 / dsdb / schema / schema_init.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    DSDB schema header
4    
5    Copyright (C) Stefan Metzmacher 2006
6     
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20    
21 */
22
23 #include "includes.h"
24 #include "dsdb/samdb/samdb.h"
25 #include "lib/ldb/include/ldb_errors.h"
26 #include "lib/util/dlinklist.h"
27 #include "librpc/gen_ndr/ndr_misc.h"
28 #include "librpc/gen_ndr/ndr_drsuapi.h"
29 #include "librpc/gen_ndr/ndr_drsblobs.h"
30
31 WERROR dsdb_load_oid_mappings_drsuapi(struct dsdb_schema *schema, const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
32 {
33         uint32_t i,j;
34
35         schema->prefixes = talloc_array(schema, struct dsdb_schema_oid_prefix, ctr->num_mappings);
36         W_ERROR_HAVE_NO_MEMORY(schema->prefixes);
37
38         for (i=0, j=0; i < ctr->num_mappings; i++) {
39                 if (ctr->mappings[i].oid.oid == NULL) {
40                         return WERR_INVALID_PARAM;
41                 }
42
43                 if (strncasecmp(ctr->mappings[i].oid.oid, "ff", 2) == 0) {
44                         if (ctr->mappings[i].id_prefix != 0) {
45                                 return WERR_INVALID_PARAM;
46                         }
47
48                         /* the magic value should be in the last array member */
49                         if (i != (ctr->num_mappings - 1)) {
50                                 return WERR_INVALID_PARAM;
51                         }
52
53                         if (ctr->mappings[i].oid.__ndr_size != 21) {
54                                 return WERR_INVALID_PARAM;
55                         }
56
57                         schema->schema_info = talloc_strdup(schema, ctr->mappings[i].oid.oid);
58                         W_ERROR_HAVE_NO_MEMORY(schema->schema_info);
59                 } else {
60                         /* the last array member should contain the magic value not a oid */
61                         if (i == (ctr->num_mappings - 1)) {
62                                 return WERR_INVALID_PARAM;
63                         }
64
65                         schema->prefixes[j].id  = ctr->mappings[i].id_prefix<<16;
66                         schema->prefixes[j].oid = talloc_asprintf(schema->prefixes, "%s.",
67                                                                   ctr->mappings[i].oid.oid);
68                         W_ERROR_HAVE_NO_MEMORY(schema->prefixes[j].oid);
69                         schema->prefixes[j].oid_len = strlen(schema->prefixes[j].oid);
70                         j++;
71                 }
72         }
73
74         schema->num_prefixes = j;
75         return WERR_OK;
76 }
77
78 WERROR dsdb_load_oid_mappings_ldb(struct dsdb_schema *schema,
79                                   const struct ldb_val *prefixMap,
80                                   const struct ldb_val *schemaInfo)
81 {
82         WERROR status;
83         NTSTATUS nt_status;
84         struct prefixMapBlob pfm;
85         char *schema_info;
86
87         nt_status = ndr_pull_struct_blob(prefixMap, schema, &pfm,
88                                          (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
89         if (!NT_STATUS_IS_OK(nt_status)) {
90                 return ntstatus_to_werror(nt_status);
91         }
92
93         if (pfm.version != PREFIX_MAP_VERSION_DSDB) {
94                 return WERR_FOOBAR;
95         }
96
97         if (schemaInfo->length != 21 && schemaInfo->data[0] == 0xFF) {
98                 return WERR_FOOBAR;
99         }
100
101         /* append the schema info as last element */
102         pfm.ctr.dsdb.num_mappings++;
103         pfm.ctr.dsdb.mappings = talloc_realloc(schema, pfm.ctr.dsdb.mappings,
104                                                struct drsuapi_DsReplicaOIDMapping,
105                                                pfm.ctr.dsdb.num_mappings);
106         W_ERROR_HAVE_NO_MEMORY(pfm.ctr.dsdb.mappings);
107
108         schema_info = data_blob_hex_string(pfm.ctr.dsdb.mappings, schemaInfo);
109         W_ERROR_HAVE_NO_MEMORY(schema_info);
110
111         pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].id_prefix  = 0;
112         pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].oid.oid    = schema_info;
113
114         /* call the drsuapi version */
115         status = dsdb_load_oid_mappings_drsuapi(schema, &pfm.ctr.dsdb);
116         talloc_free(pfm.ctr.dsdb.mappings);
117         W_ERROR_NOT_OK_RETURN(status);
118
119         return WERR_OK;
120 }
121
122 WERROR dsdb_verify_oid_mappings_drsuapi(const struct dsdb_schema *schema, const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
123 {
124         uint32_t i,j;
125
126         for (i=0; i < ctr->num_mappings; i++) {
127                 if (ctr->mappings[i].oid.oid == NULL) {
128                         return WERR_INVALID_PARAM;
129                 }
130
131                 if (strncasecmp(ctr->mappings[i].oid.oid, "ff", 2) == 0) {
132                         if (ctr->mappings[i].id_prefix != 0) {
133                                 return WERR_INVALID_PARAM;
134                         }
135
136                         /* the magic value should be in the last array member */
137                         if (i != (ctr->num_mappings - 1)) {
138                                 return WERR_INVALID_PARAM;
139                         }
140
141                         if (ctr->mappings[i].oid.__ndr_size != 21) {
142                                 return WERR_INVALID_PARAM;
143                         }
144
145                         if (strcasecmp(schema->schema_info, ctr->mappings[i].oid.oid) != 0) {
146                                 return WERR_DS_DRA_SCHEMA_MISMATCH;
147                         }
148                 } else {
149                         /* the last array member should contain the magic value not a oid */
150                         if (i == (ctr->num_mappings - 1)) {
151                                 return WERR_INVALID_PARAM;
152                         }
153
154                         for (j=0; j < schema->num_prefixes; j++) {
155                                 size_t oid_len;
156                                 if (schema->prefixes[j].id != (ctr->mappings[i].id_prefix<<16)) {
157                                         continue;
158                                 }
159
160                                 oid_len = strlen(ctr->mappings[i].oid.oid);
161
162                                 if (oid_len != (schema->prefixes[j].oid_len - 1)) {
163                                         return WERR_DS_DRA_SCHEMA_MISMATCH;
164                                 }
165
166                                 if (strncmp(ctr->mappings[i].oid.oid, schema->prefixes[j].oid, oid_len) != 0) {
167                                         return WERR_DS_DRA_SCHEMA_MISMATCH;                             
168                                 }
169
170                                 break;
171                         }
172
173                         if (j == schema->num_prefixes) {
174                                 return WERR_DS_DRA_SCHEMA_MISMATCH;                             
175                         }
176                 }
177         }
178
179         return WERR_OK;
180 }
181
182 WERROR dsdb_map_oid2int(const struct dsdb_schema *schema, const char *in, uint32_t *out)
183 {
184         uint32_t i;
185
186         for (i=0; i < schema->num_prefixes; i++) {
187                 const char *val_str;
188                 char *end_str;
189                 unsigned val;
190
191                 if (strncmp(schema->prefixes[i].oid, in, schema->prefixes[i].oid_len) != 0) {
192                         continue;
193                 }
194
195                 val_str = in + schema->prefixes[i].oid_len;
196                 end_str = NULL;
197                 errno = 0;
198
199                 if (val_str[0] == '\0') {
200                         return WERR_INVALID_PARAM;
201                 }
202
203                 /* two '.' chars are invalid */
204                 if (val_str[0] == '.') {
205                         return WERR_INVALID_PARAM;
206                 }
207
208                 val = strtoul(val_str, &end_str, 10);
209                 if (end_str[0] == '.' && end_str[1] != '\0') {
210                         /*
211                          * if it's a '.' and not the last char
212                          * then maybe an other mapping apply
213                          */
214                         continue;
215                 } else if (end_str[0] != '\0') {
216                         return WERR_INVALID_PARAM;
217                 } else if (val > 0xFFFF) {
218                         return WERR_INVALID_PARAM;
219                 }
220
221                 *out = schema->prefixes[i].id | val;
222                 return WERR_OK;
223         }
224
225         return WERR_DS_NO_MSDS_INTID;
226 }
227
228 WERROR dsdb_map_int2oid(const struct dsdb_schema *schema, uint32_t in, TALLOC_CTX *mem_ctx, const char **out)
229 {
230         uint32_t i;
231
232         for (i=0; i < schema->num_prefixes; i++) {
233                 const char *val;
234                 if (schema->prefixes[i].id != (in & 0xFFFF0000)) {
235                         continue;
236                 }
237
238                 val = talloc_asprintf(mem_ctx, "%s%u",
239                                       schema->prefixes[i].oid,
240                                       in & 0xFFFF);
241                 W_ERROR_HAVE_NO_MEMORY(val);
242
243                 *out = val;
244                 return WERR_OK;
245         }
246
247         return WERR_DS_NO_MSDS_INTID;
248 }
249
250 #define GET_STRING_LDB(msg, attr, mem_ctx, p, elem, strict) do { \
251         (p)->elem = samdb_result_string(msg, attr, NULL);\
252         if (strict && (p)->elem == NULL) { \
253                 d_printf("%s: %s == NULL\n", __location__, attr); \
254                 return WERR_INVALID_PARAM; \
255         } \
256         talloc_steal(mem_ctx, (p)->elem); \
257 } while (0)
258
259 #define GET_BOOL_LDB(msg, attr, p, elem, strict) do { \
260         const char *str; \
261         str = samdb_result_string(msg, attr, NULL);\
262         if (str == NULL) { \
263                 if (strict) { \
264                         d_printf("%s: %s == NULL\n", __location__, attr); \
265                         return WERR_INVALID_PARAM; \
266                 } else { \
267                         (p)->elem = False; \
268                 } \
269         } else if (strcasecmp("TRUE", str) == 0) { \
270                 (p)->elem = True; \
271         } else if (strcasecmp("FALSE", str) == 0) { \
272                 (p)->elem = False; \
273         } else { \
274                 d_printf("%s: %s == %s\n", __location__, attr, str); \
275                 return WERR_INVALID_PARAM; \
276         } \
277 } while (0)
278
279 #define GET_UINT32_LDB(msg, attr, p, elem) do { \
280         (p)->elem = samdb_result_uint(msg, attr, 0);\
281 } while (0)
282
283 #define GET_GUID_LDB(msg, attr, p, elem) do { \
284         (p)->elem = samdb_result_guid(msg, attr);\
285 } while (0)
286
287 #define GET_BLOB_LDB(msg, attr, mem_ctx, p, elem) do { \
288         const struct ldb_val *_val;\
289         _val = ldb_msg_find_ldb_val(msg, attr);\
290         if (_val) {\
291                 (p)->elem = *_val;\
292                 talloc_steal(mem_ctx, (p)->elem.data);\
293         } else {\
294                 ZERO_STRUCT((p)->elem);\
295         }\
296 } while (0)
297
298 WERROR dsdb_attribute_from_ldb(struct ldb_message *msg, TALLOC_CTX *mem_ctx, struct dsdb_attribute *attr)
299 {
300         GET_STRING_LDB(msg, "cn", mem_ctx, attr, cn, True);
301         GET_STRING_LDB(msg, "lDAPDisplayName", mem_ctx, attr, lDAPDisplayName, True);
302         GET_STRING_LDB(msg, "attributeID", mem_ctx, attr, attributeID_oid, True);
303         /* set an invalid value */
304         attr->attributeID_id = 0xFFFFFFFF;
305         GET_GUID_LDB(msg, "schemaIDGUID", attr, schemaIDGUID);
306         GET_UINT32_LDB(msg, "mAPIID", attr, mAPIID);
307
308         GET_GUID_LDB(msg, "attributeSecurityGUID", attr, attributeSecurityGUID);
309
310         GET_UINT32_LDB(msg, "searchFlags", attr, searchFlags);
311         GET_UINT32_LDB(msg, "systemFlags", attr, systemFlags);
312         GET_BOOL_LDB(msg, "isMemberOfPartialAttributeSet", attr, isMemberOfPartialAttributeSet, False);
313         GET_UINT32_LDB(msg, "linkID", attr, linkID);
314
315         GET_STRING_LDB(msg, "attributeSyntax", mem_ctx, attr, attributeSyntax_oid, True);
316         /* set an invalid value */
317         attr->attributeSyntax_id = 0xFFFFFFFF;
318         GET_UINT32_LDB(msg, "oMSyntax", attr, oMSyntax);
319         GET_BLOB_LDB(msg, "oMObjectClass", mem_ctx, attr, oMObjectClass);
320
321         GET_BOOL_LDB(msg, "isSingleValued", attr, isSingleValued, True);
322         GET_UINT32_LDB(msg, "rangeLower", attr, rangeLower);
323         GET_UINT32_LDB(msg, "rangeUpper", attr, rangeUpper);
324         GET_BOOL_LDB(msg, "extendedCharsAllowed", attr, extendedCharsAllowed, False);
325
326         GET_UINT32_LDB(msg, "schemaFlagsEx", attr, schemaFlagsEx);
327         GET_BLOB_LDB(msg, "msDs-Schema-Extensions", mem_ctx, attr, msDs_Schema_Extensions);
328
329         GET_BOOL_LDB(msg, "showInAdvancedViewOnly", attr, showInAdvancedViewOnly, False);
330         GET_STRING_LDB(msg, "adminDisplayName", mem_ctx, attr, adminDisplayName, False);
331         GET_STRING_LDB(msg, "adminDescription", mem_ctx, attr, adminDescription, False);
332         GET_STRING_LDB(msg, "classDisplayName", mem_ctx, attr, classDisplayName, False);
333         GET_BOOL_LDB(msg, "isEphemeral", attr, isEphemeral, False);
334         GET_BOOL_LDB(msg, "isDefunct", attr, isDefunct, False);
335         GET_BOOL_LDB(msg, "systemOnly", attr, systemOnly, False);
336
337         attr->syntax = dsdb_syntax_for_attribute(attr);
338         if (!attr->syntax) {
339                 return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
340         }
341
342         return WERR_OK;
343 }
344
345 WERROR dsdb_class_from_ldb(struct ldb_message *msg, TALLOC_CTX *mem_ctx, struct dsdb_class *obj)
346 {
347         GET_STRING_LDB(msg, "cn", mem_ctx, obj, cn, True);
348         GET_STRING_LDB(msg, "lDAPDisplayName", mem_ctx, obj, lDAPDisplayName, True);
349         GET_STRING_LDB(msg, "governsID", mem_ctx, obj, governsID_oid, True);
350         /* set an invalid value */
351         obj->governsID_id = 0xFFFFFFFF;
352         GET_GUID_LDB(msg, "schemaIDGUID", obj, schemaIDGUID);
353
354         GET_UINT32_LDB(msg, "objectClassCategory", obj, objectClassCategory);
355         GET_STRING_LDB(msg, "rDNAttID", mem_ctx, obj, rDNAttID, False);
356         GET_STRING_LDB(msg, "defaultObjectCategory", mem_ctx, obj, defaultObjectCategory, True);
357  
358         GET_STRING_LDB(msg, "subClassOf", mem_ctx, obj, subClassOf, True);
359
360         obj->systemAuxiliaryClass       = NULL;
361         obj->systemPossSuperiors        = NULL;
362         obj->systemMustContain          = NULL;
363         obj->systemMayContain           = NULL;
364
365         obj->auxiliaryClass             = NULL;
366         obj->possSuperiors              = NULL;
367         obj->mustContain                = NULL;
368         obj->mayContain                 = NULL;
369
370         GET_STRING_LDB(msg, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, False);
371
372         GET_UINT32_LDB(msg, "schemaFlagsEx", obj, schemaFlagsEx);
373         GET_BLOB_LDB(msg, "msDs-Schema-Extensions", mem_ctx, obj, msDs_Schema_Extensions);
374
375         GET_BOOL_LDB(msg, "showInAdvancedViewOnly", obj, showInAdvancedViewOnly, False);
376         GET_STRING_LDB(msg, "adminDisplayName", mem_ctx, obj, adminDisplayName, False);
377         GET_STRING_LDB(msg, "adminDescription", mem_ctx, obj, adminDescription, False);
378         GET_STRING_LDB(msg, "classDisplayName", mem_ctx, obj, classDisplayName, False);
379         GET_BOOL_LDB(msg, "defaultHidingValue", obj, defaultHidingValue, False);
380         GET_BOOL_LDB(msg, "isDefunct", obj, isDefunct, False);
381         GET_BOOL_LDB(msg, "systemOnly", obj, systemOnly, False);
382
383         return WERR_OK;
384 }
385
386 static const struct {
387         const char *name;
388         const char *oid;
389 } name_mappings[] = {
390         { "cn",                                 "2.5.4.3" },
391         { "name",                               "1.2.840.113556.1.4.1" },
392         { "lDAPDisplayName",                    "1.2.840.113556.1.2.460" },
393         { "attributeID",                        "1.2.840.113556.1.2.30" },
394         { "schemaIDGUID",                       "1.2.840.113556.1.4.148" },
395         { "mAPIID",                             "1.2.840.113556.1.2.49" },
396         { "attributeSecurityGUID",              "1.2.840.113556.1.4.149" },
397         { "searchFlags",                        "1.2.840.113556.1.2.334" },
398         { "systemFlags",                        "1.2.840.113556.1.4.375" },
399         { "isMemberOfPartialAttributeSet",      "1.2.840.113556.1.4.639" },
400         { "linkID",                             "1.2.840.113556.1.2.50" },
401         { "attributeSyntax",                    "1.2.840.113556.1.2.32" },
402         { "oMSyntax",                           "1.2.840.113556.1.2.231" },
403         { "oMObjectClass",                      "1.2.840.113556.1.2.218" },
404         { "isSingleValued",                     "1.2.840.113556.1.2.33" },
405         { "rangeLower",                         "1.2.840.113556.1.2.34" },
406         { "rangeUpper",                         "1.2.840.113556.1.2.35" },
407         { "extendedCharsAllowed",               "1.2.840.113556.1.2.380" },
408         { "schemaFlagsEx",                      "1.2.840.113556.1.4.120" },
409         { "msDs-Schema-Extensions",             "1.2.840.113556.1.4.1440" },
410         { "showInAdvancedViewOnly",             "1.2.840.113556.1.2.169" },
411         { "adminDisplayName",                   "1.2.840.113556.1.2.194" },
412         { "adminDescription",                   "1.2.840.113556.1.2.226" },
413         { "classDisplayName",                   "1.2.840.113556.1.4.610" },
414         { "isEphemeral",                        "1.2.840.113556.1.4.1212" },
415         { "isDefunct",                          "1.2.840.113556.1.4.661" },
416         { "systemOnly",                         "1.2.840.113556.1.4.170" },
417         { "governsID",                          "1.2.840.113556.1.2.22" },
418         { "objectClassCategory",                "1.2.840.113556.1.2.370" },
419         { "rDNAttID",                           "1.2.840.113556.1.2.26" },
420         { "defaultObjectCategory",              "1.2.840.113556.1.4.783" },
421         { "subClassOf",                         "1.2.840.113556.1.2.21" },
422         { "systemAuxiliaryClass",               "1.2.840.113556.1.4.198" },
423         { "systemPossSuperiors",                "1.2.840.113556.1.4.195" },
424         { "systemMustContain",                  "1.2.840.113556.1.4.197" },
425         { "systemMayContain",                   "1.2.840.113556.1.4.196" },
426         { "auxiliaryClass",                     "1.2.840.113556.1.2.351" },
427         { "possSuperiors",                      "1.2.840.113556.1.2.8" },
428         { "mustContain",                        "1.2.840.113556.1.2.24" },
429         { "mayContain",                         "1.2.840.113556.1.2.25" },
430         { "defaultSecurityDescriptor",          "1.2.840.113556.1.4.224" },
431         { "defaultHidingValue",                 "1.2.840.113556.1.4.518" },
432 };
433
434 static struct drsuapi_DsReplicaAttribute *dsdb_find_object_attr_name(struct dsdb_schema *schema,
435                                                                      struct drsuapi_DsReplicaObject *obj,
436                                                                      const char *name,
437                                                                      uint32_t *idx)
438 {
439         WERROR status;
440         uint32_t i, id;
441         const char *oid = NULL;
442
443         for(i=0; i < ARRAY_SIZE(name_mappings); i++) {
444                 if (strcmp(name_mappings[i].name, name) != 0) continue;
445
446                 oid = name_mappings[i].oid;
447                 break;
448         }
449
450         if (!oid) {
451                 return NULL;
452         }
453
454         status = dsdb_map_oid2int(schema, oid, &id);
455         if (!W_ERROR_IS_OK(status)) {
456                 return NULL;
457         }
458
459         for (i=0; i < obj->attribute_ctr.num_attributes; i++) {
460                 if (obj->attribute_ctr.attributes[i].attid != id) continue;
461
462                 if (idx) *idx = i;
463                 return &obj->attribute_ctr.attributes[i];
464         }
465
466         return NULL;
467 }
468
469 #define GET_STRING_DS(s, r, attr, mem_ctx, p, elem, strict) do { \
470         struct drsuapi_DsReplicaAttribute *_a; \
471         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
472         if (strict && !_a) { \
473                 d_printf("%s: %s == NULL\n", __location__, attr); \
474                 return WERR_INVALID_PARAM; \
475         } \
476         if (strict && _a->value_ctr.num_values != 1) { \
477                 d_printf("%s: %s num_values == %u\n", __location__, attr, \
478                         _a->value_ctr.num_values); \
479                 return WERR_INVALID_PARAM; \
480         } \
481         if (_a && _a->value_ctr.num_values >= 1) { \
482                 ssize_t _ret; \
483                 _ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, \
484                                              _a->value_ctr.values[0].blob->data, \
485                                              _a->value_ctr.values[0].blob->length, \
486                                              (void **)discard_const(&(p)->elem)); \
487                 if (_ret == -1) { \
488                         DEBUG(0,("%s: invalid data!\n", attr)); \
489                         dump_data(0, \
490                                      _a->value_ctr.values[0].blob->data, \
491                                      _a->value_ctr.values[0].blob->length); \
492                         return WERR_FOOBAR; \
493                 } \
494         } else { \
495                 (p)->elem = NULL; \
496         } \
497 } while (0)
498
499 #define GET_DN_DS(s, r, attr, mem_ctx, p, elem, strict) do { \
500         struct drsuapi_DsReplicaAttribute *_a; \
501         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
502         if (strict && !_a) { \
503                 d_printf("%s: %s == NULL\n", __location__, attr); \
504                 return WERR_INVALID_PARAM; \
505         } \
506         if (strict && _a->value_ctr.num_values != 1) { \
507                 d_printf("%s: %s num_values == %u\n", __location__, attr, \
508                         _a->value_ctr.num_values); \
509                 return WERR_INVALID_PARAM; \
510         } \
511         if (strict && !_a->value_ctr.values[0].blob) { \
512                 d_printf("%s: %s data == NULL\n", __location__, attr); \
513                 return WERR_INVALID_PARAM; \
514         } \
515         if (_a && _a->value_ctr.num_values >= 1 \
516             && _a->value_ctr.values[0].blob) { \
517                 struct drsuapi_DsReplicaObjectIdentifier3 _id3; \
518                 NTSTATUS _nt_status; \
519                 _nt_status = ndr_pull_struct_blob_all(_a->value_ctr.values[0].blob, \
520                                                       mem_ctx, &_id3,\
521                                                       (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);\
522                 if (!NT_STATUS_IS_OK(_nt_status)) { \
523                         return ntstatus_to_werror(_nt_status); \
524                 } \
525                 (p)->elem = _id3.dn; \
526         } else { \
527                 (p)->elem = NULL; \
528         } \
529 } while (0)
530
531 #define GET_BOOL_DS(s, r, attr, p, elem, strict) do { \
532         struct drsuapi_DsReplicaAttribute *_a; \
533         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
534         if (strict && !_a) { \
535                 d_printf("%s: %s == NULL\n", __location__, attr); \
536                 return WERR_INVALID_PARAM; \
537         } \
538         if (strict && _a->value_ctr.num_values != 1) { \
539                 d_printf("%s: %s num_values == %u\n", __location__, attr, \
540                         _a->value_ctr.num_values); \
541                 return WERR_INVALID_PARAM; \
542         } \
543         if (strict && !_a->value_ctr.values[0].blob) { \
544                 d_printf("%s: %s data == NULL\n", __location__, attr); \
545                 return WERR_INVALID_PARAM; \
546         } \
547         if (strict && _a->value_ctr.values[0].blob->length != 4) { \
548                 d_printf("%s: %s length == %u\n", __location__, attr, \
549                         _a->value_ctr.values[0].blob->length); \
550                 return WERR_INVALID_PARAM; \
551         } \
552         if (_a && _a->value_ctr.num_values >= 1 \
553             && _a->value_ctr.values[0].blob \
554             && _a->value_ctr.values[0].blob->length == 4) { \
555                 (p)->elem = (IVAL(_a->value_ctr.values[0].blob->data,0)?True:False);\
556         } else { \
557                 (p)->elem = False; \
558         } \
559 } while (0)
560
561 #define GET_UINT32_DS(s, r, attr, p, elem) do { \
562         struct drsuapi_DsReplicaAttribute *_a; \
563         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
564         if (_a && _a->value_ctr.num_values >= 1 \
565             && _a->value_ctr.values[0].blob \
566             && _a->value_ctr.values[0].blob->length == 4) { \
567                 (p)->elem = IVAL(_a->value_ctr.values[0].blob->data,0);\
568         } else { \
569                 (p)->elem = 0; \
570         } \
571 } while (0)
572
573 #define GET_GUID_DS(s, r, attr, mem_ctx, p, elem) do { \
574         struct drsuapi_DsReplicaAttribute *_a; \
575         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
576         if (_a && _a->value_ctr.num_values >= 1 \
577             && _a->value_ctr.values[0].blob \
578             && _a->value_ctr.values[0].blob->length == 16) { \
579                 NTSTATUS _nt_status; \
580                 _nt_status = ndr_pull_struct_blob_all(_a->value_ctr.values[0].blob, \
581                                                       mem_ctx, &(p)->elem, \
582                                                       (ndr_pull_flags_fn_t)ndr_pull_GUID); \
583                 if (!NT_STATUS_IS_OK(_nt_status)) { \
584                         return ntstatus_to_werror(_nt_status); \
585                 } \
586         } else { \
587                 ZERO_STRUCT((p)->elem);\
588         } \
589 } while (0)
590
591 #define GET_BLOB_DS(s, r, attr, mem_ctx, p, elem) do { \
592         struct drsuapi_DsReplicaAttribute *_a; \
593         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
594         if (_a && _a->value_ctr.num_values >= 1 \
595             && _a->value_ctr.values[0].blob) { \
596                 (p)->elem = *_a->value_ctr.values[0].blob;\
597                 talloc_steal(mem_ctx, (p)->elem.data); \
598         } else { \
599                 ZERO_STRUCT((p)->elem);\
600         }\
601 } while (0)
602
603 WERROR dsdb_attribute_from_drsuapi(struct dsdb_schema *schema,
604                                    struct drsuapi_DsReplicaObject *r,
605                                    TALLOC_CTX *mem_ctx,
606                                    struct dsdb_attribute *attr)
607 {
608         WERROR status;
609
610         GET_STRING_DS(schema, r, "name", mem_ctx, attr, cn, True);
611         GET_STRING_DS(schema, r, "lDAPDisplayName", mem_ctx, attr, lDAPDisplayName, True);
612         GET_UINT32_DS(schema, r, "attributeID", attr, attributeID_id);
613         status = dsdb_map_int2oid(schema, attr->attributeID_id, mem_ctx, &attr->attributeID_oid);
614         if (!W_ERROR_IS_OK(status)) {
615                 DEBUG(0,("%s: '%s': unable to map attributeID 0x%08X: %s\n",
616                         __location__, attr->lDAPDisplayName, attr->attributeID_id,
617                         win_errstr(status)));
618                 return status;
619         }
620         GET_GUID_DS(schema, r, "schemaIDGUID", mem_ctx, attr, schemaIDGUID);
621         GET_UINT32_DS(schema, r, "mAPIID", attr, mAPIID);
622
623         GET_GUID_DS(schema, r, "attributeSecurityGUID", mem_ctx, attr, attributeSecurityGUID);
624
625         GET_UINT32_DS(schema, r, "searchFlags", attr, searchFlags);
626         GET_UINT32_DS(schema, r, "systemFlags", attr, systemFlags);
627         GET_BOOL_DS(schema, r, "isMemberOfPartialAttributeSet", attr, isMemberOfPartialAttributeSet, False);
628         GET_UINT32_DS(schema, r, "linkID", attr, linkID);
629
630         GET_UINT32_DS(schema, r, "attributeSyntax", attr, attributeSyntax_id);
631         status = dsdb_map_int2oid(schema, attr->attributeSyntax_id, mem_ctx, &attr->attributeSyntax_oid);
632         if (!W_ERROR_IS_OK(status)) {
633                 DEBUG(0,("%s: '%s': unable to map attributeSyntax 0x%08X: %s\n",
634                         __location__, attr->lDAPDisplayName, attr->attributeSyntax_id,
635                         win_errstr(status)));
636                 return status;
637         }
638         GET_UINT32_DS(schema, r, "oMSyntax", attr, oMSyntax);
639         GET_BLOB_DS(schema, r, "oMObjectClass", mem_ctx, attr, oMObjectClass);
640
641         GET_BOOL_DS(schema, r, "isSingleValued", attr, isSingleValued, True);
642         GET_UINT32_DS(schema, r, "rangeLower", attr, rangeLower);
643         GET_UINT32_DS(schema, r, "rangeUpper", attr, rangeUpper);
644         GET_BOOL_DS(schema, r, "extendedCharsAllowed", attr, extendedCharsAllowed, False);
645
646         GET_UINT32_DS(schema, r, "schemaFlagsEx", attr, schemaFlagsEx);
647         GET_BLOB_DS(schema, r, "msDs-Schema-Extensions", mem_ctx, attr, msDs_Schema_Extensions);
648
649         GET_BOOL_DS(schema, r, "showInAdvancedViewOnly", attr, showInAdvancedViewOnly, False);
650         GET_STRING_DS(schema, r, "adminDisplayName", mem_ctx, attr, adminDisplayName, False);
651         GET_STRING_DS(schema, r, "adminDescription", mem_ctx, attr, adminDescription, False);
652         GET_STRING_DS(schema, r, "classDisplayName", mem_ctx, attr, classDisplayName, False);
653         GET_BOOL_DS(schema, r, "isEphemeral", attr, isEphemeral, False);
654         GET_BOOL_DS(schema, r, "isDefunct", attr, isDefunct, False);
655         GET_BOOL_DS(schema, r, "systemOnly", attr, systemOnly, False);
656
657         attr->syntax = dsdb_syntax_for_attribute(attr);
658         if (!attr->syntax) {
659                 return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
660         }
661
662         return WERR_OK;
663 }
664
665 WERROR dsdb_class_from_drsuapi(struct dsdb_schema *schema,
666                                struct drsuapi_DsReplicaObject *r,
667                                TALLOC_CTX *mem_ctx,
668                                struct dsdb_class *obj)
669 {
670         WERROR status;
671
672         GET_STRING_DS(schema, r, "name", mem_ctx, obj, cn, True);
673         GET_STRING_DS(schema, r, "lDAPDisplayName", mem_ctx, obj, lDAPDisplayName, True);
674         GET_UINT32_DS(schema, r, "governsID", obj, governsID_id);
675         status = dsdb_map_int2oid(schema, obj->governsID_id, mem_ctx, &obj->governsID_oid);
676         if (!W_ERROR_IS_OK(status)) {
677                 DEBUG(0,("%s: '%s': unable to map governsID 0x%08X: %s\n",
678                         __location__, obj->lDAPDisplayName, obj->governsID_id,
679                         win_errstr(status)));
680                 return status;
681         }
682         GET_GUID_DS(schema, r, "schemaIDGUID", mem_ctx, obj, schemaIDGUID);
683
684         GET_UINT32_DS(schema, r, "objectClassCategory", obj, objectClassCategory);
685         GET_STRING_DS(schema, r, "rDNAttID", mem_ctx, obj, rDNAttID, False);
686         GET_DN_DS(schema, r, "defaultObjectCategory", mem_ctx, obj, defaultObjectCategory, True);
687
688         GET_STRING_DS(schema, r, "subClassOf", mem_ctx, obj, subClassOf, True);
689
690         obj->systemAuxiliaryClass       = NULL;
691         obj->systemPossSuperiors        = NULL;
692         obj->systemMustContain          = NULL;
693         obj->systemMayContain           = NULL;
694
695         obj->auxiliaryClass             = NULL;
696         obj->possSuperiors              = NULL;
697         obj->mustContain                = NULL;
698         obj->mayContain                 = NULL;
699
700         GET_STRING_DS(schema, r, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, False);
701
702         GET_UINT32_DS(schema, r, "schemaFlagsEx", obj, schemaFlagsEx);
703         GET_BLOB_DS(schema, r, "msDs-Schema-Extensions", mem_ctx, obj, msDs_Schema_Extensions);
704
705         GET_BOOL_DS(schema, r, "showInAdvancedViewOnly", obj, showInAdvancedViewOnly, False);
706         GET_STRING_DS(schema, r, "adminDisplayName", mem_ctx, obj, adminDisplayName, False);
707         GET_STRING_DS(schema, r, "adminDescription", mem_ctx, obj, adminDescription, False);
708         GET_STRING_DS(schema, r, "classDisplayName", mem_ctx, obj, classDisplayName, False);
709         GET_BOOL_DS(schema, r, "defaultHidingValue", obj, defaultHidingValue, False);
710         GET_BOOL_DS(schema, r, "isDefunct", obj, isDefunct, False);
711         GET_BOOL_DS(schema, r, "systemOnly", obj, systemOnly, False);
712
713         return WERR_OK;
714 }
715
716 const struct dsdb_attribute *dsdb_attribute_by_attributeID_id(const struct dsdb_schema *schema,
717                                                               uint32_t id)
718 {
719         struct dsdb_attribute *cur;
720
721         /*
722          * 0xFFFFFFFF is used as value when no mapping table is available,
723          * so don't try to match with it
724          */
725         if (id == 0xFFFFFFFF) return NULL;
726
727         /* TODO: add binary search */
728         for (cur = schema->attributes; cur; cur = cur->next) {
729                 if (cur->attributeID_id != id) continue;
730
731                 return cur;
732         }
733
734         return NULL;
735 }
736
737 const struct dsdb_attribute *dsdb_attribute_by_attributeID_oid(const struct dsdb_schema *schema,
738                                                                const char *oid)
739 {
740         struct dsdb_attribute *cur;
741
742         if (!oid) return NULL;
743
744         /* TODO: add binary search */
745         for (cur = schema->attributes; cur; cur = cur->next) {
746                 if (strcmp(cur->attributeID_oid, oid) != 0) continue;
747
748                 return cur;
749         }
750
751         return NULL;
752 }
753
754 const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema *schema,
755                                                                const char *name)
756 {
757         struct dsdb_attribute *cur;
758
759         if (!name) return NULL;
760
761         /* TODO: add binary search */
762         for (cur = schema->attributes; cur; cur = cur->next) {
763                 if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue;
764
765                 return cur;
766         }
767
768         return NULL;
769 }
770
771 const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *schema,
772                                                     uint32_t id)
773 {
774         struct dsdb_class *cur;
775
776         /*
777          * 0xFFFFFFFF is used as value when no mapping table is available,
778          * so don't try to match with it
779          */
780         if (id == 0xFFFFFFFF) return NULL;
781
782         /* TODO: add binary search */
783         for (cur = schema->classes; cur; cur = cur->next) {
784                 if (cur->governsID_id != id) continue;
785
786                 return cur;
787         }
788
789         return NULL;
790 }
791
792 const struct dsdb_class *dsdb_class_by_governsID_oid(const struct dsdb_schema *schema,
793                                                      const char *oid)
794 {
795         struct dsdb_class *cur;
796
797         if (!oid) return NULL;
798
799         /* TODO: add binary search */
800         for (cur = schema->classes; cur; cur = cur->next) {
801                 if (strcmp(cur->governsID_oid, oid) != 0) continue;
802
803                 return cur;
804         }
805
806         return NULL;
807 }
808
809 const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema *schema,
810                                                        const char *name)
811 {
812         struct dsdb_class *cur;
813
814         if (!name) return NULL;
815
816         /* TODO: add binary search */
817         for (cur = schema->classes; cur; cur = cur->next) {
818                 if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue;
819
820                 return cur;
821         }
822
823         return NULL;
824 }
825
826 const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
827                                        uint32_t id)
828 {
829         const struct dsdb_attribute *a;
830         const struct dsdb_class *c;
831
832         /* TODO: add binary search */
833         a = dsdb_attribute_by_attributeID_id(schema, id);
834         if (a) {
835                 return a->lDAPDisplayName;
836         }
837
838         c = dsdb_class_by_governsID_id(schema, id);
839         if (c) {
840                 return c->lDAPDisplayName;
841         }
842
843         return NULL;
844 }
845
846 int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
847 {
848         int ret;
849
850         ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
851         if (ret != LDB_SUCCESS) {
852                 return ret;
853         }
854
855         talloc_steal(ldb, schema);
856
857         return LDB_SUCCESS;
858 }
859
860 const struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb)
861 {
862         const void *p;
863         const struct dsdb_schema *schema;
864
865         /* see if we have a cached copy */
866         p = ldb_get_opaque(ldb, "dsdb_schema");
867         if (!p) {
868                 return NULL;
869         }
870
871         schema = talloc_get_type(p, struct dsdb_schema);
872         if (!schema) {
873                 return NULL;
874         }
875
876         return schema;
877 }