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