r21839: add my email address
[samba.git] / source4 / dsdb / schema / schema_init.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    DSDB schema header
4    
5    Copyright (C) Stefan Metzmacher <metze@samba.org> 2006
6     
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(const struct dsdb_schema *schema,
365                                struct ldb_message *msg,
366                                TALLOC_CTX *mem_ctx,
367                                struct dsdb_attribute *attr)
368 {
369         WERROR status;
370
371         GET_STRING_LDB(msg, "cn", mem_ctx, attr, cn, True);
372         GET_STRING_LDB(msg, "lDAPDisplayName", mem_ctx, attr, lDAPDisplayName, True);
373         GET_STRING_LDB(msg, "attributeID", mem_ctx, attr, attributeID_oid, True);
374         if (schema->num_prefixes == 0) {
375                 /* set an invalid value */
376                 attr->attributeID_id = 0xFFFFFFFF;
377         } else {
378                 status = dsdb_map_oid2int(schema, attr->attributeID_oid, &attr->attributeID_id);
379                 if (!W_ERROR_IS_OK(status)) {
380                         DEBUG(0,("%s: '%s': unable to map attributeID %s: %s\n",
381                                 __location__, attr->lDAPDisplayName, attr->attributeID_oid,
382                                 win_errstr(status)));
383                         return status;
384                 }
385         }
386         GET_GUID_LDB(msg, "schemaIDGUID", attr, schemaIDGUID);
387         GET_UINT32_LDB(msg, "mAPIID", attr, mAPIID);
388
389         GET_GUID_LDB(msg, "attributeSecurityGUID", attr, attributeSecurityGUID);
390
391         GET_UINT32_LDB(msg, "searchFlags", attr, searchFlags);
392         GET_UINT32_LDB(msg, "systemFlags", attr, systemFlags);
393         GET_BOOL_LDB(msg, "isMemberOfPartialAttributeSet", attr, isMemberOfPartialAttributeSet, False);
394         GET_UINT32_LDB(msg, "linkID", attr, linkID);
395
396         GET_STRING_LDB(msg, "attributeSyntax", mem_ctx, attr, attributeSyntax_oid, True);
397         if (schema->num_prefixes == 0) {
398                 /* set an invalid value */
399                 attr->attributeSyntax_id = 0xFFFFFFFF;
400         } else {
401                 status = dsdb_map_oid2int(schema, attr->attributeSyntax_oid, &attr->attributeSyntax_id);
402                 if (!W_ERROR_IS_OK(status)) {
403                         DEBUG(0,("%s: '%s': unable to map attributeSyntax_ %s: %s\n",
404                                 __location__, attr->lDAPDisplayName, attr->attributeSyntax_oid,
405                                 win_errstr(status)));
406                         return status;
407                 }
408         }
409         GET_UINT32_LDB(msg, "oMSyntax", attr, oMSyntax);
410         GET_BLOB_LDB(msg, "oMObjectClass", mem_ctx, attr, oMObjectClass);
411
412         GET_BOOL_LDB(msg, "isSingleValued", attr, isSingleValued, True);
413         GET_UINT32_LDB(msg, "rangeLower", attr, rangeLower);
414         GET_UINT32_LDB(msg, "rangeUpper", attr, rangeUpper);
415         GET_BOOL_LDB(msg, "extendedCharsAllowed", attr, extendedCharsAllowed, False);
416
417         GET_UINT32_LDB(msg, "schemaFlagsEx", attr, schemaFlagsEx);
418         GET_BLOB_LDB(msg, "msDs-Schema-Extensions", mem_ctx, attr, msDs_Schema_Extensions);
419
420         GET_BOOL_LDB(msg, "showInAdvancedViewOnly", attr, showInAdvancedViewOnly, False);
421         GET_STRING_LDB(msg, "adminDisplayName", mem_ctx, attr, adminDisplayName, False);
422         GET_STRING_LDB(msg, "adminDescription", mem_ctx, attr, adminDescription, False);
423         GET_STRING_LDB(msg, "classDisplayName", mem_ctx, attr, classDisplayName, False);
424         GET_BOOL_LDB(msg, "isEphemeral", attr, isEphemeral, False);
425         GET_BOOL_LDB(msg, "isDefunct", attr, isDefunct, False);
426         GET_BOOL_LDB(msg, "systemOnly", attr, systemOnly, False);
427
428         attr->syntax = dsdb_syntax_for_attribute(attr);
429         if (!attr->syntax) {
430                 return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
431         }
432
433         return WERR_OK;
434 }
435
436 WERROR dsdb_class_from_ldb(const struct dsdb_schema *schema,
437                            struct ldb_message *msg,
438                            TALLOC_CTX *mem_ctx,
439                            struct dsdb_class *obj)
440 {
441         WERROR status;
442
443         GET_STRING_LDB(msg, "cn", mem_ctx, obj, cn, True);
444         GET_STRING_LDB(msg, "lDAPDisplayName", mem_ctx, obj, lDAPDisplayName, True);
445         GET_STRING_LDB(msg, "governsID", mem_ctx, obj, governsID_oid, True);
446         if (schema->num_prefixes == 0) {
447                 /* set an invalid value */
448                 obj->governsID_id = 0xFFFFFFFF;
449         } else {
450                 status = dsdb_map_oid2int(schema, obj->governsID_oid, &obj->governsID_id);
451                 if (!W_ERROR_IS_OK(status)) {
452                         DEBUG(0,("%s: '%s': unable to map governsID %s: %s\n",
453                                 __location__, obj->lDAPDisplayName, obj->governsID_oid,
454                                 win_errstr(status)));
455                         return status;
456                 }
457         }
458         GET_GUID_LDB(msg, "schemaIDGUID", obj, schemaIDGUID);
459
460         GET_UINT32_LDB(msg, "objectClassCategory", obj, objectClassCategory);
461         GET_STRING_LDB(msg, "rDNAttID", mem_ctx, obj, rDNAttID, False);
462         GET_STRING_LDB(msg, "defaultObjectCategory", mem_ctx, obj, defaultObjectCategory, True);
463  
464         GET_STRING_LDB(msg, "subClassOf", mem_ctx, obj, subClassOf, True);
465
466         obj->systemAuxiliaryClass       = NULL;
467         obj->systemPossSuperiors        = NULL;
468         obj->systemMustContain          = NULL;
469         obj->systemMayContain           = NULL;
470
471         obj->auxiliaryClass             = NULL;
472         obj->possSuperiors              = NULL;
473         obj->mustContain                = NULL;
474         obj->mayContain                 = NULL;
475
476         GET_STRING_LDB(msg, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, False);
477
478         GET_UINT32_LDB(msg, "schemaFlagsEx", obj, schemaFlagsEx);
479         GET_BLOB_LDB(msg, "msDs-Schema-Extensions", mem_ctx, obj, msDs_Schema_Extensions);
480
481         GET_BOOL_LDB(msg, "showInAdvancedViewOnly", obj, showInAdvancedViewOnly, False);
482         GET_STRING_LDB(msg, "adminDisplayName", mem_ctx, obj, adminDisplayName, False);
483         GET_STRING_LDB(msg, "adminDescription", mem_ctx, obj, adminDescription, False);
484         GET_STRING_LDB(msg, "classDisplayName", mem_ctx, obj, classDisplayName, False);
485         GET_BOOL_LDB(msg, "defaultHidingValue", obj, defaultHidingValue, False);
486         GET_BOOL_LDB(msg, "isDefunct", obj, isDefunct, False);
487         GET_BOOL_LDB(msg, "systemOnly", obj, systemOnly, False);
488
489         return WERR_OK;
490 }
491
492 static const struct {
493         const char *name;
494         const char *oid;
495 } name_mappings[] = {
496         { "cn",                                 "2.5.4.3" },
497         { "name",                               "1.2.840.113556.1.4.1" },
498         { "lDAPDisplayName",                    "1.2.840.113556.1.2.460" },
499         { "attributeID",                        "1.2.840.113556.1.2.30" },
500         { "schemaIDGUID",                       "1.2.840.113556.1.4.148" },
501         { "mAPIID",                             "1.2.840.113556.1.2.49" },
502         { "attributeSecurityGUID",              "1.2.840.113556.1.4.149" },
503         { "searchFlags",                        "1.2.840.113556.1.2.334" },
504         { "systemFlags",                        "1.2.840.113556.1.4.375" },
505         { "isMemberOfPartialAttributeSet",      "1.2.840.113556.1.4.639" },
506         { "linkID",                             "1.2.840.113556.1.2.50" },
507         { "attributeSyntax",                    "1.2.840.113556.1.2.32" },
508         { "oMSyntax",                           "1.2.840.113556.1.2.231" },
509         { "oMObjectClass",                      "1.2.840.113556.1.2.218" },
510         { "isSingleValued",                     "1.2.840.113556.1.2.33" },
511         { "rangeLower",                         "1.2.840.113556.1.2.34" },
512         { "rangeUpper",                         "1.2.840.113556.1.2.35" },
513         { "extendedCharsAllowed",               "1.2.840.113556.1.2.380" },
514         { "schemaFlagsEx",                      "1.2.840.113556.1.4.120" },
515         { "msDs-Schema-Extensions",             "1.2.840.113556.1.4.1440" },
516         { "showInAdvancedViewOnly",             "1.2.840.113556.1.2.169" },
517         { "adminDisplayName",                   "1.2.840.113556.1.2.194" },
518         { "adminDescription",                   "1.2.840.113556.1.2.226" },
519         { "classDisplayName",                   "1.2.840.113556.1.4.610" },
520         { "isEphemeral",                        "1.2.840.113556.1.4.1212" },
521         { "isDefunct",                          "1.2.840.113556.1.4.661" },
522         { "systemOnly",                         "1.2.840.113556.1.4.170" },
523         { "governsID",                          "1.2.840.113556.1.2.22" },
524         { "objectClassCategory",                "1.2.840.113556.1.2.370" },
525         { "rDNAttID",                           "1.2.840.113556.1.2.26" },
526         { "defaultObjectCategory",              "1.2.840.113556.1.4.783" },
527         { "subClassOf",                         "1.2.840.113556.1.2.21" },
528         { "systemAuxiliaryClass",               "1.2.840.113556.1.4.198" },
529         { "systemPossSuperiors",                "1.2.840.113556.1.4.195" },
530         { "systemMustContain",                  "1.2.840.113556.1.4.197" },
531         { "systemMayContain",                   "1.2.840.113556.1.4.196" },
532         { "auxiliaryClass",                     "1.2.840.113556.1.2.351" },
533         { "possSuperiors",                      "1.2.840.113556.1.2.8" },
534         { "mustContain",                        "1.2.840.113556.1.2.24" },
535         { "mayContain",                         "1.2.840.113556.1.2.25" },
536         { "defaultSecurityDescriptor",          "1.2.840.113556.1.4.224" },
537         { "defaultHidingValue",                 "1.2.840.113556.1.4.518" },
538 };
539
540 static struct drsuapi_DsReplicaAttribute *dsdb_find_object_attr_name(struct dsdb_schema *schema,
541                                                                      struct drsuapi_DsReplicaObject *obj,
542                                                                      const char *name,
543                                                                      uint32_t *idx)
544 {
545         WERROR status;
546         uint32_t i, id;
547         const char *oid = NULL;
548
549         for(i=0; i < ARRAY_SIZE(name_mappings); i++) {
550                 if (strcmp(name_mappings[i].name, name) != 0) continue;
551
552                 oid = name_mappings[i].oid;
553                 break;
554         }
555
556         if (!oid) {
557                 return NULL;
558         }
559
560         status = dsdb_map_oid2int(schema, oid, &id);
561         if (!W_ERROR_IS_OK(status)) {
562                 return NULL;
563         }
564
565         for (i=0; i < obj->attribute_ctr.num_attributes; i++) {
566                 if (obj->attribute_ctr.attributes[i].attid != id) continue;
567
568                 if (idx) *idx = i;
569                 return &obj->attribute_ctr.attributes[i];
570         }
571
572         return NULL;
573 }
574
575 #define GET_STRING_DS(s, r, attr, mem_ctx, p, elem, strict) do { \
576         struct drsuapi_DsReplicaAttribute *_a; \
577         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
578         if (strict && !_a) { \
579                 d_printf("%s: %s == NULL\n", __location__, attr); \
580                 return WERR_INVALID_PARAM; \
581         } \
582         if (strict && _a->value_ctr.num_values != 1) { \
583                 d_printf("%s: %s num_values == %u\n", __location__, attr, \
584                         _a->value_ctr.num_values); \
585                 return WERR_INVALID_PARAM; \
586         } \
587         if (_a && _a->value_ctr.num_values >= 1) { \
588                 ssize_t _ret; \
589                 _ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, \
590                                              _a->value_ctr.values[0].blob->data, \
591                                              _a->value_ctr.values[0].blob->length, \
592                                              (void **)discard_const(&(p)->elem)); \
593                 if (_ret == -1) { \
594                         DEBUG(0,("%s: invalid data!\n", attr)); \
595                         dump_data(0, \
596                                      _a->value_ctr.values[0].blob->data, \
597                                      _a->value_ctr.values[0].blob->length); \
598                         return WERR_FOOBAR; \
599                 } \
600         } else { \
601                 (p)->elem = NULL; \
602         } \
603 } while (0)
604
605 #define GET_DN_DS(s, r, attr, mem_ctx, p, elem, strict) do { \
606         struct drsuapi_DsReplicaAttribute *_a; \
607         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
608         if (strict && !_a) { \
609                 d_printf("%s: %s == NULL\n", __location__, attr); \
610                 return WERR_INVALID_PARAM; \
611         } \
612         if (strict && _a->value_ctr.num_values != 1) { \
613                 d_printf("%s: %s num_values == %u\n", __location__, attr, \
614                         _a->value_ctr.num_values); \
615                 return WERR_INVALID_PARAM; \
616         } \
617         if (strict && !_a->value_ctr.values[0].blob) { \
618                 d_printf("%s: %s data == NULL\n", __location__, attr); \
619                 return WERR_INVALID_PARAM; \
620         } \
621         if (_a && _a->value_ctr.num_values >= 1 \
622             && _a->value_ctr.values[0].blob) { \
623                 struct drsuapi_DsReplicaObjectIdentifier3 _id3; \
624                 NTSTATUS _nt_status; \
625                 _nt_status = ndr_pull_struct_blob_all(_a->value_ctr.values[0].blob, \
626                                                       mem_ctx, &_id3,\
627                                                       (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);\
628                 if (!NT_STATUS_IS_OK(_nt_status)) { \
629                         return ntstatus_to_werror(_nt_status); \
630                 } \
631                 (p)->elem = _id3.dn; \
632         } else { \
633                 (p)->elem = NULL; \
634         } \
635 } while (0)
636
637 #define GET_BOOL_DS(s, r, attr, p, elem, strict) do { \
638         struct drsuapi_DsReplicaAttribute *_a; \
639         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
640         if (strict && !_a) { \
641                 d_printf("%s: %s == NULL\n", __location__, attr); \
642                 return WERR_INVALID_PARAM; \
643         } \
644         if (strict && _a->value_ctr.num_values != 1) { \
645                 d_printf("%s: %s num_values == %u\n", __location__, attr, \
646                         _a->value_ctr.num_values); \
647                 return WERR_INVALID_PARAM; \
648         } \
649         if (strict && !_a->value_ctr.values[0].blob) { \
650                 d_printf("%s: %s data == NULL\n", __location__, attr); \
651                 return WERR_INVALID_PARAM; \
652         } \
653         if (strict && _a->value_ctr.values[0].blob->length != 4) { \
654                 d_printf("%s: %s length == %u\n", __location__, attr, \
655                         _a->value_ctr.values[0].blob->length); \
656                 return WERR_INVALID_PARAM; \
657         } \
658         if (_a && _a->value_ctr.num_values >= 1 \
659             && _a->value_ctr.values[0].blob \
660             && _a->value_ctr.values[0].blob->length == 4) { \
661                 (p)->elem = (IVAL(_a->value_ctr.values[0].blob->data,0)?True:False);\
662         } else { \
663                 (p)->elem = False; \
664         } \
665 } while (0)
666
667 #define GET_UINT32_DS(s, r, attr, p, elem) do { \
668         struct drsuapi_DsReplicaAttribute *_a; \
669         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
670         if (_a && _a->value_ctr.num_values >= 1 \
671             && _a->value_ctr.values[0].blob \
672             && _a->value_ctr.values[0].blob->length == 4) { \
673                 (p)->elem = IVAL(_a->value_ctr.values[0].blob->data,0);\
674         } else { \
675                 (p)->elem = 0; \
676         } \
677 } while (0)
678
679 #define GET_GUID_DS(s, r, attr, mem_ctx, p, elem) do { \
680         struct drsuapi_DsReplicaAttribute *_a; \
681         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
682         if (_a && _a->value_ctr.num_values >= 1 \
683             && _a->value_ctr.values[0].blob \
684             && _a->value_ctr.values[0].blob->length == 16) { \
685                 NTSTATUS _nt_status; \
686                 _nt_status = ndr_pull_struct_blob_all(_a->value_ctr.values[0].blob, \
687                                                       mem_ctx, &(p)->elem, \
688                                                       (ndr_pull_flags_fn_t)ndr_pull_GUID); \
689                 if (!NT_STATUS_IS_OK(_nt_status)) { \
690                         return ntstatus_to_werror(_nt_status); \
691                 } \
692         } else { \
693                 ZERO_STRUCT((p)->elem);\
694         } \
695 } while (0)
696
697 #define GET_BLOB_DS(s, r, attr, mem_ctx, p, elem) do { \
698         struct drsuapi_DsReplicaAttribute *_a; \
699         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
700         if (_a && _a->value_ctr.num_values >= 1 \
701             && _a->value_ctr.values[0].blob) { \
702                 (p)->elem = *_a->value_ctr.values[0].blob;\
703                 talloc_steal(mem_ctx, (p)->elem.data); \
704         } else { \
705                 ZERO_STRUCT((p)->elem);\
706         }\
707 } while (0)
708
709 WERROR dsdb_attribute_from_drsuapi(struct dsdb_schema *schema,
710                                    struct drsuapi_DsReplicaObject *r,
711                                    TALLOC_CTX *mem_ctx,
712                                    struct dsdb_attribute *attr)
713 {
714         WERROR status;
715
716         GET_STRING_DS(schema, r, "name", mem_ctx, attr, cn, True);
717         GET_STRING_DS(schema, r, "lDAPDisplayName", mem_ctx, attr, lDAPDisplayName, True);
718         GET_UINT32_DS(schema, r, "attributeID", attr, attributeID_id);
719         status = dsdb_map_int2oid(schema, attr->attributeID_id, mem_ctx, &attr->attributeID_oid);
720         if (!W_ERROR_IS_OK(status)) {
721                 DEBUG(0,("%s: '%s': unable to map attributeID 0x%08X: %s\n",
722                         __location__, attr->lDAPDisplayName, attr->attributeID_id,
723                         win_errstr(status)));
724                 return status;
725         }
726         GET_GUID_DS(schema, r, "schemaIDGUID", mem_ctx, attr, schemaIDGUID);
727         GET_UINT32_DS(schema, r, "mAPIID", attr, mAPIID);
728
729         GET_GUID_DS(schema, r, "attributeSecurityGUID", mem_ctx, attr, attributeSecurityGUID);
730
731         GET_UINT32_DS(schema, r, "searchFlags", attr, searchFlags);
732         GET_UINT32_DS(schema, r, "systemFlags", attr, systemFlags);
733         GET_BOOL_DS(schema, r, "isMemberOfPartialAttributeSet", attr, isMemberOfPartialAttributeSet, False);
734         GET_UINT32_DS(schema, r, "linkID", attr, linkID);
735
736         GET_UINT32_DS(schema, r, "attributeSyntax", attr, attributeSyntax_id);
737         status = dsdb_map_int2oid(schema, attr->attributeSyntax_id, mem_ctx, &attr->attributeSyntax_oid);
738         if (!W_ERROR_IS_OK(status)) {
739                 DEBUG(0,("%s: '%s': unable to map attributeSyntax 0x%08X: %s\n",
740                         __location__, attr->lDAPDisplayName, attr->attributeSyntax_id,
741                         win_errstr(status)));
742                 return status;
743         }
744         GET_UINT32_DS(schema, r, "oMSyntax", attr, oMSyntax);
745         GET_BLOB_DS(schema, r, "oMObjectClass", mem_ctx, attr, oMObjectClass);
746
747         GET_BOOL_DS(schema, r, "isSingleValued", attr, isSingleValued, True);
748         GET_UINT32_DS(schema, r, "rangeLower", attr, rangeLower);
749         GET_UINT32_DS(schema, r, "rangeUpper", attr, rangeUpper);
750         GET_BOOL_DS(schema, r, "extendedCharsAllowed", attr, extendedCharsAllowed, False);
751
752         GET_UINT32_DS(schema, r, "schemaFlagsEx", attr, schemaFlagsEx);
753         GET_BLOB_DS(schema, r, "msDs-Schema-Extensions", mem_ctx, attr, msDs_Schema_Extensions);
754
755         GET_BOOL_DS(schema, r, "showInAdvancedViewOnly", attr, showInAdvancedViewOnly, False);
756         GET_STRING_DS(schema, r, "adminDisplayName", mem_ctx, attr, adminDisplayName, False);
757         GET_STRING_DS(schema, r, "adminDescription", mem_ctx, attr, adminDescription, False);
758         GET_STRING_DS(schema, r, "classDisplayName", mem_ctx, attr, classDisplayName, False);
759         GET_BOOL_DS(schema, r, "isEphemeral", attr, isEphemeral, False);
760         GET_BOOL_DS(schema, r, "isDefunct", attr, isDefunct, False);
761         GET_BOOL_DS(schema, r, "systemOnly", attr, systemOnly, False);
762
763         attr->syntax = dsdb_syntax_for_attribute(attr);
764         if (!attr->syntax) {
765                 return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
766         }
767
768         return WERR_OK;
769 }
770
771 WERROR dsdb_class_from_drsuapi(struct dsdb_schema *schema,
772                                struct drsuapi_DsReplicaObject *r,
773                                TALLOC_CTX *mem_ctx,
774                                struct dsdb_class *obj)
775 {
776         WERROR status;
777
778         GET_STRING_DS(schema, r, "name", mem_ctx, obj, cn, True);
779         GET_STRING_DS(schema, r, "lDAPDisplayName", mem_ctx, obj, lDAPDisplayName, True);
780         GET_UINT32_DS(schema, r, "governsID", obj, governsID_id);
781         status = dsdb_map_int2oid(schema, obj->governsID_id, mem_ctx, &obj->governsID_oid);
782         if (!W_ERROR_IS_OK(status)) {
783                 DEBUG(0,("%s: '%s': unable to map governsID 0x%08X: %s\n",
784                         __location__, obj->lDAPDisplayName, obj->governsID_id,
785                         win_errstr(status)));
786                 return status;
787         }
788         GET_GUID_DS(schema, r, "schemaIDGUID", mem_ctx, obj, schemaIDGUID);
789
790         GET_UINT32_DS(schema, r, "objectClassCategory", obj, objectClassCategory);
791         GET_STRING_DS(schema, r, "rDNAttID", mem_ctx, obj, rDNAttID, False);
792         GET_DN_DS(schema, r, "defaultObjectCategory", mem_ctx, obj, defaultObjectCategory, True);
793
794         GET_STRING_DS(schema, r, "subClassOf", mem_ctx, obj, subClassOf, True);
795
796         obj->systemAuxiliaryClass       = NULL;
797         obj->systemPossSuperiors        = NULL;
798         obj->systemMustContain          = NULL;
799         obj->systemMayContain           = NULL;
800
801         obj->auxiliaryClass             = NULL;
802         obj->possSuperiors              = NULL;
803         obj->mustContain                = NULL;
804         obj->mayContain                 = NULL;
805
806         GET_STRING_DS(schema, r, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, False);
807
808         GET_UINT32_DS(schema, r, "schemaFlagsEx", obj, schemaFlagsEx);
809         GET_BLOB_DS(schema, r, "msDs-Schema-Extensions", mem_ctx, obj, msDs_Schema_Extensions);
810
811         GET_BOOL_DS(schema, r, "showInAdvancedViewOnly", obj, showInAdvancedViewOnly, False);
812         GET_STRING_DS(schema, r, "adminDisplayName", mem_ctx, obj, adminDisplayName, False);
813         GET_STRING_DS(schema, r, "adminDescription", mem_ctx, obj, adminDescription, False);
814         GET_STRING_DS(schema, r, "classDisplayName", mem_ctx, obj, classDisplayName, False);
815         GET_BOOL_DS(schema, r, "defaultHidingValue", obj, defaultHidingValue, False);
816         GET_BOOL_DS(schema, r, "isDefunct", obj, isDefunct, False);
817         GET_BOOL_DS(schema, r, "systemOnly", obj, systemOnly, False);
818
819         return WERR_OK;
820 }
821
822 const struct dsdb_attribute *dsdb_attribute_by_attributeID_id(const struct dsdb_schema *schema,
823                                                               uint32_t id)
824 {
825         struct dsdb_attribute *cur;
826
827         /*
828          * 0xFFFFFFFF is used as value when no mapping table is available,
829          * so don't try to match with it
830          */
831         if (id == 0xFFFFFFFF) return NULL;
832
833         /* TODO: add binary search */
834         for (cur = schema->attributes; cur; cur = cur->next) {
835                 if (cur->attributeID_id != id) continue;
836
837                 return cur;
838         }
839
840         return NULL;
841 }
842
843 const struct dsdb_attribute *dsdb_attribute_by_attributeID_oid(const struct dsdb_schema *schema,
844                                                                const char *oid)
845 {
846         struct dsdb_attribute *cur;
847
848         if (!oid) return NULL;
849
850         /* TODO: add binary search */
851         for (cur = schema->attributes; cur; cur = cur->next) {
852                 if (strcmp(cur->attributeID_oid, oid) != 0) continue;
853
854                 return cur;
855         }
856
857         return NULL;
858 }
859
860 const struct dsdb_attribute *dsdb_attribute_by_lDAPDisplayName(const struct dsdb_schema *schema,
861                                                                const char *name)
862 {
863         struct dsdb_attribute *cur;
864
865         if (!name) return NULL;
866
867         /* TODO: add binary search */
868         for (cur = schema->attributes; cur; cur = cur->next) {
869                 if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue;
870
871                 return cur;
872         }
873
874         return NULL;
875 }
876
877 const struct dsdb_class *dsdb_class_by_governsID_id(const struct dsdb_schema *schema,
878                                                     uint32_t id)
879 {
880         struct dsdb_class *cur;
881
882         /*
883          * 0xFFFFFFFF is used as value when no mapping table is available,
884          * so don't try to match with it
885          */
886         if (id == 0xFFFFFFFF) return NULL;
887
888         /* TODO: add binary search */
889         for (cur = schema->classes; cur; cur = cur->next) {
890                 if (cur->governsID_id != id) continue;
891
892                 return cur;
893         }
894
895         return NULL;
896 }
897
898 const struct dsdb_class *dsdb_class_by_governsID_oid(const struct dsdb_schema *schema,
899                                                      const char *oid)
900 {
901         struct dsdb_class *cur;
902
903         if (!oid) return NULL;
904
905         /* TODO: add binary search */
906         for (cur = schema->classes; cur; cur = cur->next) {
907                 if (strcmp(cur->governsID_oid, oid) != 0) continue;
908
909                 return cur;
910         }
911
912         return NULL;
913 }
914
915 const struct dsdb_class *dsdb_class_by_lDAPDisplayName(const struct dsdb_schema *schema,
916                                                        const char *name)
917 {
918         struct dsdb_class *cur;
919
920         if (!name) return NULL;
921
922         /* TODO: add binary search */
923         for (cur = schema->classes; cur; cur = cur->next) {
924                 if (strcasecmp(cur->lDAPDisplayName, name) != 0) continue;
925
926                 return cur;
927         }
928
929         return NULL;
930 }
931
932 const char *dsdb_lDAPDisplayName_by_id(const struct dsdb_schema *schema,
933                                        uint32_t id)
934 {
935         const struct dsdb_attribute *a;
936         const struct dsdb_class *c;
937
938         /* TODO: add binary search */
939         a = dsdb_attribute_by_attributeID_id(schema, id);
940         if (a) {
941                 return a->lDAPDisplayName;
942         }
943
944         c = dsdb_class_by_governsID_id(schema, id);
945         if (c) {
946                 return c->lDAPDisplayName;
947         }
948
949         return NULL;
950 }
951
952 int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
953 {
954         int ret;
955
956         ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
957         if (ret != LDB_SUCCESS) {
958                 return ret;
959         }
960
961         talloc_steal(ldb, schema);
962
963         return LDB_SUCCESS;
964 }
965
966 const struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb)
967 {
968         const void *p;
969         const struct dsdb_schema *schema;
970
971         /* see if we have a cached copy */
972         p = ldb_get_opaque(ldb, "dsdb_schema");
973         if (!p) {
974                 return NULL;
975         }
976
977         schema = talloc_get_type(p, struct dsdb_schema);
978         if (!schema) {
979                 return NULL;
980         }
981
982         return schema;
983 }