r20764: fix some little bugs
[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.__ndr_size     = schemaInfo->length;
113         pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].oid.oid            = schema_info;
114
115         /* call the drsuapi version */
116         status = dsdb_load_oid_mappings_drsuapi(schema, &pfm.ctr.dsdb);
117         talloc_free(pfm.ctr.dsdb.mappings);
118         W_ERROR_NOT_OK_RETURN(status);
119
120         return WERR_OK;
121 }
122
123 WERROR dsdb_get_oid_mappings_drsuapi(const struct dsdb_schema *schema,
124                                      bool include_schema_info,
125                                      TALLOC_CTX *mem_ctx,
126                                      struct drsuapi_DsReplicaOIDMapping_Ctr **_ctr)
127 {
128         struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
129         uint32_t i;
130
131         ctr = talloc(mem_ctx, struct drsuapi_DsReplicaOIDMapping_Ctr);
132         W_ERROR_HAVE_NO_MEMORY(ctr);
133
134         ctr->num_mappings       = schema->num_prefixes;
135         if (include_schema_info) ctr->num_mappings++;
136         ctr->mappings = talloc_array(schema, struct drsuapi_DsReplicaOIDMapping, ctr->num_mappings);
137         W_ERROR_HAVE_NO_MEMORY(ctr->mappings);
138
139         for (i=0; i < schema->num_prefixes; i++) {
140                 ctr->mappings[i].id_prefix      = schema->prefixes[i].id>>16;
141                 ctr->mappings[i].oid.oid        = talloc_strndup(ctr->mappings,
142                                                                  schema->prefixes[i].oid,
143                                                                  schema->prefixes[i].oid_len - 1);
144                 W_ERROR_HAVE_NO_MEMORY(ctr->mappings[i].oid.oid);
145         }
146
147         if (include_schema_info) {
148                 ctr->mappings[i].id_prefix      = 0;
149                 ctr->mappings[i].oid.oid        = talloc_strdup(ctr->mappings,
150                                                                 schema->schema_info);
151                 W_ERROR_HAVE_NO_MEMORY(ctr->mappings[i].oid.oid);
152         }
153
154         *_ctr = ctr;
155         return WERR_OK;
156 }
157
158 WERROR dsdb_get_oid_mappings_ldb(const struct dsdb_schema *schema,
159                                  TALLOC_CTX *mem_ctx,
160                                  struct ldb_val *prefixMap,
161                                  struct ldb_val *schemaInfo)
162 {
163         WERROR status;
164         NTSTATUS nt_status;
165         struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
166         struct prefixMapBlob pfm;
167
168         status = dsdb_get_oid_mappings_drsuapi(schema, false, mem_ctx, &ctr);
169         W_ERROR_NOT_OK_RETURN(status);
170
171         pfm.version     = PREFIX_MAP_VERSION_DSDB;
172         pfm.ctr.dsdb    = *ctr;
173
174         nt_status = ndr_push_struct_blob(prefixMap, mem_ctx, &pfm,
175                                          (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
176         talloc_free(ctr);
177         if (!NT_STATUS_IS_OK(nt_status)) {
178                 return ntstatus_to_werror(nt_status);
179         }
180
181         *schemaInfo = strhex_to_data_blob(schema->schema_info);
182         W_ERROR_HAVE_NO_MEMORY(schemaInfo->data);
183         talloc_steal(mem_ctx, schemaInfo->data);
184
185         return WERR_OK;
186 }
187
188 WERROR dsdb_verify_oid_mappings_drsuapi(const struct dsdb_schema *schema, const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
189 {
190         uint32_t i,j;
191
192         for (i=0; i < ctr->num_mappings; i++) {
193                 if (ctr->mappings[i].oid.oid == NULL) {
194                         return WERR_INVALID_PARAM;
195                 }
196
197                 if (strncasecmp(ctr->mappings[i].oid.oid, "ff", 2) == 0) {
198                         if (ctr->mappings[i].id_prefix != 0) {
199                                 return WERR_INVALID_PARAM;
200                         }
201
202                         /* the magic value should be in the last array member */
203                         if (i != (ctr->num_mappings - 1)) {
204                                 return WERR_INVALID_PARAM;
205                         }
206
207                         if (ctr->mappings[i].oid.__ndr_size != 21) {
208                                 return WERR_INVALID_PARAM;
209                         }
210
211                         if (strcasecmp(schema->schema_info, ctr->mappings[i].oid.oid) != 0) {
212                                 return WERR_DS_DRA_SCHEMA_MISMATCH;
213                         }
214                 } else {
215                         /* the last array member should contain the magic value not a oid */
216                         if (i == (ctr->num_mappings - 1)) {
217                                 return WERR_INVALID_PARAM;
218                         }
219
220                         for (j=0; j < schema->num_prefixes; j++) {
221                                 size_t oid_len;
222                                 if (schema->prefixes[j].id != (ctr->mappings[i].id_prefix<<16)) {
223                                         continue;
224                                 }
225
226                                 oid_len = strlen(ctr->mappings[i].oid.oid);
227
228                                 if (oid_len != (schema->prefixes[j].oid_len - 1)) {
229                                         return WERR_DS_DRA_SCHEMA_MISMATCH;
230                                 }
231
232                                 if (strncmp(ctr->mappings[i].oid.oid, schema->prefixes[j].oid, oid_len) != 0) {
233                                         return WERR_DS_DRA_SCHEMA_MISMATCH;                             
234                                 }
235
236                                 break;
237                         }
238
239                         if (j == schema->num_prefixes) {
240                                 return WERR_DS_DRA_SCHEMA_MISMATCH;                             
241                         }
242                 }
243         }
244
245         return WERR_OK;
246 }
247
248 WERROR dsdb_map_oid2int(const struct dsdb_schema *schema, const char *in, uint32_t *out)
249 {
250         uint32_t i;
251
252         for (i=0; i < schema->num_prefixes; i++) {
253                 const char *val_str;
254                 char *end_str;
255                 unsigned val;
256
257                 if (strncmp(schema->prefixes[i].oid, in, schema->prefixes[i].oid_len) != 0) {
258                         continue;
259                 }
260
261                 val_str = in + schema->prefixes[i].oid_len;
262                 end_str = NULL;
263                 errno = 0;
264
265                 if (val_str[0] == '\0') {
266                         return WERR_INVALID_PARAM;
267                 }
268
269                 /* two '.' chars are invalid */
270                 if (val_str[0] == '.') {
271                         return WERR_INVALID_PARAM;
272                 }
273
274                 val = strtoul(val_str, &end_str, 10);
275                 if (end_str[0] == '.' && end_str[1] != '\0') {
276                         /*
277                          * if it's a '.' and not the last char
278                          * then maybe an other mapping apply
279                          */
280                         continue;
281                 } else if (end_str[0] != '\0') {
282                         return WERR_INVALID_PARAM;
283                 } else if (val > 0xFFFF) {
284                         return WERR_INVALID_PARAM;
285                 }
286
287                 *out = schema->prefixes[i].id | val;
288                 return WERR_OK;
289         }
290
291         return WERR_DS_NO_MSDS_INTID;
292 }
293
294 WERROR dsdb_map_int2oid(const struct dsdb_schema *schema, uint32_t in, TALLOC_CTX *mem_ctx, const char **out)
295 {
296         uint32_t i;
297
298         for (i=0; i < schema->num_prefixes; i++) {
299                 const char *val;
300                 if (schema->prefixes[i].id != (in & 0xFFFF0000)) {
301                         continue;
302                 }
303
304                 val = talloc_asprintf(mem_ctx, "%s%u",
305                                       schema->prefixes[i].oid,
306                                       in & 0xFFFF);
307                 W_ERROR_HAVE_NO_MEMORY(val);
308
309                 *out = val;
310                 return WERR_OK;
311         }
312
313         return WERR_DS_NO_MSDS_INTID;
314 }
315
316 #define GET_STRING_LDB(msg, attr, mem_ctx, p, elem, strict) do { \
317         (p)->elem = samdb_result_string(msg, attr, NULL);\
318         if (strict && (p)->elem == NULL) { \
319                 d_printf("%s: %s == NULL\n", __location__, attr); \
320                 return WERR_INVALID_PARAM; \
321         } \
322         talloc_steal(mem_ctx, (p)->elem); \
323 } while (0)
324
325 #define GET_BOOL_LDB(msg, attr, p, elem, strict) do { \
326         const char *str; \
327         str = samdb_result_string(msg, attr, NULL);\
328         if (str == NULL) { \
329                 if (strict) { \
330                         d_printf("%s: %s == NULL\n", __location__, attr); \
331                         return WERR_INVALID_PARAM; \
332                 } else { \
333                         (p)->elem = False; \
334                 } \
335         } else if (strcasecmp("TRUE", str) == 0) { \
336                 (p)->elem = True; \
337         } else if (strcasecmp("FALSE", str) == 0) { \
338                 (p)->elem = False; \
339         } else { \
340                 d_printf("%s: %s == %s\n", __location__, attr, str); \
341                 return WERR_INVALID_PARAM; \
342         } \
343 } while (0)
344
345 #define GET_UINT32_LDB(msg, attr, p, elem) do { \
346         (p)->elem = samdb_result_uint(msg, attr, 0);\
347 } while (0)
348
349 #define GET_GUID_LDB(msg, attr, p, elem) do { \
350         (p)->elem = samdb_result_guid(msg, attr);\
351 } while (0)
352
353 #define GET_BLOB_LDB(msg, attr, mem_ctx, p, elem) do { \
354         const struct ldb_val *_val;\
355         _val = ldb_msg_find_ldb_val(msg, attr);\
356         if (_val) {\
357                 (p)->elem = *_val;\
358                 talloc_steal(mem_ctx, (p)->elem.data);\
359         } else {\
360                 ZERO_STRUCT((p)->elem);\
361         }\
362 } while (0)
363
364 WERROR dsdb_attribute_from_ldb(struct ldb_message *msg, TALLOC_CTX *mem_ctx, struct dsdb_attribute *attr)
365 {
366         GET_STRING_LDB(msg, "cn", mem_ctx, attr, cn, True);
367         GET_STRING_LDB(msg, "lDAPDisplayName", mem_ctx, attr, lDAPDisplayName, True);
368         GET_STRING_LDB(msg, "attributeID", mem_ctx, attr, attributeID_oid, True);
369         /* set an invalid value */
370         attr->attributeID_id = 0xFFFFFFFF;
371         GET_GUID_LDB(msg, "schemaIDGUID", attr, schemaIDGUID);
372         GET_UINT32_LDB(msg, "mAPIID", attr, mAPIID);
373
374         GET_GUID_LDB(msg, "attributeSecurityGUID", attr, attributeSecurityGUID);
375
376         GET_UINT32_LDB(msg, "searchFlags", attr, searchFlags);
377         GET_UINT32_LDB(msg, "systemFlags", attr, systemFlags);
378         GET_BOOL_LDB(msg, "isMemberOfPartialAttributeSet", attr, isMemberOfPartialAttributeSet, False);
379         GET_UINT32_LDB(msg, "linkID", attr, linkID);
380
381         GET_STRING_LDB(msg, "attributeSyntax", mem_ctx, attr, attributeSyntax_oid, True);
382         /* set an invalid value */
383         attr->attributeSyntax_id = 0xFFFFFFFF;
384         GET_UINT32_LDB(msg, "oMSyntax", attr, oMSyntax);
385         GET_BLOB_LDB(msg, "oMObjectClass", mem_ctx, attr, oMObjectClass);
386
387         GET_BOOL_LDB(msg, "isSingleValued", attr, isSingleValued, True);
388         GET_UINT32_LDB(msg, "rangeLower", attr, rangeLower);
389         GET_UINT32_LDB(msg, "rangeUpper", attr, rangeUpper);
390         GET_BOOL_LDB(msg, "extendedCharsAllowed", attr, extendedCharsAllowed, False);
391
392         GET_UINT32_LDB(msg, "schemaFlagsEx", attr, schemaFlagsEx);
393         GET_BLOB_LDB(msg, "msDs-Schema-Extensions", mem_ctx, attr, msDs_Schema_Extensions);
394
395         GET_BOOL_LDB(msg, "showInAdvancedViewOnly", attr, showInAdvancedViewOnly, False);
396         GET_STRING_LDB(msg, "adminDisplayName", mem_ctx, attr, adminDisplayName, False);
397         GET_STRING_LDB(msg, "adminDescription", mem_ctx, attr, adminDescription, False);
398         GET_STRING_LDB(msg, "classDisplayName", mem_ctx, attr, classDisplayName, False);
399         GET_BOOL_LDB(msg, "isEphemeral", attr, isEphemeral, False);
400         GET_BOOL_LDB(msg, "isDefunct", attr, isDefunct, False);
401         GET_BOOL_LDB(msg, "systemOnly", attr, systemOnly, False);
402
403         attr->syntax = dsdb_syntax_for_attribute(attr);
404         if (!attr->syntax) {
405                 return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
406         }
407
408         return WERR_OK;
409 }
410
411 WERROR dsdb_class_from_ldb(struct ldb_message *msg, TALLOC_CTX *mem_ctx, struct dsdb_class *obj)
412 {
413         GET_STRING_LDB(msg, "cn", mem_ctx, obj, cn, True);
414         GET_STRING_LDB(msg, "lDAPDisplayName", mem_ctx, obj, lDAPDisplayName, True);
415         GET_STRING_LDB(msg, "governsID", mem_ctx, obj, governsID_oid, True);
416         /* set an invalid value */
417         obj->governsID_id = 0xFFFFFFFF;
418         GET_GUID_LDB(msg, "schemaIDGUID", obj, schemaIDGUID);
419
420         GET_UINT32_LDB(msg, "objectClassCategory", obj, objectClassCategory);
421         GET_STRING_LDB(msg, "rDNAttID", mem_ctx, obj, rDNAttID, False);
422         GET_STRING_LDB(msg, "defaultObjectCategory", mem_ctx, obj, defaultObjectCategory, True);
423  
424         GET_STRING_LDB(msg, "subClassOf", mem_ctx, obj, subClassOf, True);
425
426         obj->systemAuxiliaryClass       = NULL;
427         obj->systemPossSuperiors        = NULL;
428         obj->systemMustContain          = NULL;
429         obj->systemMayContain           = NULL;
430
431         obj->auxiliaryClass             = NULL;
432         obj->possSuperiors              = NULL;
433         obj->mustContain                = NULL;
434         obj->mayContain                 = NULL;
435
436         GET_STRING_LDB(msg, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, False);
437
438         GET_UINT32_LDB(msg, "schemaFlagsEx", obj, schemaFlagsEx);
439         GET_BLOB_LDB(msg, "msDs-Schema-Extensions", mem_ctx, obj, msDs_Schema_Extensions);
440
441         GET_BOOL_LDB(msg, "showInAdvancedViewOnly", obj, showInAdvancedViewOnly, False);
442         GET_STRING_LDB(msg, "adminDisplayName", mem_ctx, obj, adminDisplayName, False);
443         GET_STRING_LDB(msg, "adminDescription", mem_ctx, obj, adminDescription, False);
444         GET_STRING_LDB(msg, "classDisplayName", mem_ctx, obj, classDisplayName, False);
445         GET_BOOL_LDB(msg, "defaultHidingValue", obj, defaultHidingValue, False);
446         GET_BOOL_LDB(msg, "isDefunct", obj, isDefunct, False);
447         GET_BOOL_LDB(msg, "systemOnly", obj, systemOnly, False);
448
449         return WERR_OK;
450 }
451
452 static const struct {
453         const char *name;
454         const char *oid;
455 } name_mappings[] = {
456         { "cn",                                 "2.5.4.3" },
457         { "name",                               "1.2.840.113556.1.4.1" },
458         { "lDAPDisplayName",                    "1.2.840.113556.1.2.460" },
459         { "attributeID",                        "1.2.840.113556.1.2.30" },
460         { "schemaIDGUID",                       "1.2.840.113556.1.4.148" },
461         { "mAPIID",                             "1.2.840.113556.1.2.49" },
462         { "attributeSecurityGUID",              "1.2.840.113556.1.4.149" },
463         { "searchFlags",                        "1.2.840.113556.1.2.334" },
464         { "systemFlags",                        "1.2.840.113556.1.4.375" },
465         { "isMemberOfPartialAttributeSet",      "1.2.840.113556.1.4.639" },
466         { "linkID",                             "1.2.840.113556.1.2.50" },
467         { "attributeSyntax",                    "1.2.840.113556.1.2.32" },
468         { "oMSyntax",                           "1.2.840.113556.1.2.231" },
469         { "oMObjectClass",                      "1.2.840.113556.1.2.218" },
470         { "isSingleValued",                     "1.2.840.113556.1.2.33" },
471         { "rangeLower",                         "1.2.840.113556.1.2.34" },
472         { "rangeUpper",                         "1.2.840.113556.1.2.35" },
473         { "extendedCharsAllowed",               "1.2.840.113556.1.2.380" },
474         { "schemaFlagsEx",                      "1.2.840.113556.1.4.120" },
475         { "msDs-Schema-Extensions",             "1.2.840.113556.1.4.1440" },
476         { "showInAdvancedViewOnly",             "1.2.840.113556.1.2.169" },
477         { "adminDisplayName",                   "1.2.840.113556.1.2.194" },
478         { "adminDescription",                   "1.2.840.113556.1.2.226" },
479         { "classDisplayName",                   "1.2.840.113556.1.4.610" },
480         { "isEphemeral",                        "1.2.840.113556.1.4.1212" },
481         { "isDefunct",                          "1.2.840.113556.1.4.661" },
482         { "systemOnly",                         "1.2.840.113556.1.4.170" },
483         { "governsID",                          "1.2.840.113556.1.2.22" },
484         { "objectClassCategory",                "1.2.840.113556.1.2.370" },
485         { "rDNAttID",                           "1.2.840.113556.1.2.26" },
486         { "defaultObjectCategory",              "1.2.840.113556.1.4.783" },
487         { "subClassOf",                         "1.2.840.113556.1.2.21" },
488         { "systemAuxiliaryClass",               "1.2.840.113556.1.4.198" },
489         { "systemPossSuperiors",                "1.2.840.113556.1.4.195" },
490         { "systemMustContain",                  "1.2.840.113556.1.4.197" },
491         { "systemMayContain",                   "1.2.840.113556.1.4.196" },
492         { "auxiliaryClass",                     "1.2.840.113556.1.2.351" },
493         { "possSuperiors",                      "1.2.840.113556.1.2.8" },
494         { "mustContain",                        "1.2.840.113556.1.2.24" },
495         { "mayContain",                         "1.2.840.113556.1.2.25" },
496         { "defaultSecurityDescriptor",          "1.2.840.113556.1.4.224" },
497         { "defaultHidingValue",                 "1.2.840.113556.1.4.518" },
498 };
499
500 static struct drsuapi_DsReplicaAttribute *dsdb_find_object_attr_name(struct dsdb_schema *schema,
501                                                                      struct drsuapi_DsReplicaObject *obj,
502                                                                      const char *name,
503                                                                      uint32_t *idx)
504 {
505         WERROR status;
506         uint32_t i, id;
507         const char *oid = NULL;
508
509         for(i=0; i < ARRAY_SIZE(name_mappings); i++) {
510                 if (strcmp(name_mappings[i].name, name) != 0) continue;
511
512                 oid = name_mappings[i].oid;
513                 break;
514         }
515
516         if (!oid) {
517                 return NULL;
518         }
519
520         status = dsdb_map_oid2int(schema, oid, &id);
521         if (!W_ERROR_IS_OK(status)) {
522                 return NULL;
523         }
524
525         for (i=0; i < obj->attribute_ctr.num_attributes; i++) {
526                 if (obj->attribute_ctr.attributes[i].attid != id) continue;
527
528                 if (idx) *idx = i;
529                 return &obj->attribute_ctr.attributes[i];
530         }
531
532         return NULL;
533 }
534
535 #define GET_STRING_DS(s, r, attr, mem_ctx, p, elem, strict) do { \
536         struct drsuapi_DsReplicaAttribute *_a; \
537         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
538         if (strict && !_a) { \
539                 d_printf("%s: %s == NULL\n", __location__, attr); \
540                 return WERR_INVALID_PARAM; \
541         } \
542         if (strict && _a->value_ctr.num_values != 1) { \
543                 d_printf("%s: %s num_values == %u\n", __location__, attr, \
544                         _a->value_ctr.num_values); \
545                 return WERR_INVALID_PARAM; \
546         } \
547         if (_a && _a->value_ctr.num_values >= 1) { \
548                 ssize_t _ret; \
549                 _ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, \
550                                              _a->value_ctr.values[0].blob->data, \
551                                              _a->value_ctr.values[0].blob->length, \
552                                              (void **)discard_const(&(p)->elem)); \
553                 if (_ret == -1) { \
554                         DEBUG(0,("%s: invalid data!\n", attr)); \
555                         dump_data(0, \
556                                      _a->value_ctr.values[0].blob->data, \
557                                      _a->value_ctr.values[0].blob->length); \
558                         return WERR_FOOBAR; \
559                 } \
560         } else { \
561                 (p)->elem = NULL; \
562         } \
563 } while (0)
564
565 #define GET_DN_DS(s, r, attr, mem_ctx, p, elem, strict) do { \
566         struct drsuapi_DsReplicaAttribute *_a; \
567         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
568         if (strict && !_a) { \
569                 d_printf("%s: %s == NULL\n", __location__, attr); \
570                 return WERR_INVALID_PARAM; \
571         } \
572         if (strict && _a->value_ctr.num_values != 1) { \
573                 d_printf("%s: %s num_values == %u\n", __location__, attr, \
574                         _a->value_ctr.num_values); \
575                 return WERR_INVALID_PARAM; \
576         } \
577         if (strict && !_a->value_ctr.values[0].blob) { \
578                 d_printf("%s: %s data == NULL\n", __location__, attr); \
579                 return WERR_INVALID_PARAM; \
580         } \
581         if (_a && _a->value_ctr.num_values >= 1 \
582             && _a->value_ctr.values[0].blob) { \
583                 struct drsuapi_DsReplicaObjectIdentifier3 _id3; \
584                 NTSTATUS _nt_status; \
585                 _nt_status = ndr_pull_struct_blob_all(_a->value_ctr.values[0].blob, \
586                                                       mem_ctx, &_id3,\
587                                                       (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);\
588                 if (!NT_STATUS_IS_OK(_nt_status)) { \
589                         return ntstatus_to_werror(_nt_status); \
590                 } \
591                 (p)->elem = _id3.dn; \
592         } else { \
593                 (p)->elem = NULL; \
594         } \
595 } while (0)
596
597 #define GET_BOOL_DS(s, r, attr, p, elem, strict) do { \
598         struct drsuapi_DsReplicaAttribute *_a; \
599         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
600         if (strict && !_a) { \
601                 d_printf("%s: %s == NULL\n", __location__, attr); \
602                 return WERR_INVALID_PARAM; \
603         } \
604         if (strict && _a->value_ctr.num_values != 1) { \
605                 d_printf("%s: %s num_values == %u\n", __location__, attr, \
606                         _a->value_ctr.num_values); \
607                 return WERR_INVALID_PARAM; \
608         } \
609         if (strict && !_a->value_ctr.values[0].blob) { \
610                 d_printf("%s: %s data == NULL\n", __location__, attr); \
611                 return WERR_INVALID_PARAM; \
612         } \
613         if (strict && _a->value_ctr.values[0].blob->length != 4) { \
614                 d_printf("%s: %s length == %u\n", __location__, attr, \
615                         _a->value_ctr.values[0].blob->length); \
616                 return WERR_INVALID_PARAM; \
617         } \
618         if (_a && _a->value_ctr.num_values >= 1 \
619             && _a->value_ctr.values[0].blob \
620             && _a->value_ctr.values[0].blob->length == 4) { \
621                 (p)->elem = (IVAL(_a->value_ctr.values[0].blob->data,0)?True:False);\
622         } else { \
623                 (p)->elem = False; \
624         } \
625 } while (0)
626
627 #define GET_UINT32_DS(s, r, attr, p, elem) do { \
628         struct drsuapi_DsReplicaAttribute *_a; \
629         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
630         if (_a && _a->value_ctr.num_values >= 1 \
631             && _a->value_ctr.values[0].blob \
632             && _a->value_ctr.values[0].blob->length == 4) { \
633                 (p)->elem = IVAL(_a->value_ctr.values[0].blob->data,0);\
634         } else { \
635                 (p)->elem = 0; \
636         } \
637 } while (0)
638
639 #define GET_GUID_DS(s, r, attr, mem_ctx, p, elem) do { \
640         struct drsuapi_DsReplicaAttribute *_a; \
641         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
642         if (_a && _a->value_ctr.num_values >= 1 \
643             && _a->value_ctr.values[0].blob \
644             && _a->value_ctr.values[0].blob->length == 16) { \
645                 NTSTATUS _nt_status; \
646                 _nt_status = ndr_pull_struct_blob_all(_a->value_ctr.values[0].blob, \
647                                                       mem_ctx, &(p)->elem, \
648                                                       (ndr_pull_flags_fn_t)ndr_pull_GUID); \
649                 if (!NT_STATUS_IS_OK(_nt_status)) { \
650                         return ntstatus_to_werror(_nt_status); \
651                 } \
652         } else { \
653                 ZERO_STRUCT((p)->elem);\
654         } \
655 } while (0)
656
657 #define GET_BLOB_DS(s, r, attr, mem_ctx, p, elem) do { \
658         struct drsuapi_DsReplicaAttribute *_a; \
659         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
660         if (_a && _a->value_ctr.num_values >= 1 \
661             && _a->value_ctr.values[0].blob) { \
662                 (p)->elem = *_a->value_ctr.values[0].blob;\
663                 talloc_steal(mem_ctx, (p)->elem.data); \
664         } else { \
665                 ZERO_STRUCT((p)->elem);\
666         }\
667 } while (0)
668
669 WERROR dsdb_attribute_from_drsuapi(struct dsdb_schema *schema,
670                                    struct drsuapi_DsReplicaObject *r,
671                                    TALLOC_CTX *mem_ctx,
672                                    struct dsdb_attribute *attr)
673 {
674         WERROR status;
675
676         GET_STRING_DS(schema, r, "name", mem_ctx, attr, cn, True);
677         GET_STRING_DS(schema, r, "lDAPDisplayName", mem_ctx, attr, lDAPDisplayName, True);
678         GET_UINT32_DS(schema, r, "attributeID", attr, attributeID_id);
679         status = dsdb_map_int2oid(schema, attr->attributeID_id, mem_ctx, &attr->attributeID_oid);
680         if (!W_ERROR_IS_OK(status)) {
681                 DEBUG(0,("%s: '%s': unable to map attributeID 0x%08X: %s\n",
682                         __location__, attr->lDAPDisplayName, attr->attributeID_id,
683                         win_errstr(status)));
684                 return status;
685         }
686         GET_GUID_DS(schema, r, "schemaIDGUID", mem_ctx, attr, schemaIDGUID);
687         GET_UINT32_DS(schema, r, "mAPIID", attr, mAPIID);
688
689         GET_GUID_DS(schema, r, "attributeSecurityGUID", mem_ctx, attr, attributeSecurityGUID);
690
691         GET_UINT32_DS(schema, r, "searchFlags", attr, searchFlags);
692         GET_UINT32_DS(schema, r, "systemFlags", attr, systemFlags);
693         GET_BOOL_DS(schema, r, "isMemberOfPartialAttributeSet", attr, isMemberOfPartialAttributeSet, False);
694         GET_UINT32_DS(schema, r, "linkID", attr, linkID);
695
696         GET_UINT32_DS(schema, r, "attributeSyntax", attr, attributeSyntax_id);
697         status = dsdb_map_int2oid(schema, attr->attributeSyntax_id, mem_ctx, &attr->attributeSyntax_oid);
698         if (!W_ERROR_IS_OK(status)) {
699                 DEBUG(0,("%s: '%s': unable to map attributeSyntax 0x%08X: %s\n",
700                         __location__, attr->lDAPDisplayName, attr->attributeSyntax_id,
701                         win_errstr(status)));
702                 return status;
703         }
704         GET_UINT32_DS(schema, r, "oMSyntax", attr, oMSyntax);
705         GET_BLOB_DS(schema, r, "oMObjectClass", mem_ctx, attr, oMObjectClass);
706
707         GET_BOOL_DS(schema, r, "isSingleValued", attr, isSingleValued, True);
708         GET_UINT32_DS(schema, r, "rangeLower", attr, rangeLower);
709         GET_UINT32_DS(schema, r, "rangeUpper", attr, rangeUpper);
710         GET_BOOL_DS(schema, r, "extendedCharsAllowed", attr, extendedCharsAllowed, False);
711
712         GET_UINT32_DS(schema, r, "schemaFlagsEx", attr, schemaFlagsEx);
713         GET_BLOB_DS(schema, r, "msDs-Schema-Extensions", mem_ctx, attr, msDs_Schema_Extensions);
714
715         GET_BOOL_DS(schema, r, "showInAdvancedViewOnly", attr, showInAdvancedViewOnly, False);
716         GET_STRING_DS(schema, r, "adminDisplayName", mem_ctx, attr, adminDisplayName, False);
717         GET_STRING_DS(schema, r, "adminDescription", mem_ctx, attr, adminDescription, False);
718         GET_STRING_DS(schema, r, "classDisplayName", mem_ctx, attr, classDisplayName, False);
719         GET_BOOL_DS(schema, r, "isEphemeral", attr, isEphemeral, False);
720         GET_BOOL_DS(schema, r, "isDefunct", attr, isDefunct, False);
721         GET_BOOL_DS(schema, r, "systemOnly", attr, systemOnly, False);
722
723         attr->syntax = dsdb_syntax_for_attribute(attr);
724         if (!attr->syntax) {
725                 return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
726         }
727
728         return WERR_OK;
729 }
730
731 WERROR dsdb_class_from_drsuapi(struct dsdb_schema *schema,
732                                struct drsuapi_DsReplicaObject *r,
733                                TALLOC_CTX *mem_ctx,
734                                struct dsdb_class *obj)
735 {
736         WERROR status;
737
738         GET_STRING_DS(schema, r, "name", mem_ctx, obj, cn, True);
739         GET_STRING_DS(schema, r, "lDAPDisplayName", mem_ctx, obj, lDAPDisplayName, True);
740         GET_UINT32_DS(schema, r, "governsID", obj, governsID_id);
741         status = dsdb_map_int2oid(schema, obj->governsID_id, mem_ctx, &obj->governsID_oid);
742         if (!W_ERROR_IS_OK(status)) {
743                 DEBUG(0,("%s: '%s': unable to map governsID 0x%08X: %s\n",
744                         __location__, obj->lDAPDisplayName, obj->governsID_id,
745                         win_errstr(status)));
746                 return status;
747         }
748         GET_GUID_DS(schema, r, "schemaIDGUID", mem_ctx, obj, schemaIDGUID);
749
750         GET_UINT32_DS(schema, r, "objectClassCategory", obj, objectClassCategory);
751         GET_STRING_DS(schema, r, "rDNAttID", mem_ctx, obj, rDNAttID, False);
752         GET_DN_DS(schema, r, "defaultObjectCategory", mem_ctx, obj, defaultObjectCategory, True);
753
754         GET_STRING_DS(schema, r, "subClassOf", mem_ctx, obj, subClassOf, True);
755
756         obj->systemAuxiliaryClass       = NULL;
757         obj->systemPossSuperiors        = NULL;
758         obj->systemMustContain          = NULL;
759         obj->systemMayContain           = NULL;
760
761         obj->auxiliaryClass             = NULL;
762         obj->possSuperiors              = NULL;
763         obj->mustContain                = NULL;
764         obj->mayContain                 = NULL;
765
766         GET_STRING_DS(schema, r, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, False);
767
768         GET_UINT32_DS(schema, r, "schemaFlagsEx", obj, schemaFlagsEx);
769         GET_BLOB_DS(schema, r, "msDs-Schema-Extensions", mem_ctx, obj, msDs_Schema_Extensions);
770
771         GET_BOOL_DS(schema, r, "showInAdvancedViewOnly", obj, showInAdvancedViewOnly, False);
772         GET_STRING_DS(schema, r, "adminDisplayName", mem_ctx, obj, adminDisplayName, False);
773         GET_STRING_DS(schema, r, "adminDescription", mem_ctx, obj, adminDescription, False);
774         GET_STRING_DS(schema, r, "classDisplayName", mem_ctx, obj, classDisplayName, False);
775         GET_BOOL_DS(schema, r, "defaultHidingValue", obj, defaultHidingValue, False);
776         GET_BOOL_DS(schema, r, "isDefunct", obj, isDefunct, False);
777         GET_BOOL_DS(schema, r, "systemOnly", obj, systemOnly, False);
778
779         return WERR_OK;
780 }
781
782 const struct dsdb_attribute *dsdb_attribute_by_attributeID_id(const struct dsdb_schema *schema,
783                                                               uint32_t id)
784 {
785         struct dsdb_attribute *cur;
786
787         /*
788          * 0xFFFFFFFF is used as value when no mapping table is available,
789          * so don't try to match with it
790          */
791         if (id == 0xFFFFFFFF) return NULL;
792
793         /* TODO: add binary search */
794         for (cur = schema->attributes; cur; cur = cur->next) {
795                 if (cur->attributeID_id != id) continue;
796
797                 return cur;
798         }
799
800         return NULL;
801 }
802
803 const struct dsdb_attribute *dsdb_attribute_by_attributeID_oid(const struct dsdb_schema *schema,
804                                                                const char *oid)
805 {
806         struct dsdb_attribute *cur;
807
808         if (!oid) return NULL;
809
810         /* TODO: add binary search */
811         for (cur = schema->attributes; cur; cur = cur->next) {
812                 if (strcmp(cur->attributeID_oid, oid) != 0) continue;
813
814                 return cur;
815         }
816
817         return NULL;
818 }
819
820 const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema *schema,
821                                                                const char *name)
822 {
823         struct dsdb_attribute *cur;
824
825         if (!name) return NULL;
826
827         /* TODO: add binary search */
828         for (cur = schema->attributes; cur; cur = cur->next) {
829                 if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue;
830
831                 return cur;
832         }
833
834         return NULL;
835 }
836
837 const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *schema,
838                                                     uint32_t id)
839 {
840         struct dsdb_class *cur;
841
842         /*
843          * 0xFFFFFFFF is used as value when no mapping table is available,
844          * so don't try to match with it
845          */
846         if (id == 0xFFFFFFFF) return NULL;
847
848         /* TODO: add binary search */
849         for (cur = schema->classes; cur; cur = cur->next) {
850                 if (cur->governsID_id != id) continue;
851
852                 return cur;
853         }
854
855         return NULL;
856 }
857
858 const struct dsdb_class *dsdb_class_by_governsID_oid(const struct dsdb_schema *schema,
859                                                      const char *oid)
860 {
861         struct dsdb_class *cur;
862
863         if (!oid) return NULL;
864
865         /* TODO: add binary search */
866         for (cur = schema->classes; cur; cur = cur->next) {
867                 if (strcmp(cur->governsID_oid, oid) != 0) continue;
868
869                 return cur;
870         }
871
872         return NULL;
873 }
874
875 const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema *schema,
876                                                        const char *name)
877 {
878         struct dsdb_class *cur;
879
880         if (!name) return NULL;
881
882         /* TODO: add binary search */
883         for (cur = schema->classes; cur; cur = cur->next) {
884                 if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue;
885
886                 return cur;
887         }
888
889         return NULL;
890 }
891
892 const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
893                                        uint32_t id)
894 {
895         const struct dsdb_attribute *a;
896         const struct dsdb_class *c;
897
898         /* TODO: add binary search */
899         a = dsdb_attribute_by_attributeID_id(schema, id);
900         if (a) {
901                 return a->lDAPDisplayName;
902         }
903
904         c = dsdb_class_by_governsID_id(schema, id);
905         if (c) {
906                 return c->lDAPDisplayName;
907         }
908
909         return NULL;
910 }
911
912 int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
913 {
914         int ret;
915
916         ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
917         if (ret != LDB_SUCCESS) {
918                 return ret;
919         }
920
921         talloc_steal(ldb, schema);
922
923         return LDB_SUCCESS;
924 }
925
926 const struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb)
927 {
928         const void *p;
929         const struct dsdb_schema *schema;
930
931         /* see if we have a cached copy */
932         p = ldb_get_opaque(ldb, "dsdb_schema");
933         if (!p) {
934                 return NULL;
935         }
936
937         schema = talloc_get_type(p, struct dsdb_schema);
938         if (!schema) {
939                 return NULL;
940         }
941
942         return schema;
943 }