Merge branch 'master' of ssh://jra@git.samba.org/data/git/samba
[sfrench/samba-autobuild/.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-2007
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2008
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20    
21 */
22
23 #include "includes.h"
24 #include "dsdb/samdb/samdb.h"
25 #include "lib/ldb/include/ldb_errors.h"
26 #include "../lib/util/dlinklist.h"
27 #include "librpc/gen_ndr/ndr_misc.h"
28 #include "librpc/gen_ndr/ndr_drsuapi.h"
29 #include "librpc/gen_ndr/ndr_drsblobs.h"
30 #include "param/param.h"
31 #include "lib/ldb/include/ldb_module.h"
32 #include "../lib/util/asn1.h"
33
34 static WERROR dsdb_read_prefixes_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, uint32_t* num_prefixes, struct dsdb_schema_oid_prefix **prefixes);
35
36 struct dsdb_schema *dsdb_new_schema(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience)
37 {
38         struct dsdb_schema *schema = talloc_zero(mem_ctx, struct dsdb_schema);
39         if (!schema) {
40                 return NULL;
41         }
42
43         schema->iconv_convenience = iconv_convenience;
44         return schema;
45 }
46
47
48 WERROR dsdb_load_oid_mappings_drsuapi(struct dsdb_schema *schema, const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
49 {
50         uint32_t i,j;
51
52         schema->prefixes = talloc_array(schema, struct dsdb_schema_oid_prefix, ctr->num_mappings);
53         W_ERROR_HAVE_NO_MEMORY(schema->prefixes);
54
55         for (i=0, j=0; i < ctr->num_mappings; i++) {
56                 if (ctr->mappings[i].oid.binary_oid == NULL) {
57                         return WERR_INVALID_PARAM;
58                 }
59
60                 if (ctr->mappings[i].oid.binary_oid[0] == 0xFF) {
61                         if (ctr->mappings[i].id_prefix != 0) {
62                                 return WERR_INVALID_PARAM;
63                         }
64
65                         /* the magic value should be in the last array member */
66                         if (i != (ctr->num_mappings - 1)) {
67                                 return WERR_INVALID_PARAM;
68                         }
69
70                         if (ctr->mappings[i].oid.length != 21) {
71                                 return WERR_INVALID_PARAM;
72                         }
73
74                         schema->schema_info = hex_encode_talloc(schema,
75                                                                 ctr->mappings[i].oid.binary_oid,
76                                                                 ctr->mappings[i].oid.length);
77                         W_ERROR_HAVE_NO_MEMORY(schema->schema_info);
78                 } else {
79                         DATA_BLOB oid_blob;
80                         const char *partial_oid = NULL;
81
82                         /* the last array member should contain the magic value not a oid */
83                         if (i == (ctr->num_mappings - 1)) {
84                                 return WERR_INVALID_PARAM;
85                         }
86
87                         oid_blob = data_blob_const(ctr->mappings[i].oid.binary_oid,
88                                                    ctr->mappings[i].oid.length);
89                         if (!ber_read_partial_OID_String(schema->prefixes, oid_blob, &partial_oid)) {
90                                 DEBUG(0, ("ber_read_partial_OID failed on prefixMap item with id: 0x%X",
91                                           ctr->mappings[i].id_prefix));
92                                 return WERR_INVALID_PARAM;
93                         }
94
95                         schema->prefixes[j].id  = ctr->mappings[i].id_prefix<<16;
96                         schema->prefixes[j].oid = partial_oid;
97                         W_ERROR_HAVE_NO_MEMORY(schema->prefixes[j].oid);
98                         schema->prefixes[j].oid_len = strlen(schema->prefixes[j].oid);
99                         j++;
100                 }
101         }
102
103         schema->num_prefixes = j;
104         return WERR_OK;
105 }
106
107 WERROR dsdb_load_oid_mappings_ldb(struct dsdb_schema *schema,
108                                   const struct ldb_val *prefixMap,
109                                   const struct ldb_val *schemaInfo)
110 {
111         WERROR status;
112         enum ndr_err_code ndr_err;
113         struct prefixMapBlob pfm;
114         DATA_BLOB schema_info_blob;
115
116         TALLOC_CTX *mem_ctx = talloc_new(schema);
117         W_ERROR_HAVE_NO_MEMORY(mem_ctx);
118         
119         ndr_err = ndr_pull_struct_blob(prefixMap, mem_ctx, schema->iconv_convenience, &pfm, (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
120         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
121                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
122                 talloc_free(mem_ctx);
123                 return ntstatus_to_werror(nt_status);
124         }
125
126         if (pfm.version != PREFIX_MAP_VERSION_DSDB) {
127                 talloc_free(mem_ctx);
128                 return WERR_FOOBAR;
129         }
130
131         if (schemaInfo->length != 21 && schemaInfo->data[0] == 0xFF) {
132                 talloc_free(mem_ctx);
133                 return WERR_FOOBAR;
134         }
135
136         /* append the schema info as last element */
137         pfm.ctr.dsdb.num_mappings++;
138         pfm.ctr.dsdb.mappings = talloc_realloc(mem_ctx, pfm.ctr.dsdb.mappings,
139                                                struct drsuapi_DsReplicaOIDMapping,
140                                                pfm.ctr.dsdb.num_mappings);
141         W_ERROR_HAVE_NO_MEMORY(pfm.ctr.dsdb.mappings);
142
143         schema_info_blob = data_blob_dup_talloc(pfm.ctr.dsdb.mappings, schemaInfo);
144         W_ERROR_HAVE_NO_MEMORY(schema_info_blob.data);
145
146         pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].id_prefix          = 0;    
147         pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].oid.length         = schemaInfo->length;
148         pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].oid.binary_oid     = schema_info_blob.data;
149
150         /* call the drsuapi version */
151         status = dsdb_load_oid_mappings_drsuapi(schema, &pfm.ctr.dsdb);
152         talloc_free(mem_ctx);
153
154         W_ERROR_NOT_OK_RETURN(status);
155
156         return WERR_OK;
157 }
158
159 WERROR dsdb_get_oid_mappings_drsuapi(const struct dsdb_schema *schema,
160                                      bool include_schema_info,
161                                      TALLOC_CTX *mem_ctx,
162                                      struct drsuapi_DsReplicaOIDMapping_Ctr **_ctr)
163 {
164         DATA_BLOB oid_blob;
165         struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
166         uint32_t i;
167
168         ctr = talloc(mem_ctx, struct drsuapi_DsReplicaOIDMapping_Ctr);
169         W_ERROR_HAVE_NO_MEMORY(ctr);
170
171         ctr->num_mappings       = schema->num_prefixes;
172         if (include_schema_info) ctr->num_mappings++;
173         ctr->mappings = talloc_array(schema, struct drsuapi_DsReplicaOIDMapping, ctr->num_mappings);
174         W_ERROR_HAVE_NO_MEMORY(ctr->mappings);
175
176         for (i=0; i < schema->num_prefixes; i++) {
177                 if (!ber_write_partial_OID_String(ctr->mappings, &oid_blob, schema->prefixes[i].oid)) {
178                         DEBUG(0, ("write_partial_OID failed for %s", schema->prefixes[i].oid));
179                         return WERR_INTERNAL_ERROR;
180                 }
181
182                 ctr->mappings[i].id_prefix      = schema->prefixes[i].id>>16;
183                 ctr->mappings[i].oid.length     = oid_blob.length;
184                 ctr->mappings[i].oid.binary_oid = oid_blob.data;
185         }
186
187         if (include_schema_info) {
188                 oid_blob = strhex_to_data_blob(ctr->mappings, schema->schema_info);
189                 W_ERROR_HAVE_NO_MEMORY(oid_blob.data);
190
191                 ctr->mappings[i].id_prefix      = 0;
192                 ctr->mappings[i].oid.length     = oid_blob.length;
193                 ctr->mappings[i].oid.binary_oid = oid_blob.data;
194         }
195
196         *_ctr = ctr;
197         return WERR_OK;
198 }
199
200 WERROR dsdb_get_oid_mappings_ldb(const struct dsdb_schema *schema,
201                                  TALLOC_CTX *mem_ctx,
202                                  struct ldb_val *prefixMap,
203                                  struct ldb_val *schemaInfo)
204 {
205         WERROR status;
206         enum ndr_err_code ndr_err;
207         struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
208         struct prefixMapBlob pfm;
209
210         status = dsdb_get_oid_mappings_drsuapi(schema, false, mem_ctx, &ctr);
211         W_ERROR_NOT_OK_RETURN(status);
212
213         pfm.version     = PREFIX_MAP_VERSION_DSDB;
214         pfm.reserved    = 0;
215         pfm.ctr.dsdb    = *ctr;
216
217         ndr_err = ndr_push_struct_blob(prefixMap, mem_ctx, schema->iconv_convenience, &pfm, (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
218         talloc_free(ctr);
219         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
220                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
221                 return ntstatus_to_werror(nt_status);
222         }
223
224         *schemaInfo = strhex_to_data_blob(mem_ctx, schema->schema_info);
225         W_ERROR_HAVE_NO_MEMORY(schemaInfo->data);
226
227         return WERR_OK;
228 }
229
230 WERROR dsdb_verify_oid_mappings_drsuapi(const struct dsdb_schema *schema, const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
231 {
232         uint32_t i,j;
233         DATA_BLOB oid_blob;
234
235         for (i=0; i < ctr->num_mappings; i++) {
236                 if (ctr->mappings[i].oid.binary_oid == NULL) {
237                         return WERR_INVALID_PARAM;
238                 }
239
240                 if (ctr->mappings[i].oid.binary_oid[0] == 0xFF) {
241                         if (ctr->mappings[i].id_prefix != 0) {
242                                 return WERR_INVALID_PARAM;
243                         }
244
245                         /* the magic value should be in the last array member */
246                         if (i != (ctr->num_mappings - 1)) {
247                                 return WERR_INVALID_PARAM;
248                         }
249
250                         if (ctr->mappings[i].oid.length != 21) {
251                                 return WERR_INVALID_PARAM;
252                         }
253
254                         oid_blob = strhex_to_data_blob(NULL, schema->schema_info);
255                         W_ERROR_HAVE_NO_MEMORY(oid_blob.data);
256
257                         if (memcmp(oid_blob.data, ctr->mappings[i].oid.binary_oid, 21) != 0) {
258                                 data_blob_free(&oid_blob);
259                                 return WERR_DS_DRA_SCHEMA_MISMATCH;
260                         }
261
262                         data_blob_free(&oid_blob);
263                 } else {
264                         /* the last array member should contain the magic value not a oid */
265                         if (i == (ctr->num_mappings - 1)) {
266                                 return WERR_INVALID_PARAM;
267                         }
268
269                         for (j=0; j < schema->num_prefixes; j++) {
270                                 if (schema->prefixes[j].id != (ctr->mappings[i].id_prefix<<16)) {
271                                         continue;
272                                 }
273
274                                 if (!ber_write_partial_OID_String(NULL, &oid_blob, schema->prefixes[j].oid)) {
275                                         return WERR_INTERNAL_ERROR;
276                                 }
277
278                                 if (oid_blob.length != ctr->mappings[j].oid.length) {
279                                         data_blob_free(&oid_blob);
280                                         return WERR_DS_DRA_SCHEMA_MISMATCH;
281                                 }
282
283                                 if (memcmp(ctr->mappings[i].oid.binary_oid, oid_blob.data, oid_blob.length) != 0) {
284                                         data_blob_free(&oid_blob);
285                                         return WERR_DS_DRA_SCHEMA_MISMATCH;
286                                 }
287
288                                 data_blob_free(&oid_blob);
289
290                                 break;
291                         }
292
293                         if (j == schema->num_prefixes) {
294                                 return WERR_DS_DRA_SCHEMA_MISMATCH;                             
295                         }
296                 }
297         }
298
299         return WERR_OK;
300 }
301
302 WERROR dsdb_map_oid2int(const struct dsdb_schema *schema, const char *in, uint32_t *out)
303 {
304         return dsdb_find_prefix_for_oid(schema->num_prefixes, schema->prefixes, in, out);
305 }
306
307
308 WERROR dsdb_map_int2oid(const struct dsdb_schema *schema, uint32_t in, TALLOC_CTX *mem_ctx, const char **out)
309 {
310         uint32_t i;
311
312         for (i=0; i < schema->num_prefixes; i++) {
313                 const char *val;
314                 if (schema->prefixes[i].id != (in & 0xFFFF0000)) {
315                         continue;
316                 }
317
318                 val = talloc_asprintf(mem_ctx, "%s.%u",
319                                       schema->prefixes[i].oid,
320                                       in & 0xFFFF);
321                 W_ERROR_HAVE_NO_MEMORY(val);
322
323                 *out = val;
324                 return WERR_OK;
325         }
326
327         return WERR_DS_NO_MSDS_INTID;
328 }
329
330 /*
331  * this function is called from within a ldb transaction from the schema_fsmo module
332  */
333 WERROR dsdb_create_prefix_mapping(struct ldb_context *ldb, struct dsdb_schema *schema, const char *full_oid)
334 {
335         WERROR status;
336         uint32_t num_prefixes;
337         struct dsdb_schema_oid_prefix *prefixes;
338         TALLOC_CTX *mem_ctx;
339         uint32_t out;
340
341         mem_ctx = talloc_new(ldb);
342         W_ERROR_HAVE_NO_MEMORY(mem_ctx);
343
344         /* Read prefixes from disk*/
345         status = dsdb_read_prefixes_from_ldb( mem_ctx, ldb, &num_prefixes, &prefixes ); 
346         if (!W_ERROR_IS_OK(status)) {
347                 DEBUG(0,("dsdb_create_prefix_mapping: dsdb_read_prefixes_from_ldb: %s\n",
348                         win_errstr(status)));
349                 talloc_free(mem_ctx);
350                 return status;
351         }
352
353         /* Check if there is a prefix for the oid in the prefixes array*/
354         status = dsdb_find_prefix_for_oid( num_prefixes, prefixes, full_oid, &out ); 
355         if (W_ERROR_IS_OK(status)) {
356                 /* prefix found*/
357                 talloc_free(mem_ctx);
358                 return status;
359         } else if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) {
360                 /* error */
361                 DEBUG(0,("dsdb_create_prefix_mapping: dsdb_find_prefix_for_oid: %s\n",
362                         win_errstr(status)));
363                 talloc_free(mem_ctx);
364                 return status;
365         }
366
367         /* Create the new mapping for the prefix of full_oid */
368         status = dsdb_prefix_map_update(mem_ctx, &num_prefixes, &prefixes, full_oid);
369         if (!W_ERROR_IS_OK(status)) {
370                 DEBUG(0,("dsdb_create_prefix_mapping: dsdb_prefix_map_update: %s\n",
371                         win_errstr(status)));
372                 talloc_free(mem_ctx);
373                 return status;
374         }
375
376         talloc_free(schema->prefixes);
377         schema->prefixes = talloc_steal(schema, prefixes);
378         schema->num_prefixes = num_prefixes;
379
380         /* Update prefixMap in ldb*/
381         status = dsdb_write_prefixes_from_schema_to_ldb(mem_ctx, ldb, schema);
382         if (!W_ERROR_IS_OK(status)) {
383                 DEBUG(0,("dsdb_create_prefix_mapping: dsdb_write_prefixes_to_ldb: %s\n",
384                         win_errstr(status)));
385                 talloc_free(mem_ctx);
386                 return status;
387         }
388
389         DEBUG(2,(__location__ " Added prefixMap %s - now have %u prefixes\n",
390                  full_oid, num_prefixes));
391
392         talloc_free(mem_ctx);
393         return status;
394 }
395
396 WERROR dsdb_prefix_map_update(TALLOC_CTX *mem_ctx, uint32_t *num_prefixes, struct dsdb_schema_oid_prefix **prefixes, const char *oid)
397 {
398         uint32_t new_num_prefixes, index_new_prefix, new_entry_id;
399         const char* lastDotOffset;
400         size_t size;
401         
402         new_num_prefixes = *num_prefixes + 1;
403         index_new_prefix = *num_prefixes;
404
405         /*
406          * this is the algorithm we use to create new mappings for now
407          *
408          * TODO: find what algorithm windows use
409          */
410         new_entry_id = (*num_prefixes)<<16;
411
412         /* Extract the prefix from the oid*/
413         lastDotOffset = strrchr(oid, '.');
414         if (lastDotOffset == NULL) {
415                 DEBUG(0,("dsdb_prefix_map_update: failed to find the last dot\n"));
416                 return WERR_NOT_FOUND;
417         }
418
419         /* Calculate the size of the remainig string that should be the prefix of it */
420         size = strlen(oid) - strlen(lastDotOffset);
421         if (size <= 0) {
422                 DEBUG(0,("dsdb_prefix_map_update: size of the remaining string invalid\n"));
423                 return WERR_FOOBAR;
424         }
425
426         /* Create a spot in the prefixMap for one more prefix*/
427         (*prefixes) = talloc_realloc(mem_ctx, *prefixes, struct dsdb_schema_oid_prefix, new_num_prefixes);
428         W_ERROR_HAVE_NO_MEMORY(*prefixes);
429
430         /* Add the new prefix entry*/
431         (*prefixes)[index_new_prefix].id = new_entry_id;
432         (*prefixes)[index_new_prefix].oid = talloc_strndup(mem_ctx, oid, size);
433         (*prefixes)[index_new_prefix].oid_len = strlen((*prefixes)[index_new_prefix].oid);
434
435         /* Increase num_prefixes because new prefix has been added */
436         ++(*num_prefixes);
437
438         return WERR_OK;
439 }
440
441 WERROR dsdb_find_prefix_for_oid(uint32_t num_prefixes, const struct dsdb_schema_oid_prefix *prefixes, const char *in, uint32_t *out)
442 {
443         uint32_t i;
444         char *oid_prefix;
445         char *pstr;
446         char *end_str;
447         unsigned val;
448
449         /* make oid prefix, i.e. oid w/o last subidentifier */
450         pstr = strrchr(in, '.');
451         if (!pstr)      return WERR_INVALID_PARAM;
452         if (pstr < in)  return WERR_INVALID_PARAM;
453         if ((pstr - in) < 4) return WERR_INVALID_PARAM;
454
455         oid_prefix = talloc_strndup(0, in, pstr - in);
456
457         for (i=0; i < num_prefixes; i++) {
458                 if (strcmp(prefixes[i].oid, oid_prefix) == 0) {
459                         break;
460                 }
461         }
462
463         talloc_free(oid_prefix);
464
465         if (i < num_prefixes) {
466                 /* move next to '.' char */
467                 pstr++;
468
469                 val = strtoul(pstr, &end_str, 10);
470                 if (end_str[0] != '\0') {
471                         return WERR_INVALID_PARAM;
472                 } else if (val > 0xFFFF) {
473                         return WERR_INVALID_PARAM;
474                 }
475
476                 *out = prefixes[i].id | val;
477                 return WERR_OK;
478         }
479
480         DEBUG(5,(__location__ " Failed to find oid %s - have %u prefixes\n", in, num_prefixes));
481
482         return WERR_DS_NO_MSDS_INTID;
483 }
484
485 WERROR dsdb_write_prefixes_from_schema_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
486                                                      const struct dsdb_schema *schema)
487 {
488         struct ldb_message *msg = ldb_msg_new(mem_ctx);
489         struct ldb_dn *schema_dn;
490         struct prefixMapBlob pm;
491         struct ldb_val ndr_blob;
492         enum ndr_err_code ndr_err;
493         uint32_t i;
494         int ret;
495
496         if (!msg) {
497                 return WERR_NOMEM;
498         }
499         
500         schema_dn = samdb_schema_dn(ldb);
501         if (!schema_dn) {
502                 DEBUG(0,("dsdb_write_prefixes_from_schema_to_ldb: no schema dn present\n"));    
503                 return WERR_FOOBAR;
504         }
505
506         pm.version                      = PREFIX_MAP_VERSION_DSDB;
507         pm.ctr.dsdb.num_mappings        = schema->num_prefixes;
508         pm.ctr.dsdb.mappings            = talloc_array(msg,
509                                                 struct drsuapi_DsReplicaOIDMapping,
510                                                 pm.ctr.dsdb.num_mappings);
511         if (!pm.ctr.dsdb.mappings) {
512                 talloc_free(msg);
513                 return WERR_NOMEM;
514         }
515
516         for (i=0; i < schema->num_prefixes; i++) {
517                 DATA_BLOB oid_blob;
518
519                 if (!ber_write_partial_OID_String(pm.ctr.dsdb.mappings, &oid_blob, schema->prefixes[i].oid)) {
520                         DEBUG(0, ("write_partial_OID failed for %s", schema->prefixes[i].oid));
521                         return WERR_INTERNAL_ERROR;
522                 }
523
524                 pm.ctr.dsdb.mappings[i].id_prefix       = schema->prefixes[i].id>>16;
525                 pm.ctr.dsdb.mappings[i].oid.length      = oid_blob.length;
526                 pm.ctr.dsdb.mappings[i].oid.binary_oid  = oid_blob.data;
527         }
528
529         ndr_err = ndr_push_struct_blob(&ndr_blob, msg,
530                                        lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
531                                        &pm,
532                                        (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
533         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
534                 talloc_free(msg);
535                 return WERR_FOOBAR;
536         }
537  
538         msg->dn = schema_dn;
539         ret = ldb_msg_add_value(msg, "prefixMap", &ndr_blob, NULL);
540         if (ret != 0) {
541                 talloc_free(msg);
542                 DEBUG(0,("dsdb_write_prefixes_from_schema_to_ldb: ldb_msg_add_value failed\n"));        
543                 return WERR_NOMEM;
544         }
545  
546         ret = samdb_replace( ldb, msg, msg );
547         talloc_free(msg);
548
549         if (ret != 0) {
550                 DEBUG(0,("dsdb_write_prefixes_from_schema_to_ldb: samdb_replace failed\n"));    
551                 return WERR_FOOBAR;
552         }
553  
554         return WERR_OK;
555 }
556
557 static WERROR dsdb_read_prefixes_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, uint32_t* num_prefixes, struct dsdb_schema_oid_prefix **prefixes)
558 {
559         struct prefixMapBlob *blob;
560         enum ndr_err_code ndr_err;
561         uint32_t i;
562         const struct ldb_val *prefix_val;
563         struct ldb_dn *schema_dn;
564         struct ldb_result *schema_res = NULL;
565         int ret;    
566         static const char *schema_attrs[] = {
567                 "prefixMap",
568                 NULL
569         };
570
571         schema_dn = samdb_schema_dn(ldb);
572         if (!schema_dn) {
573                 DEBUG(0,("dsdb_read_prefixes_from_ldb: no schema dn present\n"));
574                 return WERR_FOOBAR;
575         }
576
577         ret = ldb_search(ldb, mem_ctx, &schema_res, schema_dn, LDB_SCOPE_BASE, schema_attrs, NULL);
578         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
579                 DEBUG(0,("dsdb_read_prefixes_from_ldb: no prefix map present\n"));
580                 talloc_free(schema_res);
581                 return WERR_FOOBAR;
582         } else if (ret != LDB_SUCCESS) {
583                 DEBUG(0,("dsdb_read_prefixes_from_ldb: failed to search the schema head\n"));
584                 talloc_free(schema_res);
585                 return WERR_FOOBAR;
586         }
587
588         prefix_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "prefixMap");
589         if (!prefix_val) {
590                 DEBUG(0,("dsdb_read_prefixes_from_ldb: no prefixMap attribute found\n"));
591                 talloc_free(schema_res);
592                 return WERR_FOOBAR;
593         }
594
595         blob = talloc(mem_ctx, struct prefixMapBlob);
596         W_ERROR_HAVE_NO_MEMORY(blob);
597
598         ndr_err = ndr_pull_struct_blob(prefix_val, blob, 
599                                            lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
600                                            blob,
601                                            (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
602         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
603                 DEBUG(0,("dsdb_read_prefixes_from_ldb: ndr_pull_struct_blob failed\n"));
604                 talloc_free(blob);
605                 talloc_free(schema_res);
606                 return WERR_FOOBAR;
607         }
608
609         talloc_free(schema_res);
610
611         if (blob->version != PREFIX_MAP_VERSION_DSDB) {
612                 DEBUG(0,("dsdb_read_prefixes_from_ldb: blob->version incorect\n"));
613                 talloc_free(blob);
614                 return WERR_FOOBAR;
615         }
616         
617         *num_prefixes = blob->ctr.dsdb.num_mappings;
618         *prefixes = talloc_array(mem_ctx, struct dsdb_schema_oid_prefix, *num_prefixes);
619         if(!(*prefixes)) {
620                 talloc_free(blob);
621                 return WERR_NOMEM;
622         }
623         for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
624                 DATA_BLOB oid_blob;
625                 const char *partial_oid;
626
627                 oid_blob = data_blob_const(blob->ctr.dsdb.mappings[i].oid.binary_oid,
628                                            blob->ctr.dsdb.mappings[i].oid.length);
629
630                 if (!ber_read_partial_OID_String(mem_ctx, oid_blob, &partial_oid)) {
631                         DEBUG(0, ("ber_read_partial_OID failed on prefixMap item with id: 0x%X",
632                                         blob->ctr.dsdb.mappings[i].id_prefix));
633                         talloc_free(blob);
634                         return WERR_INVALID_PARAM;
635                 }
636
637                 (*prefixes)[i].id = blob->ctr.dsdb.mappings[i].id_prefix<<16;
638                 (*prefixes)[i].oid = partial_oid;
639                 (*prefixes)[i].oid_len = strlen((*prefixes)[i].oid);
640         }
641
642         talloc_free(blob);
643         return WERR_OK;
644 }
645
646 /*
647   this will be replaced with something that looks at the right part of
648   the schema once we know where unique indexing information is hidden
649  */
650 static bool dsdb_schema_unique_attribute(const char *attr)
651 {
652         const char *attrs[] = { "objectGUID", "objectSID" , NULL };
653         int i;
654         for (i=0;attrs[i];i++) {
655                 if (strcasecmp(attr, attrs[i]) == 0) {
656                         return true;
657                 }
658         }
659         return false;
660 }
661
662
663 /*
664   setup the ldb_schema_attribute field for a dsdb_attribute
665  */
666 static int dsdb_schema_setup_ldb_schema_attribute(struct ldb_context *ldb, 
667                                                   struct dsdb_attribute *attr)
668 {
669         const char *syntax = attr->syntax->ldb_syntax;
670         const struct ldb_schema_syntax *s;
671         struct ldb_schema_attribute *a;
672
673         if (!syntax) {
674                 syntax = attr->syntax->ldap_oid;
675         }
676
677         s = ldb_samba_syntax_by_lDAPDisplayName(ldb, attr->lDAPDisplayName);
678         if (s == NULL) {
679                 s = ldb_samba_syntax_by_name(ldb, syntax);
680         }
681         if (s == NULL) {
682                 s = ldb_standard_syntax_by_name(ldb, syntax);
683         }
684
685         if (s == NULL) {
686                 return LDB_ERR_OPERATIONS_ERROR;                
687         }
688
689         attr->ldb_schema_attribute = a = talloc(attr, struct ldb_schema_attribute);
690         if (attr->ldb_schema_attribute == NULL) {
691                 ldb_oom(ldb);
692                 return LDB_ERR_OPERATIONS_ERROR;
693         }
694
695         a->name = attr->lDAPDisplayName;
696         a->flags = 0;
697         a->syntax = s;
698
699         if (dsdb_schema_unique_attribute(a->name)) {
700                 a->flags |= LDB_ATTR_FLAG_UNIQUE_INDEX;
701         }
702         if (attr->isSingleValued) {
703                 a->flags |= LDB_ATTR_FLAG_SINGLE_VALUE;
704         }
705         
706         
707         return LDB_SUCCESS;
708 }
709
710
711 #define GET_STRING_LDB(msg, attr, mem_ctx, p, elem, strict) do { \
712         const struct ldb_val *get_string_val = ldb_msg_find_ldb_val(msg, attr); \
713         if (get_string_val == NULL) { \
714                 if (strict) {                                     \
715                         d_printf("%s: %s == NULL\n", __location__, attr); \
716                         return WERR_INVALID_PARAM;                      \
717                 } else {                                                \
718                         (p)->elem = NULL;                               \
719                 }                                                       \
720         } else {                                                        \
721                 (p)->elem = talloc_strndup(mem_ctx,                     \
722                                            (const char *)get_string_val->data, \
723                                            get_string_val->length); \
724                 if (!(p)->elem) {                                       \
725                         d_printf("%s: talloc_strndup failed for %s\n", __location__, attr); \
726                         return WERR_NOMEM;                              \
727                 }                                                       \
728         }                                                               \
729 } while (0)
730
731 #define GET_STRING_LIST_LDB(msg, attr, mem_ctx, p, elem, strict) do {   \
732         int get_string_list_counter;                                    \
733         struct ldb_message_element *get_string_list_el = ldb_msg_find_element(msg, attr); \
734         if (get_string_list_el == NULL) {                               \
735                 if (strict) {                                           \
736                         d_printf("%s: %s == NULL\n", __location__, attr); \
737                         return WERR_INVALID_PARAM;                      \
738                 } else {                                                \
739                         (p)->elem = NULL;                               \
740                         break;                                          \
741                 }                                                       \
742         }                                                               \
743         (p)->elem = talloc_array(mem_ctx, const char *, get_string_list_el->num_values + 1); \
744         for (get_string_list_counter=0;                                 \
745              get_string_list_counter < get_string_list_el->num_values;  \
746              get_string_list_counter++) {                               \
747                 (p)->elem[get_string_list_counter] = talloc_strndup((p)->elem, \
748                                                                     (const char *)get_string_list_el->values[get_string_list_counter].data, \
749                                                                     get_string_list_el->values[get_string_list_counter].length); \
750                 if (!(p)->elem[get_string_list_counter]) {              \
751                         d_printf("%s: talloc_strndup failed for %s\n", __location__, attr); \
752                         return WERR_NOMEM;                              \
753                 }                                                       \
754                 (p)->elem[get_string_list_counter+1] = NULL;            \
755         }                                                               \
756         talloc_steal(mem_ctx, (p)->elem);                               \
757 } while (0)
758
759 #define GET_BOOL_LDB(msg, attr, p, elem, strict) do { \
760         const char *str; \
761         str = samdb_result_string(msg, attr, NULL);\
762         if (str == NULL) { \
763                 if (strict) { \
764                         d_printf("%s: %s == NULL\n", __location__, attr); \
765                         return WERR_INVALID_PARAM; \
766                 } else { \
767                         (p)->elem = false; \
768                 } \
769         } else if (strcasecmp("TRUE", str) == 0) { \
770                 (p)->elem = true; \
771         } else if (strcasecmp("FALSE", str) == 0) { \
772                 (p)->elem = false; \
773         } else { \
774                 d_printf("%s: %s == %s\n", __location__, attr, str); \
775                 return WERR_INVALID_PARAM; \
776         } \
777 } while (0)
778
779 #define GET_UINT32_LDB(msg, attr, p, elem) do { \
780         (p)->elem = samdb_result_uint(msg, attr, 0);\
781 } while (0)
782
783 #define GET_UINT32_PTR_LDB(msg, attr, p, elem) do { \
784         uint64_t _v = samdb_result_uint64(msg, attr, UINT64_MAX);\
785         if (_v == UINT64_MAX) { \
786                 (p)->elem = NULL; \
787         } else if (_v > UINT32_MAX) { \
788                 d_printf("%s: %s == 0x%llX\n", __location__, \
789                          attr, (unsigned long long)_v); \
790                 return WERR_INVALID_PARAM; \
791         } else { \
792                 (p)->elem = talloc(mem_ctx, uint32_t); \
793                 if (!(p)->elem) { \
794                         d_printf("%s: talloc failed for %s\n", __location__, attr); \
795                         return WERR_NOMEM; \
796                 } \
797                 *(p)->elem = (uint32_t)_v; \
798         } \
799 } while (0)
800
801 #define GET_GUID_LDB(msg, attr, p, elem) do { \
802         (p)->elem = samdb_result_guid(msg, attr);\
803 } while (0)
804
805 #define GET_BLOB_LDB(msg, attr, mem_ctx, p, elem) do { \
806         const struct ldb_val *_val;\
807         _val = ldb_msg_find_ldb_val(msg, attr);\
808         if (_val) {\
809                 (p)->elem = *_val;\
810                 talloc_steal(mem_ctx, (p)->elem.data);\
811         } else {\
812                 ZERO_STRUCT((p)->elem);\
813         }\
814 } while (0)
815
816 WERROR dsdb_attribute_from_ldb(struct ldb_context *ldb,
817                                const struct dsdb_schema *schema,
818                                struct ldb_message *msg,
819                                TALLOC_CTX *mem_ctx,
820                                struct dsdb_attribute *attr)
821 {
822         WERROR status;
823
824         GET_STRING_LDB(msg, "cn", mem_ctx, attr, cn, false);
825         GET_STRING_LDB(msg, "lDAPDisplayName", mem_ctx, attr, lDAPDisplayName, true);
826         GET_STRING_LDB(msg, "attributeID", mem_ctx, attr, attributeID_oid, true);
827         if (schema->num_prefixes == 0) {
828                 /* set an invalid value */
829                 attr->attributeID_id = 0xFFFFFFFF;
830         } else {
831                 status = dsdb_map_oid2int(schema, attr->attributeID_oid, &attr->attributeID_id);
832                 if (!W_ERROR_IS_OK(status)) {
833                         DEBUG(0,("%s: '%s': unable to map attributeID %s: %s\n",
834                                 __location__, attr->lDAPDisplayName, attr->attributeID_oid,
835                                 win_errstr(status)));
836                         return status;
837                 }
838         }
839         GET_GUID_LDB(msg, "schemaIDGUID", attr, schemaIDGUID);
840         GET_UINT32_LDB(msg, "mAPIID", attr, mAPIID);
841
842         GET_GUID_LDB(msg, "attributeSecurityGUID", attr, attributeSecurityGUID);
843
844         GET_UINT32_LDB(msg, "searchFlags", attr, searchFlags);
845         GET_UINT32_LDB(msg, "systemFlags", attr, systemFlags);
846         GET_BOOL_LDB(msg, "isMemberOfPartialAttributeSet", attr, isMemberOfPartialAttributeSet, false);
847         GET_UINT32_LDB(msg, "linkID", attr, linkID);
848
849         GET_STRING_LDB(msg, "attributeSyntax", mem_ctx, attr, attributeSyntax_oid, true);
850         if (schema->num_prefixes == 0) {
851                 /* set an invalid value */
852                 attr->attributeSyntax_id = 0xFFFFFFFF;
853         } else {
854                 status = dsdb_map_oid2int(schema, attr->attributeSyntax_oid, &attr->attributeSyntax_id);
855                 if (!W_ERROR_IS_OK(status)) {
856                         DEBUG(0,("%s: '%s': unable to map attributeSyntax_ %s: %s\n",
857                                 __location__, attr->lDAPDisplayName, attr->attributeSyntax_oid,
858                                 win_errstr(status)));
859                         return status;
860                 }
861         }
862         GET_UINT32_LDB(msg, "oMSyntax", attr, oMSyntax);
863         GET_BLOB_LDB(msg, "oMObjectClass", mem_ctx, attr, oMObjectClass);
864
865         GET_BOOL_LDB(msg, "isSingleValued", attr, isSingleValued, true);
866         GET_UINT32_PTR_LDB(msg, "rangeLower", attr, rangeLower);
867         GET_UINT32_PTR_LDB(msg, "rangeUpper", attr, rangeUpper);
868         GET_BOOL_LDB(msg, "extendedCharsAllowed", attr, extendedCharsAllowed, false);
869
870         GET_UINT32_LDB(msg, "schemaFlagsEx", attr, schemaFlagsEx);
871         GET_BLOB_LDB(msg, "msDs-Schema-Extensions", mem_ctx, attr, msDs_Schema_Extensions);
872
873         GET_BOOL_LDB(msg, "showInAdvancedViewOnly", attr, showInAdvancedViewOnly, false);
874         GET_STRING_LDB(msg, "adminDisplayName", mem_ctx, attr, adminDisplayName, false);
875         GET_STRING_LDB(msg, "adminDescription", mem_ctx, attr, adminDescription, false);
876         GET_STRING_LDB(msg, "classDisplayName", mem_ctx, attr, classDisplayName, false);
877         GET_BOOL_LDB(msg, "isEphemeral", attr, isEphemeral, false);
878         GET_BOOL_LDB(msg, "isDefunct", attr, isDefunct, false);
879         GET_BOOL_LDB(msg, "systemOnly", attr, systemOnly, false);
880
881         attr->syntax = dsdb_syntax_for_attribute(attr);
882         if (!attr->syntax) {
883                 return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
884         }
885
886         if (dsdb_schema_setup_ldb_schema_attribute(ldb, attr) != LDB_SUCCESS) {
887                 return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
888         }
889
890         return WERR_OK;
891 }
892
893 WERROR dsdb_class_from_ldb(const struct dsdb_schema *schema,
894                            struct ldb_message *msg,
895                            TALLOC_CTX *mem_ctx,
896                            struct dsdb_class *obj)
897 {
898         WERROR status;
899
900         GET_STRING_LDB(msg, "cn", mem_ctx, obj, cn, false);
901         GET_STRING_LDB(msg, "lDAPDisplayName", mem_ctx, obj, lDAPDisplayName, true);
902         GET_STRING_LDB(msg, "governsID", mem_ctx, obj, governsID_oid, true);
903         if (schema->num_prefixes == 0) {
904                 /* set an invalid value */
905                 obj->governsID_id = 0xFFFFFFFF;
906         } else {
907                 status = dsdb_map_oid2int(schema, obj->governsID_oid, &obj->governsID_id);
908                 if (!W_ERROR_IS_OK(status)) {
909                         DEBUG(0,("%s: '%s': unable to map governsID %s: %s\n",
910                                 __location__, obj->lDAPDisplayName, obj->governsID_oid,
911                                 win_errstr(status)));
912                         return status;
913                 }
914         }
915         GET_GUID_LDB(msg, "schemaIDGUID", obj, schemaIDGUID);
916
917         GET_UINT32_LDB(msg, "objectClassCategory", obj, objectClassCategory);
918         GET_STRING_LDB(msg, "rDNAttID", mem_ctx, obj, rDNAttID, false);
919         GET_STRING_LDB(msg, "defaultObjectCategory", mem_ctx, obj, defaultObjectCategory, true);
920  
921         GET_STRING_LDB(msg, "subClassOf", mem_ctx, obj, subClassOf, true);
922
923         GET_STRING_LIST_LDB(msg, "systemAuxiliaryClass", mem_ctx, obj, systemAuxiliaryClass, false);
924         GET_STRING_LIST_LDB(msg, "auxiliaryClass", mem_ctx, obj, auxiliaryClass, false);
925
926         GET_STRING_LIST_LDB(msg, "systemMustContain", mem_ctx, obj, systemMustContain, false);
927         GET_STRING_LIST_LDB(msg, "systemMayContain", mem_ctx, obj, systemMayContain, false);
928         GET_STRING_LIST_LDB(msg, "mustContain", mem_ctx, obj, mustContain, false);
929         GET_STRING_LIST_LDB(msg, "mayContain", mem_ctx, obj, mayContain, false);
930
931         GET_STRING_LIST_LDB(msg, "systemPossSuperiors", mem_ctx, obj, systemPossSuperiors, false);
932         GET_STRING_LIST_LDB(msg, "possSuperiors", mem_ctx, obj, possSuperiors, false);
933
934         GET_STRING_LDB(msg, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, false);
935
936         GET_UINT32_LDB(msg, "schemaFlagsEx", obj, schemaFlagsEx);
937         GET_BLOB_LDB(msg, "msDs-Schema-Extensions", mem_ctx, obj, msDs_Schema_Extensions);
938
939         GET_BOOL_LDB(msg, "showInAdvancedViewOnly", obj, showInAdvancedViewOnly, false);
940         GET_STRING_LDB(msg, "adminDisplayName", mem_ctx, obj, adminDisplayName, false);
941         GET_STRING_LDB(msg, "adminDescription", mem_ctx, obj, adminDescription, false);
942         GET_STRING_LDB(msg, "classDisplayName", mem_ctx, obj, classDisplayName, false);
943         GET_BOOL_LDB(msg, "defaultHidingValue", obj, defaultHidingValue, false);
944         GET_BOOL_LDB(msg, "isDefunct", obj, isDefunct, false);
945         GET_BOOL_LDB(msg, "systemOnly", obj, systemOnly, false);
946
947         return WERR_OK;
948 }
949
950 #define dsdb_oom(error_string, mem_ctx) *error_string = talloc_asprintf(mem_ctx, "dsdb out of memory at %s:%d\n", __FILE__, __LINE__)
951
952 /* 
953  Create a DSDB schema from the ldb results provided.  This is called
954  directly when the schema is provisioned from an on-disk LDIF file, or
955  from dsdb_schema_from_schema_dn in schema_fsmo
956 */
957
958 int dsdb_schema_from_ldb_results(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
959                                  struct smb_iconv_convenience *iconv_convenience, 
960                                  struct ldb_result *schema_res,
961                                  struct ldb_result *attrs_res, struct ldb_result *objectclass_res, 
962                                  struct dsdb_schema **schema_out,
963                                  char **error_string)
964 {
965         WERROR status;
966         uint32_t i;
967         const struct ldb_val *prefix_val;
968         const struct ldb_val *info_val;
969         struct ldb_val info_val_default;
970         struct dsdb_schema *schema;
971
972         schema = dsdb_new_schema(mem_ctx, iconv_convenience);
973         if (!schema) {
974                 dsdb_oom(error_string, mem_ctx);
975                 return LDB_ERR_OPERATIONS_ERROR;
976         }
977
978         prefix_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "prefixMap");
979         if (!prefix_val) {
980                 *error_string = talloc_asprintf(mem_ctx, 
981                                                 "schema_fsmo_init: no prefixMap attribute found");
982                 DEBUG(0,(__location__ ": %s\n", *error_string));
983                 return LDB_ERR_CONSTRAINT_VIOLATION;
984         }
985         info_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo");
986         if (!info_val) {
987                 info_val_default = strhex_to_data_blob(mem_ctx, "FF0000000000000000000000000000000000000000");
988                 if (!info_val_default.data) {
989                         dsdb_oom(error_string, mem_ctx);
990                         return LDB_ERR_OPERATIONS_ERROR;
991                 }
992                 info_val = &info_val_default;
993         }
994
995         status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val);
996         if (!W_ERROR_IS_OK(status)) {
997                 *error_string = talloc_asprintf(mem_ctx, 
998                               "schema_fsmo_init: failed to load oid mappings: %s",
999                               win_errstr(status));
1000                 DEBUG(0,(__location__ ": %s\n", *error_string));
1001                 return LDB_ERR_CONSTRAINT_VIOLATION;
1002         }
1003
1004         for (i=0; i < attrs_res->count; i++) {
1005                 struct dsdb_attribute *sa;
1006
1007                 sa = talloc_zero(schema, struct dsdb_attribute);
1008                 if (!sa) {
1009                         dsdb_oom(error_string, mem_ctx);
1010                         return LDB_ERR_OPERATIONS_ERROR;
1011                 }
1012
1013                 status = dsdb_attribute_from_ldb(ldb, schema, attrs_res->msgs[i], sa, sa);
1014                 if (!W_ERROR_IS_OK(status)) {
1015                         *error_string = talloc_asprintf(mem_ctx, 
1016                                       "schema_fsmo_init: failed to load attribute definition: %s:%s",
1017                                       ldb_dn_get_linearized(attrs_res->msgs[i]->dn),
1018                                       win_errstr(status));
1019                         DEBUG(0,(__location__ ": %s\n", *error_string));
1020                         return LDB_ERR_CONSTRAINT_VIOLATION;
1021                 }
1022
1023                 DLIST_ADD(schema->attributes, sa);
1024         }
1025
1026         for (i=0; i < objectclass_res->count; i++) {
1027                 struct dsdb_class *sc;
1028
1029                 sc = talloc_zero(schema, struct dsdb_class);
1030                 if (!sc) {
1031                         dsdb_oom(error_string, mem_ctx);
1032                         return LDB_ERR_OPERATIONS_ERROR;
1033                 }
1034
1035                 status = dsdb_class_from_ldb(schema, objectclass_res->msgs[i], sc, sc);
1036                 if (!W_ERROR_IS_OK(status)) {
1037                         *error_string = talloc_asprintf(mem_ctx, 
1038                                       "schema_fsmo_init: failed to load class definition: %s:%s",
1039                                       ldb_dn_get_linearized(objectclass_res->msgs[i]->dn),
1040                                       win_errstr(status));
1041                         DEBUG(0,(__location__ ": %s\n", *error_string));
1042                         return LDB_ERR_CONSTRAINT_VIOLATION;
1043                 }
1044
1045                 DLIST_ADD(schema->classes, sc);
1046         }
1047
1048         schema->fsmo.master_dn = ldb_msg_find_attr_as_dn(ldb, schema, schema_res->msgs[0], "fSMORoleOwner");
1049         if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), schema->fsmo.master_dn) == 0) {
1050                 schema->fsmo.we_are_master = true;
1051         } else {
1052                 schema->fsmo.we_are_master = false;
1053         }
1054
1055         DEBUG(5, ("schema_fsmo_init: we are master: %s\n",
1056                   (schema->fsmo.we_are_master?"yes":"no")));
1057
1058         *schema_out = schema;
1059         return LDB_SUCCESS;
1060 }
1061
1062
1063 static const struct {
1064         const char *name;
1065         const char *oid;
1066 } name_mappings[] = {
1067         { "cn",                                 "2.5.4.3" },
1068         { "name",                               "1.2.840.113556.1.4.1" },
1069         { "lDAPDisplayName",                    "1.2.840.113556.1.2.460" },
1070         { "attributeID",                        "1.2.840.113556.1.2.30" },
1071         { "schemaIDGUID",                       "1.2.840.113556.1.4.148" },
1072         { "mAPIID",                             "1.2.840.113556.1.2.49" },
1073         { "attributeSecurityGUID",              "1.2.840.113556.1.4.149" },
1074         { "searchFlags",                        "1.2.840.113556.1.2.334" },
1075         { "systemFlags",                        "1.2.840.113556.1.4.375" },
1076         { "isMemberOfPartialAttributeSet",      "1.2.840.113556.1.4.639" },
1077         { "linkID",                             "1.2.840.113556.1.2.50" },
1078         { "attributeSyntax",                    "1.2.840.113556.1.2.32" },
1079         { "oMSyntax",                           "1.2.840.113556.1.2.231" },
1080         { "oMObjectClass",                      "1.2.840.113556.1.2.218" },
1081         { "isSingleValued",                     "1.2.840.113556.1.2.33" },
1082         { "rangeLower",                         "1.2.840.113556.1.2.34" },
1083         { "rangeUpper",                         "1.2.840.113556.1.2.35" },
1084         { "extendedCharsAllowed",               "1.2.840.113556.1.2.380" },
1085         { "schemaFlagsEx",                      "1.2.840.113556.1.4.120" },
1086         { "msDs-Schema-Extensions",             "1.2.840.113556.1.4.1440" },
1087         { "showInAdvancedViewOnly",             "1.2.840.113556.1.2.169" },
1088         { "adminDisplayName",                   "1.2.840.113556.1.2.194" },
1089         { "adminDescription",                   "1.2.840.113556.1.2.226" },
1090         { "classDisplayName",                   "1.2.840.113556.1.4.610" },
1091         { "isEphemeral",                        "1.2.840.113556.1.4.1212" },
1092         { "isDefunct",                          "1.2.840.113556.1.4.661" },
1093         { "systemOnly",                         "1.2.840.113556.1.4.170" },
1094         { "governsID",                          "1.2.840.113556.1.2.22" },
1095         { "objectClassCategory",                "1.2.840.113556.1.2.370" },
1096         { "rDNAttID",                           "1.2.840.113556.1.2.26" },
1097         { "defaultObjectCategory",              "1.2.840.113556.1.4.783" },
1098         { "subClassOf",                         "1.2.840.113556.1.2.21" },
1099         { "systemAuxiliaryClass",               "1.2.840.113556.1.4.198" },
1100         { "systemPossSuperiors",                "1.2.840.113556.1.4.195" },
1101         { "systemMustContain",                  "1.2.840.113556.1.4.197" },
1102         { "systemMayContain",                   "1.2.840.113556.1.4.196" },
1103         { "auxiliaryClass",                     "1.2.840.113556.1.2.351" },
1104         { "possSuperiors",                      "1.2.840.113556.1.2.8" },
1105         { "mustContain",                        "1.2.840.113556.1.2.24" },
1106         { "mayContain",                         "1.2.840.113556.1.2.25" },
1107         { "defaultSecurityDescriptor",          "1.2.840.113556.1.4.224" },
1108         { "defaultHidingValue",                 "1.2.840.113556.1.4.518" },
1109 };
1110
1111 static struct drsuapi_DsReplicaAttribute *dsdb_find_object_attr_name(struct dsdb_schema *schema,
1112                                                                      struct drsuapi_DsReplicaObject *obj,
1113                                                                      const char *name,
1114                                                                      uint32_t *idx)
1115 {
1116         WERROR status;
1117         uint32_t i, id;
1118         const char *oid = NULL;
1119
1120         for(i=0; i < ARRAY_SIZE(name_mappings); i++) {
1121                 if (strcmp(name_mappings[i].name, name) != 0) continue;
1122
1123                 oid = name_mappings[i].oid;
1124                 break;
1125         }
1126
1127         if (!oid) {
1128                 return NULL;
1129         }
1130
1131         status = dsdb_map_oid2int(schema, oid, &id);
1132         if (!W_ERROR_IS_OK(status)) {
1133                 return NULL;
1134         }
1135
1136         for (i=0; i < obj->attribute_ctr.num_attributes; i++) {
1137                 if (obj->attribute_ctr.attributes[i].attid != id) continue;
1138
1139                 if (idx) *idx = i;
1140                 return &obj->attribute_ctr.attributes[i];
1141         }
1142
1143         return NULL;
1144 }
1145
1146 #define GET_STRING_DS(s, r, attr, mem_ctx, p, elem, strict) do { \
1147         struct drsuapi_DsReplicaAttribute *_a; \
1148         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
1149         if (strict && !_a) { \
1150                 d_printf("%s: %s == NULL\n", __location__, attr); \
1151                 return WERR_INVALID_PARAM; \
1152         } \
1153         if (strict && _a->value_ctr.num_values != 1) { \
1154                 d_printf("%s: %s num_values == %u\n", __location__, attr, \
1155                         _a->value_ctr.num_values); \
1156                 return WERR_INVALID_PARAM; \
1157         } \
1158         if (_a && _a->value_ctr.num_values >= 1) { \
1159                 size_t _ret; \
1160                 if (!convert_string_talloc_convenience(mem_ctx, s->iconv_convenience, CH_UTF16, CH_UNIX, \
1161                                              _a->value_ctr.values[0].blob->data, \
1162                                              _a->value_ctr.values[0].blob->length, \
1163                                              (void **)discard_const(&(p)->elem), &_ret, false)) { \
1164                         DEBUG(0,("%s: invalid data!\n", attr)); \
1165                         dump_data(0, \
1166                                      _a->value_ctr.values[0].blob->data, \
1167                                      _a->value_ctr.values[0].blob->length); \
1168                         return WERR_FOOBAR; \
1169                 } \
1170         } else { \
1171                 (p)->elem = NULL; \
1172         } \
1173 } while (0)
1174
1175 #define GET_UINT32_LIST_DS(s, r, attr, mem_ctx, p, elem) do { \
1176         int list_counter;                                       \
1177         struct drsuapi_DsReplicaAttribute *_a; \
1178         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
1179         (p)->elem = _a ? talloc_array(mem_ctx, uint32_t, _a->value_ctr.num_values + 1) : NULL; \
1180         for (list_counter=0;                                    \
1181              _a && list_counter < _a->value_ctr.num_values;     \
1182              list_counter++) {                          \
1183                 if (_a->value_ctr.values[list_counter].blob->length != 4) { \
1184                         return WERR_INVALID_PARAM;                      \
1185                 }                                                       \
1186                 (p)->elem[list_counter] = IVAL(_a->value_ctr.values[list_counter].blob->data, 0); \
1187         }                                                               \
1188         if (_a) (p)->elem[list_counter] = 0;                            \
1189 } while (0)
1190
1191 #define GET_DN_DS(s, r, attr, mem_ctx, p, elem, strict) do { \
1192         struct drsuapi_DsReplicaAttribute *_a; \
1193         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
1194         if (strict && !_a) { \
1195                 d_printf("%s: %s == NULL\n", __location__, attr); \
1196                 return WERR_INVALID_PARAM; \
1197         } \
1198         if (strict && _a->value_ctr.num_values != 1) { \
1199                 d_printf("%s: %s num_values == %u\n", __location__, attr, \
1200                         _a->value_ctr.num_values); \
1201                 return WERR_INVALID_PARAM; \
1202         } \
1203         if (strict && !_a->value_ctr.values[0].blob) { \
1204                 d_printf("%s: %s data == NULL\n", __location__, attr); \
1205                 return WERR_INVALID_PARAM; \
1206         } \
1207         if (_a && _a->value_ctr.num_values >= 1 \
1208             && _a->value_ctr.values[0].blob) { \
1209                 struct drsuapi_DsReplicaObjectIdentifier3 _id3; \
1210                 enum ndr_err_code _ndr_err; \
1211                 _ndr_err = ndr_pull_struct_blob_all(_a->value_ctr.values[0].blob, \
1212                                                       mem_ctx, s->iconv_convenience, &_id3,\
1213                                                       (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);\
1214                 if (!NDR_ERR_CODE_IS_SUCCESS(_ndr_err)) { \
1215                         NTSTATUS _nt_status = ndr_map_error2ntstatus(_ndr_err); \
1216                         return ntstatus_to_werror(_nt_status); \
1217                 } \
1218                 (p)->elem = _id3.dn; \
1219         } else { \
1220                 (p)->elem = NULL; \
1221         } \
1222 } while (0)
1223
1224 #define GET_BOOL_DS(s, r, attr, p, elem, strict) do { \
1225         struct drsuapi_DsReplicaAttribute *_a; \
1226         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
1227         if (strict && !_a) { \
1228                 d_printf("%s: %s == NULL\n", __location__, attr); \
1229                 return WERR_INVALID_PARAM; \
1230         } \
1231         if (strict && _a->value_ctr.num_values != 1) { \
1232                 d_printf("%s: %s num_values == %u\n", __location__, attr, \
1233                          (unsigned int)_a->value_ctr.num_values);       \
1234                 return WERR_INVALID_PARAM; \
1235         } \
1236         if (strict && !_a->value_ctr.values[0].blob) { \
1237                 d_printf("%s: %s data == NULL\n", __location__, attr); \
1238                 return WERR_INVALID_PARAM; \
1239         } \
1240         if (strict && _a->value_ctr.values[0].blob->length != 4) { \
1241                 d_printf("%s: %s length == %u\n", __location__, attr, \
1242                          (unsigned int)_a->value_ctr.values[0].blob->length); \
1243                 return WERR_INVALID_PARAM; \
1244         } \
1245         if (_a && _a->value_ctr.num_values >= 1 \
1246             && _a->value_ctr.values[0].blob \
1247             && _a->value_ctr.values[0].blob->length == 4) { \
1248                 (p)->elem = (IVAL(_a->value_ctr.values[0].blob->data,0)?true:false);\
1249         } else { \
1250                 (p)->elem = false; \
1251         } \
1252 } while (0)
1253
1254 #define GET_UINT32_DS(s, r, attr, p, elem) do { \
1255         struct drsuapi_DsReplicaAttribute *_a; \
1256         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
1257         if (_a && _a->value_ctr.num_values >= 1 \
1258             && _a->value_ctr.values[0].blob \
1259             && _a->value_ctr.values[0].blob->length == 4) { \
1260                 (p)->elem = IVAL(_a->value_ctr.values[0].blob->data,0);\
1261         } else { \
1262                 (p)->elem = 0; \
1263         } \
1264 } while (0)
1265
1266 #define GET_UINT32_PTR_DS(s, r, attr, p, elem) do { \
1267         struct drsuapi_DsReplicaAttribute *_a; \
1268         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
1269         if (_a && _a->value_ctr.num_values >= 1 \
1270             && _a->value_ctr.values[0].blob \
1271             && _a->value_ctr.values[0].blob->length == 4) { \
1272                 (p)->elem = talloc(mem_ctx, uint32_t); \
1273                 if (!(p)->elem) { \
1274                         d_printf("%s: talloc failed for %s\n", __location__, attr); \
1275                         return WERR_NOMEM; \
1276                 } \
1277                 *(p)->elem = IVAL(_a->value_ctr.values[0].blob->data,0);\
1278         } else { \
1279                 (p)->elem = NULL; \
1280         } \
1281 } while (0)
1282
1283 #define GET_GUID_DS(s, r, attr, mem_ctx, p, elem) do { \
1284         struct drsuapi_DsReplicaAttribute *_a; \
1285         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
1286         if (_a && _a->value_ctr.num_values >= 1 \
1287             && _a->value_ctr.values[0].blob \
1288             && _a->value_ctr.values[0].blob->length == 16) { \
1289                 enum ndr_err_code _ndr_err; \
1290                 _ndr_err = ndr_pull_struct_blob_all(_a->value_ctr.values[0].blob, \
1291                                                       mem_ctx, s->iconv_convenience, &(p)->elem, \
1292                                                       (ndr_pull_flags_fn_t)ndr_pull_GUID); \
1293                 if (!NDR_ERR_CODE_IS_SUCCESS(_ndr_err)) { \
1294                         NTSTATUS _nt_status = ndr_map_error2ntstatus(_ndr_err); \
1295                         return ntstatus_to_werror(_nt_status); \
1296                 } \
1297         } else { \
1298                 ZERO_STRUCT((p)->elem);\
1299         } \
1300 } while (0)
1301
1302 #define GET_BLOB_DS(s, r, attr, mem_ctx, p, elem) do { \
1303         struct drsuapi_DsReplicaAttribute *_a; \
1304         _a = dsdb_find_object_attr_name(s, r, attr, NULL); \
1305         if (_a && _a->value_ctr.num_values >= 1 \
1306             && _a->value_ctr.values[0].blob) { \
1307                 (p)->elem = *_a->value_ctr.values[0].blob;\
1308                 talloc_steal(mem_ctx, (p)->elem.data); \
1309         } else { \
1310                 ZERO_STRUCT((p)->elem);\
1311         }\
1312 } while (0)
1313
1314 WERROR dsdb_attribute_from_drsuapi(struct ldb_context *ldb,
1315                                    struct dsdb_schema *schema,
1316                                    struct drsuapi_DsReplicaObject *r,
1317                                    TALLOC_CTX *mem_ctx,
1318                                    struct dsdb_attribute *attr)
1319 {
1320         WERROR status;
1321
1322         GET_STRING_DS(schema, r, "name", mem_ctx, attr, cn, true);
1323         GET_STRING_DS(schema, r, "lDAPDisplayName", mem_ctx, attr, lDAPDisplayName, true);
1324         GET_UINT32_DS(schema, r, "attributeID", attr, attributeID_id);
1325         status = dsdb_map_int2oid(schema, attr->attributeID_id, mem_ctx, &attr->attributeID_oid);
1326         if (!W_ERROR_IS_OK(status)) {
1327                 DEBUG(0,("%s: '%s': unable to map attributeID 0x%08X: %s\n",
1328                         __location__, attr->lDAPDisplayName, attr->attributeID_id,
1329                         win_errstr(status)));
1330                 return status;
1331         }
1332         GET_GUID_DS(schema, r, "schemaIDGUID", mem_ctx, attr, schemaIDGUID);
1333         GET_UINT32_DS(schema, r, "mAPIID", attr, mAPIID);
1334
1335         GET_GUID_DS(schema, r, "attributeSecurityGUID", mem_ctx, attr, attributeSecurityGUID);
1336
1337         GET_UINT32_DS(schema, r, "searchFlags", attr, searchFlags);
1338         GET_UINT32_DS(schema, r, "systemFlags", attr, systemFlags);
1339         GET_BOOL_DS(schema, r, "isMemberOfPartialAttributeSet", attr, isMemberOfPartialAttributeSet, false);
1340         GET_UINT32_DS(schema, r, "linkID", attr, linkID);
1341
1342         GET_UINT32_DS(schema, r, "attributeSyntax", attr, attributeSyntax_id);
1343         status = dsdb_map_int2oid(schema, attr->attributeSyntax_id, mem_ctx, &attr->attributeSyntax_oid);
1344         if (!W_ERROR_IS_OK(status)) {
1345                 DEBUG(0,("%s: '%s': unable to map attributeSyntax 0x%08X: %s\n",
1346                         __location__, attr->lDAPDisplayName, attr->attributeSyntax_id,
1347                         win_errstr(status)));
1348                 return status;
1349         }
1350         GET_UINT32_DS(schema, r, "oMSyntax", attr, oMSyntax);
1351         GET_BLOB_DS(schema, r, "oMObjectClass", mem_ctx, attr, oMObjectClass);
1352
1353         GET_BOOL_DS(schema, r, "isSingleValued", attr, isSingleValued, true);
1354         GET_UINT32_PTR_DS(schema, r, "rangeLower", attr, rangeLower);
1355         GET_UINT32_PTR_DS(schema, r, "rangeUpper", attr, rangeUpper);
1356         GET_BOOL_DS(schema, r, "extendedCharsAllowed", attr, extendedCharsAllowed, false);
1357
1358         GET_UINT32_DS(schema, r, "schemaFlagsEx", attr, schemaFlagsEx);
1359         GET_BLOB_DS(schema, r, "msDs-Schema-Extensions", mem_ctx, attr, msDs_Schema_Extensions);
1360
1361         GET_BOOL_DS(schema, r, "showInAdvancedViewOnly", attr, showInAdvancedViewOnly, false);
1362         GET_STRING_DS(schema, r, "adminDisplayName", mem_ctx, attr, adminDisplayName, false);
1363         GET_STRING_DS(schema, r, "adminDescription", mem_ctx, attr, adminDescription, false);
1364         GET_STRING_DS(schema, r, "classDisplayName", mem_ctx, attr, classDisplayName, false);
1365         GET_BOOL_DS(schema, r, "isEphemeral", attr, isEphemeral, false);
1366         GET_BOOL_DS(schema, r, "isDefunct", attr, isDefunct, false);
1367         GET_BOOL_DS(schema, r, "systemOnly", attr, systemOnly, false);
1368
1369         attr->syntax = dsdb_syntax_for_attribute(attr);
1370         if (!attr->syntax) {
1371                 return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
1372         }
1373
1374         if (dsdb_schema_setup_ldb_schema_attribute(ldb, attr) != LDB_SUCCESS) {
1375                 return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
1376         }
1377
1378         return WERR_OK;
1379 }
1380
1381 WERROR dsdb_class_from_drsuapi(struct dsdb_schema *schema,
1382                                struct drsuapi_DsReplicaObject *r,
1383                                TALLOC_CTX *mem_ctx,
1384                                struct dsdb_class *obj)
1385 {
1386         WERROR status;
1387
1388         GET_STRING_DS(schema, r, "name", mem_ctx, obj, cn, true);
1389         GET_STRING_DS(schema, r, "lDAPDisplayName", mem_ctx, obj, lDAPDisplayName, true);
1390         GET_UINT32_DS(schema, r, "governsID", obj, governsID_id);
1391         status = dsdb_map_int2oid(schema, obj->governsID_id, mem_ctx, &obj->governsID_oid);
1392         if (!W_ERROR_IS_OK(status)) {
1393                 DEBUG(0,("%s: '%s': unable to map governsID 0x%08X: %s\n",
1394                         __location__, obj->lDAPDisplayName, obj->governsID_id,
1395                         win_errstr(status)));
1396                 return status;
1397         }
1398         GET_GUID_DS(schema, r, "schemaIDGUID", mem_ctx, obj, schemaIDGUID);
1399
1400         GET_UINT32_DS(schema, r, "objectClassCategory", obj, objectClassCategory);
1401         GET_STRING_DS(schema, r, "rDNAttID", mem_ctx, obj, rDNAttID, false);
1402         GET_DN_DS(schema, r, "defaultObjectCategory", mem_ctx, obj, defaultObjectCategory, true);
1403
1404         GET_UINT32_DS(schema, r, "subClassOf", obj, subClassOf_id);
1405
1406         GET_UINT32_LIST_DS(schema, r, "systemAuxiliaryClass", mem_ctx, obj, systemAuxiliaryClass_ids);
1407         GET_UINT32_LIST_DS(schema, r, "auxiliaryClass", mem_ctx, obj, auxiliaryClass_ids);
1408
1409         GET_UINT32_LIST_DS(schema, r, "systemMustContain", mem_ctx, obj, systemMustContain_ids);
1410         GET_UINT32_LIST_DS(schema, r, "systemMayContain", mem_ctx, obj, systemMayContain_ids);
1411         GET_UINT32_LIST_DS(schema, r, "mustContain", mem_ctx, obj, mustContain_ids);
1412         GET_UINT32_LIST_DS(schema, r, "mayContain", mem_ctx, obj, mayContain_ids);
1413
1414         GET_UINT32_LIST_DS(schema, r, "systemPossSuperiors", mem_ctx, obj, systemPossSuperiors_ids);
1415         GET_UINT32_LIST_DS(schema, r, "possSuperiors", mem_ctx, obj, possSuperiors_ids);
1416
1417         GET_STRING_DS(schema, r, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, false);
1418
1419         GET_UINT32_DS(schema, r, "schemaFlagsEx", obj, schemaFlagsEx);
1420         GET_BLOB_DS(schema, r, "msDs-Schema-Extensions", mem_ctx, obj, msDs_Schema_Extensions);
1421
1422         GET_BOOL_DS(schema, r, "showInAdvancedViewOnly", obj, showInAdvancedViewOnly, false);
1423         GET_STRING_DS(schema, r, "adminDisplayName", mem_ctx, obj, adminDisplayName, false);
1424         GET_STRING_DS(schema, r, "adminDescription", mem_ctx, obj, adminDescription, false);
1425         GET_STRING_DS(schema, r, "classDisplayName", mem_ctx, obj, classDisplayName, false);
1426         GET_BOOL_DS(schema, r, "defaultHidingValue", obj, defaultHidingValue, false);
1427         GET_BOOL_DS(schema, r, "isDefunct", obj, isDefunct, false);
1428         GET_BOOL_DS(schema, r, "systemOnly", obj, systemOnly, false);
1429
1430         return WERR_OK;
1431 }
1432