c9ff588880bf7d6db8bef92598bcdebb5e8aae59
[obnox/samba/samba-obnox.git] / source4 / dsdb / schema / schema_syntax.c
1 /*
2    Unix SMB/CIFS mplementation.
3    DSDB schema syntaxes
4
5    Copyright (C) Stefan Metzmacher <metze@samba.org> 2006
6    Copyright (C) Simo Sorce 2005
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
22 */
23 #include "includes.h"
24 #include "dsdb/samdb/samdb.h"
25 #include "librpc/gen_ndr/ndr_drsuapi.h"
26 #include "librpc/gen_ndr/ndr_security.h"
27 #include "librpc/gen_ndr/ndr_misc.h"
28 #include <ldb.h>
29 #include <ldb_errors.h>
30 #include "system/time.h"
31 #include "../lib/util/charset/charset.h"
32 #include "librpc/ndr/libndr.h"
33 #include "../lib/util/asn1.h"
34
35 /**
36  * Initialize dsdb_syntax_ctx with default values
37  * for common cases.
38  */
39 void dsdb_syntax_ctx_init(struct dsdb_syntax_ctx *ctx,
40                           struct ldb_context *ldb,
41                           const struct dsdb_schema *schema)
42 {
43         ctx->ldb        = ldb;
44         ctx->schema     = schema;
45
46         /*
47          * 'true' will keep current behavior,
48          * i.e. attributeID_id will be returned by default
49          */
50         ctx->is_schema_nc = true;
51
52         ctx->pfm_remote = NULL;
53 }
54
55
56 /**
57  * Returns ATTID for DRS attribute.
58  *
59  * ATTID depends on whether we are replicating
60  * Schema NC or msDs-IntId is set for schemaAttribute
61  * for the attribute.
62  */
63 uint32_t dsdb_attribute_get_attid(const struct dsdb_attribute *attr,
64                                   bool for_schema_nc)
65 {
66         if (!for_schema_nc && attr->msDS_IntId) {
67                 return attr->msDS_IntId;
68         }
69
70         return attr->attributeID_id;
71 }
72
73 /**
74  * Map an ATTID from remote DC to a local ATTID
75  * using remote prefixMap
76  */
77 static bool dsdb_syntax_attid_from_remote_attid(const struct dsdb_syntax_ctx *ctx,
78                                                 TALLOC_CTX *mem_ctx,
79                                                 uint32_t id_remote,
80                                                 uint32_t *id_local)
81 {
82         WERROR werr;
83         const char *oid;
84
85         /*
86          * map remote ATTID to local directly in case
87          * of no remote prefixMap (during provision for instance)
88          */
89         if (!ctx->pfm_remote) {
90                 *id_local = id_remote;
91                 return true;
92         }
93
94         werr = dsdb_schema_pfm_oid_from_attid(ctx->pfm_remote, id_remote, mem_ctx, &oid);
95         if (!W_ERROR_IS_OK(werr)) {
96                 DEBUG(0,("ATTID->OID failed (%s) for: 0x%08X\n", win_errstr(werr), id_remote));
97                 return false;
98         }
99
100         werr = dsdb_schema_pfm_make_attid(ctx->schema->prefixmap, oid, id_local);
101         if (!W_ERROR_IS_OK(werr)) {
102                 DEBUG(0,("OID->ATTID failed (%s) for: %s\n", win_errstr(werr), oid));
103                 return false;
104         }
105
106         return true;
107 }
108
109 static WERROR dsdb_syntax_FOOBAR_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
110                                                 const struct dsdb_attribute *attr,
111                                                 const struct drsuapi_DsReplicaAttribute *in,
112                                                 TALLOC_CTX *mem_ctx,
113                                                 struct ldb_message_element *out)
114 {
115         unsigned int i;
116
117         out->flags      = 0;
118         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
119         W_ERROR_HAVE_NO_MEMORY(out->name);
120
121         out->num_values = in->value_ctr.num_values;
122         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
123         W_ERROR_HAVE_NO_MEMORY(out->values);
124
125         for (i=0; i < out->num_values; i++) {
126                 char *str;
127
128                 if (in->value_ctr.values[i].blob == NULL) {
129                         return WERR_FOOBAR;
130                 }
131
132                 str = talloc_asprintf(out->values, "%s: not implemented",
133                                       attr->syntax->name);
134                 W_ERROR_HAVE_NO_MEMORY(str);
135
136                 out->values[i] = data_blob_string_const(str);
137         }
138
139         return WERR_OK;
140 }
141
142 static WERROR dsdb_syntax_FOOBAR_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
143                                                 const struct dsdb_attribute *attr,
144                                                 const struct ldb_message_element *in,
145                                                 TALLOC_CTX *mem_ctx,
146                                                 struct drsuapi_DsReplicaAttribute *out)
147 {
148         return WERR_FOOBAR;
149 }
150
151 static WERROR dsdb_syntax_FOOBAR_validate_ldb(const struct dsdb_syntax_ctx *ctx,
152                                               const struct dsdb_attribute *attr,
153                                               const struct ldb_message_element *in)
154 {
155         return WERR_FOOBAR;
156 }
157
158 static WERROR dsdb_syntax_BOOL_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
159                                               const struct dsdb_attribute *attr,
160                                               const struct drsuapi_DsReplicaAttribute *in,
161                                               TALLOC_CTX *mem_ctx,
162                                               struct ldb_message_element *out)
163 {
164         unsigned int i;
165
166         out->flags      = 0;
167         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
168         W_ERROR_HAVE_NO_MEMORY(out->name);
169
170         out->num_values = in->value_ctr.num_values;
171         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
172         W_ERROR_HAVE_NO_MEMORY(out->values);
173
174         for (i=0; i < out->num_values; i++) {
175                 uint32_t v;
176                 char *str;
177
178                 if (in->value_ctr.values[i].blob == NULL) {
179                         return WERR_FOOBAR;
180                 }
181
182                 if (in->value_ctr.values[i].blob->length != 4) {
183                         return WERR_FOOBAR;
184                 }
185
186                 v = IVAL(in->value_ctr.values[i].blob->data, 0);
187
188                 if (v != 0) {
189                         str = talloc_strdup(out->values, "TRUE");
190                         W_ERROR_HAVE_NO_MEMORY(str);
191                 } else {
192                         str = talloc_strdup(out->values, "FALSE");
193                         W_ERROR_HAVE_NO_MEMORY(str);
194                 }
195
196                 out->values[i] = data_blob_string_const(str);
197         }
198
199         return WERR_OK;
200 }
201
202 static WERROR dsdb_syntax_BOOL_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
203                                               const struct dsdb_attribute *attr,
204                                               const struct ldb_message_element *in,
205                                               TALLOC_CTX *mem_ctx,
206                                               struct drsuapi_DsReplicaAttribute *out)
207 {
208         unsigned int i;
209         DATA_BLOB *blobs;
210
211         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
212                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
213         }
214
215         out->attid                      = dsdb_attribute_get_attid(attr,
216                                                                    ctx->is_schema_nc);
217         out->value_ctr.num_values       = in->num_values;
218         out->value_ctr.values           = talloc_array(mem_ctx,
219                                                        struct drsuapi_DsAttributeValue,
220                                                        in->num_values);
221         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
222
223         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
224         W_ERROR_HAVE_NO_MEMORY(blobs);
225
226         for (i=0; i < in->num_values; i++) {
227                 out->value_ctr.values[i].blob   = &blobs[i];
228
229                 blobs[i] = data_blob_talloc(blobs, NULL, 4);
230                 W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
231
232                 if (in->values[i].length >= 4 &&
233                     strncmp("TRUE", (const char *)in->values[i].data, in->values[i].length) == 0) {
234                         SIVAL(blobs[i].data, 0, 0x00000001);
235                 } else if (in->values[i].length >= 5 &&
236                            strncmp("FALSE", (const char *)in->values[i].data, in->values[i].length) == 0) {
237                         SIVAL(blobs[i].data, 0, 0x00000000);
238                 } else {
239                         return WERR_FOOBAR;
240                 }
241         }
242
243         return WERR_OK;
244 }
245
246 static WERROR dsdb_syntax_BOOL_validate_ldb(const struct dsdb_syntax_ctx *ctx,
247                                             const struct dsdb_attribute *attr,
248                                             const struct ldb_message_element *in)
249 {
250         unsigned int i;
251
252         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
253                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
254         }
255
256         for (i=0; i < in->num_values; i++) {
257                 if (in->values[i].length == 0) {
258                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
259                 }
260
261                 if (in->values[i].length >= 4 &&
262                     strncmp("TRUE",
263                             (const char *)in->values[i].data,
264                             in->values[i].length) == 0) {
265                         continue;
266                 }
267                 if (in->values[i].length >= 5 &&
268                     strncmp("FALSE",
269                             (const char *)in->values[i].data,
270                             in->values[i].length) == 0) {
271                         continue;
272                 }
273                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
274         }
275
276         return WERR_OK;
277 }
278
279 static WERROR dsdb_syntax_INT32_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
280                                                const struct dsdb_attribute *attr,
281                                                const struct drsuapi_DsReplicaAttribute *in,
282                                                TALLOC_CTX *mem_ctx,
283                                                struct ldb_message_element *out)
284 {
285         unsigned int i;
286
287         out->flags      = 0;
288         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
289         W_ERROR_HAVE_NO_MEMORY(out->name);
290
291         out->num_values = in->value_ctr.num_values;
292         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
293         W_ERROR_HAVE_NO_MEMORY(out->values);
294
295         for (i=0; i < out->num_values; i++) {
296                 int32_t v;
297                 char *str;
298
299                 if (in->value_ctr.values[i].blob == NULL) {
300                         return WERR_FOOBAR;
301                 }
302
303                 if (in->value_ctr.values[i].blob->length != 4) {
304                         return WERR_FOOBAR;
305                 }
306
307                 v = IVALS(in->value_ctr.values[i].blob->data, 0);
308
309                 str = talloc_asprintf(out->values, "%d", v);
310                 W_ERROR_HAVE_NO_MEMORY(str);
311
312                 out->values[i] = data_blob_string_const(str);
313         }
314
315         return WERR_OK;
316 }
317
318 static WERROR dsdb_syntax_INT32_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
319                                                const struct dsdb_attribute *attr,
320                                                const struct ldb_message_element *in,
321                                                TALLOC_CTX *mem_ctx,
322                                                struct drsuapi_DsReplicaAttribute *out)
323 {
324         unsigned int i;
325         DATA_BLOB *blobs;
326
327         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
328                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
329         }
330
331         out->attid                      = dsdb_attribute_get_attid(attr,
332                                                                    ctx->is_schema_nc);
333         out->value_ctr.num_values       = in->num_values;
334         out->value_ctr.values           = talloc_array(mem_ctx,
335                                                        struct drsuapi_DsAttributeValue,
336                                                        in->num_values);
337         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
338
339         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
340         W_ERROR_HAVE_NO_MEMORY(blobs);
341
342         for (i=0; i < in->num_values; i++) {
343                 int32_t v;
344
345                 out->value_ctr.values[i].blob   = &blobs[i];
346
347                 blobs[i] = data_blob_talloc(blobs, NULL, 4);
348                 W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
349
350                 /* We've to use "strtoll" here to have the intended overflows.
351                  * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
352                 v = (int32_t) strtoll((char *)in->values[i].data, NULL, 0);
353
354                 SIVALS(blobs[i].data, 0, v);
355         }
356
357         return WERR_OK;
358 }
359
360 static WERROR dsdb_syntax_INT32_validate_ldb(const struct dsdb_syntax_ctx *ctx,
361                                              const struct dsdb_attribute *attr,
362                                              const struct ldb_message_element *in)
363 {
364         unsigned int i;
365
366         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
367                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
368         }
369
370         for (i=0; i < in->num_values; i++) {
371                 long v;
372                 char buf[sizeof("-2147483648")];
373                 char *end = NULL;
374
375                 ZERO_STRUCT(buf);
376                 if (in->values[i].length >= sizeof(buf)) {
377                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
378                 }
379
380                 memcpy(buf, in->values[i].data, in->values[i].length);
381                 errno = 0;
382                 v = strtol(buf, &end, 10);
383                 if (errno != 0) {
384                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
385                 }
386                 if (end && end[0] != '\0') {
387                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
388                 }
389
390                 if (attr->rangeLower) {
391                         if ((int32_t)v < (int32_t)*attr->rangeLower) {
392                                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
393                         }
394                 }
395
396                 if (attr->rangeUpper) {
397                         if ((int32_t)v > (int32_t)*attr->rangeUpper) {
398                                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
399                         }
400                 }
401         }
402
403         return WERR_OK;
404 }
405
406 static WERROR dsdb_syntax_INT64_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
407                                                const struct dsdb_attribute *attr,
408                                                const struct drsuapi_DsReplicaAttribute *in,
409                                                TALLOC_CTX *mem_ctx,
410                                                struct ldb_message_element *out)
411 {
412         unsigned int i;
413
414         out->flags      = 0;
415         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
416         W_ERROR_HAVE_NO_MEMORY(out->name);
417
418         out->num_values = in->value_ctr.num_values;
419         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
420         W_ERROR_HAVE_NO_MEMORY(out->values);
421
422         for (i=0; i < out->num_values; i++) {
423                 int64_t v;
424                 char *str;
425
426                 if (in->value_ctr.values[i].blob == NULL) {
427                         return WERR_FOOBAR;
428                 }
429
430                 if (in->value_ctr.values[i].blob->length != 8) {
431                         return WERR_FOOBAR;
432                 }
433
434                 v = BVALS(in->value_ctr.values[i].blob->data, 0);
435
436                 str = talloc_asprintf(out->values, "%lld", (long long int)v);
437                 W_ERROR_HAVE_NO_MEMORY(str);
438
439                 out->values[i] = data_blob_string_const(str);
440         }
441
442         return WERR_OK;
443 }
444
445 static WERROR dsdb_syntax_INT64_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
446                                                const struct dsdb_attribute *attr,
447                                                const struct ldb_message_element *in,
448                                                TALLOC_CTX *mem_ctx,
449                                                struct drsuapi_DsReplicaAttribute *out)
450 {
451         unsigned int i;
452         DATA_BLOB *blobs;
453
454         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
455                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
456         }
457
458         out->attid                      = dsdb_attribute_get_attid(attr,
459                                                                    ctx->is_schema_nc);
460         out->value_ctr.num_values       = in->num_values;
461         out->value_ctr.values           = talloc_array(mem_ctx,
462                                                        struct drsuapi_DsAttributeValue,
463                                                        in->num_values);
464         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
465
466         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
467         W_ERROR_HAVE_NO_MEMORY(blobs);
468
469         for (i=0; i < in->num_values; i++) {
470                 int64_t v;
471
472                 out->value_ctr.values[i].blob   = &blobs[i];
473
474                 blobs[i] = data_blob_talloc(blobs, NULL, 8);
475                 W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
476
477                 v = strtoll((const char *)in->values[i].data, NULL, 10);
478
479                 SBVALS(blobs[i].data, 0, v);
480         }
481
482         return WERR_OK;
483 }
484
485 static WERROR dsdb_syntax_INT64_validate_ldb(const struct dsdb_syntax_ctx *ctx,
486                                              const struct dsdb_attribute *attr,
487                                              const struct ldb_message_element *in)
488 {
489         unsigned int i;
490
491         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
492                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
493         }
494
495         for (i=0; i < in->num_values; i++) {
496                 long long v;
497                 char buf[sizeof("-9223372036854775808")];
498                 char *end = NULL;
499
500                 ZERO_STRUCT(buf);
501                 if (in->values[i].length >= sizeof(buf)) {
502                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
503                 }
504                 memcpy(buf, in->values[i].data, in->values[i].length);
505
506                 errno = 0;
507                 v = strtoll(buf, &end, 10);
508                 if (errno != 0) {
509                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
510                 }
511                 if (end && end[0] != '\0') {
512                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
513                 }
514
515                 if (attr->rangeLower) {
516                         if ((int64_t)v < (int64_t)*attr->rangeLower) {
517                                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
518                         }
519                 }
520
521                 if (attr->rangeUpper) {
522                         if ((int64_t)v > (int64_t)*attr->rangeUpper) {
523                                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
524                         }
525                 }
526         }
527
528         return WERR_OK;
529 }
530 static WERROR dsdb_syntax_NTTIME_UTC_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
531                                                     const struct dsdb_attribute *attr,
532                                                     const struct drsuapi_DsReplicaAttribute *in,
533                                                     TALLOC_CTX *mem_ctx,
534                                                     struct ldb_message_element *out)
535 {
536         unsigned int i;
537
538         out->flags      = 0;
539         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
540         W_ERROR_HAVE_NO_MEMORY(out->name);
541
542         out->num_values = in->value_ctr.num_values;
543         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
544         W_ERROR_HAVE_NO_MEMORY(out->values);
545
546         for (i=0; i < out->num_values; i++) {
547                 NTTIME v;
548                 time_t t;
549                 char *str;
550
551                 if (in->value_ctr.values[i].blob == NULL) {
552                         return WERR_FOOBAR;
553                 }
554
555                 if (in->value_ctr.values[i].blob->length != 8) {
556                         return WERR_FOOBAR;
557                 }
558
559                 v = BVAL(in->value_ctr.values[i].blob->data, 0);
560                 if (v == 0) {
561                         /* special case for 1601 zero timestamp */
562                         out->values[i] = data_blob_string_const("16010101000000.0Z");
563                         continue;
564                 }
565                 v *= 10000000;
566                 t = nt_time_to_unix(v);
567
568                 /*
569                  * NOTE: On a w2k3 server you can set a GeneralizedTime string
570                  *       via LDAP, but you get back an UTCTime string,
571                  *       but via DRSUAPI you get back the NTTIME_1sec value
572                  *       that represents the GeneralizedTime value!
573                  *
574                  *       So if we store the UTCTime string in our ldb
575                  *       we'll loose information!
576                  */
577                 str = ldb_timestring_utc(out->values, t);
578                 W_ERROR_HAVE_NO_MEMORY(str);
579                 out->values[i] = data_blob_string_const(str);
580         }
581
582         return WERR_OK;
583 }
584
585 static WERROR dsdb_syntax_NTTIME_UTC_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
586                                                     const struct dsdb_attribute *attr,
587                                                     const struct ldb_message_element *in,
588                                                     TALLOC_CTX *mem_ctx,
589                                                     struct drsuapi_DsReplicaAttribute *out)
590 {
591         unsigned int i;
592         DATA_BLOB *blobs;
593
594         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
595                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
596         }
597
598         out->attid                      = dsdb_attribute_get_attid(attr,
599                                                                    ctx->is_schema_nc);
600         out->value_ctr.num_values       = in->num_values;
601         out->value_ctr.values           = talloc_array(mem_ctx,
602                                                        struct drsuapi_DsAttributeValue,
603                                                        in->num_values);
604         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
605
606         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
607         W_ERROR_HAVE_NO_MEMORY(blobs);
608
609         for (i=0; i < in->num_values; i++) {
610                 NTTIME v;
611                 time_t t;
612
613                 out->value_ctr.values[i].blob   = &blobs[i];
614
615                 blobs[i] = data_blob_talloc(blobs, NULL, 8);
616                 W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
617
618                 if (ldb_val_string_cmp(&in->values[i], "16010101000000.0Z") == 0) {
619                         SBVALS(blobs[i].data, 0, 0);
620                         continue;
621                 }
622
623                 t = ldb_string_utc_to_time((const char *)in->values[i].data);
624                 unix_to_nt_time(&v, t);
625                 v /= 10000000;
626
627                 SBVAL(blobs[i].data, 0, v);
628         }
629
630         return WERR_OK;
631 }
632
633 static WERROR dsdb_syntax_NTTIME_UTC_validate_ldb(const struct dsdb_syntax_ctx *ctx,
634                                                   const struct dsdb_attribute *attr,
635                                                   const struct ldb_message_element *in)
636 {
637         unsigned int i;
638
639         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
640                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
641         }
642
643         for (i=0; i < in->num_values; i++) {
644                 time_t t;
645                 char buf[sizeof("090826075717Z")];
646
647                 ZERO_STRUCT(buf);
648                 if (in->values[i].length >= sizeof(buf)) {
649                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
650                 }
651                 memcpy(buf, in->values[i].data, in->values[i].length);
652
653                 t = ldb_string_utc_to_time(buf);
654                 if (t == 0) {
655                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
656                 }
657
658                 if (attr->rangeLower) {
659                         if ((int32_t)t < (int32_t)*attr->rangeLower) {
660                                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
661                         }
662                 }
663
664                 if (attr->rangeUpper) {
665                         if ((int32_t)t > (int32_t)*attr->rangeLower) {
666                                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
667                         }
668                 }
669
670                 /*
671                  * TODO: verify the comment in the
672                  * dsdb_syntax_NTTIME_UTC_drsuapi_to_ldb() function!
673                  */
674         }
675
676         return WERR_OK;
677 }
678
679 static WERROR dsdb_syntax_NTTIME_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
680                                                 const struct dsdb_attribute *attr,
681                                                 const struct drsuapi_DsReplicaAttribute *in,
682                                                 TALLOC_CTX *mem_ctx,
683                                                 struct ldb_message_element *out)
684 {
685         unsigned int i;
686
687         out->flags      = 0;
688         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
689         W_ERROR_HAVE_NO_MEMORY(out->name);
690
691         out->num_values = in->value_ctr.num_values;
692         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
693         W_ERROR_HAVE_NO_MEMORY(out->values);
694
695         for (i=0; i < out->num_values; i++) {
696                 NTTIME v;
697                 time_t t;
698                 char *str;
699
700                 if (in->value_ctr.values[i].blob == NULL) {
701                         return WERR_FOOBAR;
702                 }
703
704                 if (in->value_ctr.values[i].blob->length != 8) {
705                         return WERR_FOOBAR;
706                 }
707
708                 v = BVAL(in->value_ctr.values[i].blob->data, 0);
709                 if (v == 0) {
710                         /* special case for 1601 zero timestamp */
711                         out->values[i] = data_blob_string_const("16010101000000.0Z");
712                         continue;
713                 }
714                 v *= 10000000;
715                 t = nt_time_to_unix(v);
716
717                 str = ldb_timestring(out->values, t);
718                 W_ERROR_HAVE_NO_MEMORY(str);
719
720                 out->values[i] = data_blob_string_const(str);
721         }
722
723         return WERR_OK;
724 }
725
726 static WERROR dsdb_syntax_NTTIME_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
727                                                 const struct dsdb_attribute *attr,
728                                                 const struct ldb_message_element *in,
729                                                 TALLOC_CTX *mem_ctx,
730                                                 struct drsuapi_DsReplicaAttribute *out)
731 {
732         unsigned int i;
733         DATA_BLOB *blobs;
734
735         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
736                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
737         }
738
739         out->attid                      = dsdb_attribute_get_attid(attr,
740                                                                    ctx->is_schema_nc);
741         out->value_ctr.num_values       = in->num_values;
742         out->value_ctr.values           = talloc_array(mem_ctx,
743                                                        struct drsuapi_DsAttributeValue,
744                                                        in->num_values);
745         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
746
747         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
748         W_ERROR_HAVE_NO_MEMORY(blobs);
749
750         for (i=0; i < in->num_values; i++) {
751                 NTTIME v;
752                 time_t t;
753                 int ret;
754
755                 out->value_ctr.values[i].blob   = &blobs[i];
756
757                 blobs[i] = data_blob_talloc(blobs, NULL, 8);
758                 W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
759
760                 if (ldb_val_string_cmp(&in->values[i], "16010101000000.0Z") == 0) {
761                         SBVALS(blobs[i].data, 0, 0);
762                         continue;
763                 }
764
765                 ret = ldb_val_to_time(&in->values[i], &t);
766                 if (ret != LDB_SUCCESS) {
767                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
768                 }
769                 unix_to_nt_time(&v, t);
770                 v /= 10000000;
771
772                 SBVAL(blobs[i].data, 0, v);
773         }
774
775         return WERR_OK;
776 }
777
778 static WERROR dsdb_syntax_NTTIME_validate_ldb(const struct dsdb_syntax_ctx *ctx,
779                                               const struct dsdb_attribute *attr,
780                                               const struct ldb_message_element *in)
781 {
782         unsigned int i;
783
784         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
785                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
786         }
787
788         for (i=0; i < in->num_values; i++) {
789                 time_t t;
790                 int ret;
791
792                 ret = ldb_val_to_time(&in->values[i], &t);
793                 if (ret != LDB_SUCCESS) {
794                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
795                 }
796
797                 if (attr->rangeLower) {
798                         if ((int32_t)t < (int32_t)*attr->rangeLower) {
799                                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
800                         }
801                 }
802
803                 if (attr->rangeUpper) {
804                         if ((int32_t)t > (int32_t)*attr->rangeLower) {
805                                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
806                         }
807                 }
808         }
809
810         return WERR_OK;
811 }
812
813 static WERROR dsdb_syntax_DATA_BLOB_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
814                                                    const struct dsdb_attribute *attr,
815                                                    const struct drsuapi_DsReplicaAttribute *in,
816                                                    TALLOC_CTX *mem_ctx,
817                                                    struct ldb_message_element *out)
818 {
819         unsigned int i;
820
821         out->flags      = 0;
822         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
823         W_ERROR_HAVE_NO_MEMORY(out->name);
824
825         out->num_values = in->value_ctr.num_values;
826         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
827         W_ERROR_HAVE_NO_MEMORY(out->values);
828
829         for (i=0; i < out->num_values; i++) {
830                 if (in->value_ctr.values[i].blob == NULL) {
831                         return WERR_FOOBAR;
832                 }
833
834                 if (in->value_ctr.values[i].blob->length == 0) {
835                         return WERR_FOOBAR;
836                 }
837
838                 out->values[i] = data_blob_dup_talloc(out->values,
839                                                       *in->value_ctr.values[i].blob);
840                 W_ERROR_HAVE_NO_MEMORY(out->values[i].data);
841         }
842
843         return WERR_OK;
844 }
845
846 static WERROR dsdb_syntax_DATA_BLOB_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
847                                                    const struct dsdb_attribute *attr,
848                                                    const struct ldb_message_element *in,
849                                                    TALLOC_CTX *mem_ctx,
850                                                    struct drsuapi_DsReplicaAttribute *out)
851 {
852         unsigned int i;
853         DATA_BLOB *blobs;
854
855         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
856                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
857         }
858
859         out->attid                      = dsdb_attribute_get_attid(attr,
860                                                                    ctx->is_schema_nc);
861         out->value_ctr.num_values       = in->num_values;
862         out->value_ctr.values           = talloc_array(mem_ctx,
863                                                        struct drsuapi_DsAttributeValue,
864                                                        in->num_values);
865         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
866
867         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
868         W_ERROR_HAVE_NO_MEMORY(blobs);
869
870         for (i=0; i < in->num_values; i++) {
871                 out->value_ctr.values[i].blob   = &blobs[i];
872
873                 blobs[i] = data_blob_dup_talloc(blobs, in->values[i]);
874                 W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
875         }
876
877         return WERR_OK;
878 }
879
880 static WERROR dsdb_syntax_DATA_BLOB_validate_one_val(const struct dsdb_syntax_ctx *ctx,
881                                                      const struct dsdb_attribute *attr,
882                                                      const struct ldb_val *val)
883 {
884         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
885                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
886         }
887
888         if (attr->rangeLower) {
889                 if ((uint32_t)val->length < (uint32_t)*attr->rangeLower) {
890                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
891                 }
892         }
893
894         if (attr->rangeUpper) {
895                 if ((uint32_t)val->length > (uint32_t)*attr->rangeUpper) {
896                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
897                 }
898         }
899
900         return WERR_OK;
901 }
902
903 static WERROR dsdb_syntax_DATA_BLOB_validate_ldb(const struct dsdb_syntax_ctx *ctx,
904                                                  const struct dsdb_attribute *attr,
905                                                  const struct ldb_message_element *in)
906 {
907         unsigned int i;
908         WERROR status;
909
910         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
911                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
912         }
913
914         for (i=0; i < in->num_values; i++) {
915                 if (in->values[i].length == 0) {
916                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
917                 }
918
919                 status = dsdb_syntax_DATA_BLOB_validate_one_val(ctx,
920                                                                 attr,
921                                                                 &in->values[i]);
922                 if (!W_ERROR_IS_OK(status)) {
923                         return status;
924                 }
925         }
926
927         return WERR_OK;
928 }
929
930 static WERROR _dsdb_syntax_auto_OID_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
931                                                    const struct dsdb_attribute *attr,
932                                                    const struct drsuapi_DsReplicaAttribute *in,
933                                                    TALLOC_CTX *mem_ctx,
934                                                    struct ldb_message_element *out)
935 {
936         unsigned int i;
937
938         out->flags      = 0;
939         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
940         W_ERROR_HAVE_NO_MEMORY(out->name);
941
942         out->num_values = in->value_ctr.num_values;
943         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
944         W_ERROR_HAVE_NO_MEMORY(out->values);
945
946         for (i=0; i < out->num_values; i++) {
947                 uint32_t v;
948                 const struct dsdb_class *c;
949                 const struct dsdb_attribute *a;
950                 const char *str = NULL;
951
952                 if (in->value_ctr.values[i].blob == NULL) {
953                         return WERR_FOOBAR;
954                 }
955
956                 if (in->value_ctr.values[i].blob->length != 4) {
957                         return WERR_FOOBAR;
958                 }
959
960                 v = IVAL(in->value_ctr.values[i].blob->data, 0);
961
962                 if ((c = dsdb_class_by_governsID_id(ctx->schema, v))) {
963                         str = talloc_strdup(out->values, c->lDAPDisplayName);
964                 } else if ((a = dsdb_attribute_by_attributeID_id(ctx->schema, v))) {
965                         str = talloc_strdup(out->values, a->lDAPDisplayName);
966                 } else {
967                         WERROR werr;
968                         SMB_ASSERT(ctx->pfm_remote);
969                         werr = dsdb_schema_pfm_oid_from_attid(ctx->pfm_remote, v,
970                                                               out->values, &str);
971                         W_ERROR_NOT_OK_RETURN(werr);
972                 }
973                 W_ERROR_HAVE_NO_MEMORY(str);
974
975                 /* the values need to be reversed */
976                 out->values[out->num_values - (i + 1)] = data_blob_string_const(str);
977         }
978
979         return WERR_OK;
980 }
981
982 static WERROR _dsdb_syntax_OID_obj_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
983                                                   const struct dsdb_attribute *attr,
984                                                   const struct drsuapi_DsReplicaAttribute *in,
985                                                   TALLOC_CTX *mem_ctx,
986                                                   struct ldb_message_element *out)
987 {
988         unsigned int i;
989
990         out->flags      = 0;
991         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
992         W_ERROR_HAVE_NO_MEMORY(out->name);
993
994         out->num_values = in->value_ctr.num_values;
995         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
996         W_ERROR_HAVE_NO_MEMORY(out->values);
997
998         for (i=0; i < out->num_values; i++) {
999                 uint32_t v;
1000                 const struct dsdb_class *c;
1001                 const char *str;
1002
1003                 if (in->value_ctr.values[i].blob == NULL) {
1004                         return WERR_FOOBAR;
1005                 }
1006
1007                 if (in->value_ctr.values[i].blob->length != 4) {
1008                         return WERR_FOOBAR;
1009                 }
1010
1011                 v = IVAL(in->value_ctr.values[i].blob->data, 0);
1012
1013                 /* convert remote ATTID to local ATTID */
1014                 if (!dsdb_syntax_attid_from_remote_attid(ctx, mem_ctx, v, &v)) {
1015                         DEBUG(1,(__location__ ": Failed to map remote ATTID to local ATTID!\n"));
1016                         return WERR_FOOBAR;
1017                 }
1018
1019                 c = dsdb_class_by_governsID_id(ctx->schema, v);
1020                 if (!c) {
1021                         DEBUG(1,(__location__ ": Unknown governsID 0x%08X\n", v));
1022                         return WERR_FOOBAR;
1023                 }
1024
1025                 str = talloc_strdup(out->values, c->lDAPDisplayName);
1026                 W_ERROR_HAVE_NO_MEMORY(str);
1027
1028                 /* the values need to be reversed */
1029                 out->values[out->num_values - (i + 1)] = data_blob_string_const(str);
1030         }
1031
1032         return WERR_OK;
1033 }
1034
1035 static WERROR _dsdb_syntax_OID_attr_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
1036                                                    const struct dsdb_attribute *attr,
1037                                                    const struct drsuapi_DsReplicaAttribute *in,
1038                                                    TALLOC_CTX *mem_ctx,
1039                                                    struct ldb_message_element *out)
1040 {
1041         unsigned int i;
1042
1043         out->flags      = 0;
1044         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
1045         W_ERROR_HAVE_NO_MEMORY(out->name);
1046
1047         out->num_values = in->value_ctr.num_values;
1048         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
1049         W_ERROR_HAVE_NO_MEMORY(out->values);
1050
1051         for (i=0; i < out->num_values; i++) {
1052                 uint32_t v;
1053                 const struct dsdb_attribute *a;
1054                 const char *str;
1055
1056                 if (in->value_ctr.values[i].blob == NULL) {
1057                         DEBUG(0, ("Attribute has no value\n"));
1058                         return WERR_FOOBAR;
1059                 }
1060
1061                 if (in->value_ctr.values[i].blob->length != 4) {
1062                         DEBUG(0, ("Attribute has a value with 0 length\n"));
1063                         return WERR_FOOBAR;
1064                 }
1065
1066                 v = IVAL(in->value_ctr.values[i].blob->data, 0);
1067
1068                 /* convert remote ATTID to local ATTID */
1069                 if (!dsdb_syntax_attid_from_remote_attid(ctx, mem_ctx, v, &v)) {
1070                         DEBUG(1,(__location__ ": Failed to map remote ATTID to local ATTID!\n"));
1071                         return WERR_FOOBAR;
1072                 }
1073
1074                 a = dsdb_attribute_by_attributeID_id(ctx->schema, v);
1075                 if (!a) {
1076                         DEBUG(1,(__location__ ": Unknown attributeID_id 0x%08X\n", v));
1077                         return WERR_FOOBAR;
1078                 }
1079
1080                 str = talloc_strdup(out->values, a->lDAPDisplayName);
1081                 W_ERROR_HAVE_NO_MEMORY(str);
1082
1083                 /* the values need to be reversed */
1084                 out->values[out->num_values - (i + 1)] = data_blob_string_const(str);
1085         }
1086
1087         return WERR_OK;
1088 }
1089
1090 static WERROR _dsdb_syntax_OID_oid_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
1091                                                   const struct dsdb_attribute *attr,
1092                                                   const struct drsuapi_DsReplicaAttribute *in,
1093                                                   TALLOC_CTX *mem_ctx,
1094                                                   struct ldb_message_element *out)
1095 {
1096         unsigned int i;
1097         const struct dsdb_schema_prefixmap *prefixmap;
1098
1099         if (ctx->pfm_remote != NULL) {
1100                 prefixmap = ctx->pfm_remote;
1101         } else {
1102                 prefixmap = ctx->schema->prefixmap;
1103         }
1104         SMB_ASSERT(prefixmap);
1105
1106         out->flags      = 0;
1107         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
1108         W_ERROR_HAVE_NO_MEMORY(out->name);
1109
1110         out->num_values = in->value_ctr.num_values;
1111         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
1112         W_ERROR_HAVE_NO_MEMORY(out->values);
1113
1114         for (i=0; i < out->num_values; i++) {
1115                 uint32_t attid;
1116                 WERROR status;
1117                 const char *oid;
1118
1119                 if (in->value_ctr.values[i].blob == NULL) {
1120                         return WERR_FOOBAR;
1121                 }
1122
1123                 if (in->value_ctr.values[i].blob->length != 4) {
1124                         return WERR_FOOBAR;
1125                 }
1126
1127                 attid = IVAL(in->value_ctr.values[i].blob->data, 0);
1128
1129                 status = dsdb_schema_pfm_oid_from_attid(prefixmap, attid,
1130                                                         out->values, &oid);
1131                 if (!W_ERROR_IS_OK(status)) {
1132                         DEBUG(0,(__location__ ": Error: Unknown ATTID 0x%08X\n",
1133                                  attid));
1134                         return status;
1135                 }
1136
1137                 out->values[i] = data_blob_string_const(oid);
1138         }
1139
1140         return WERR_OK;
1141 }
1142
1143 static WERROR _dsdb_syntax_auto_OID_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
1144                                                    const struct dsdb_attribute *attr,
1145                                                    const struct ldb_message_element *in,
1146                                                    TALLOC_CTX *mem_ctx,
1147                                                    struct drsuapi_DsReplicaAttribute *out)
1148 {
1149         unsigned int i;
1150         DATA_BLOB *blobs;
1151
1152         out->attid= dsdb_attribute_get_attid(attr,
1153                                              ctx->is_schema_nc);
1154         out->value_ctr.num_values= in->num_values;
1155         out->value_ctr.values= talloc_array(mem_ctx,
1156                                             struct drsuapi_DsAttributeValue,
1157                                             in->num_values);
1158         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
1159
1160         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
1161         W_ERROR_HAVE_NO_MEMORY(blobs);
1162
1163         for (i=0; i < in->num_values; i++) {
1164                 const struct dsdb_class *obj_class;
1165                 const struct dsdb_attribute *obj_attr;
1166                 struct ldb_val *v;
1167
1168                 out->value_ctr.values[i].blob= &blobs[i];
1169
1170                 blobs[i] = data_blob_talloc(blobs, NULL, 4);
1171                 W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
1172
1173                 /* in DRS windows puts the classes in the opposite
1174                    order to the order used in ldap */
1175                 v = &in->values[(in->num_values-1)-i];
1176
1177                 if ((obj_class = dsdb_class_by_lDAPDisplayName_ldb_val(ctx->schema, v))) {
1178                         SIVAL(blobs[i].data, 0, obj_class->governsID_id);
1179                 } else if ((obj_attr = dsdb_attribute_by_lDAPDisplayName_ldb_val(ctx->schema, v))) {
1180                         SIVAL(blobs[i].data, 0, obj_attr->attributeID_id);
1181                 } else {
1182                         uint32_t attid;
1183                         WERROR werr;
1184                         werr = dsdb_schema_pfm_attid_from_oid(ctx->schema->prefixmap,
1185                                                               (const char *)v->data,
1186                                                               &attid);
1187                         W_ERROR_NOT_OK_RETURN(werr);
1188                         SIVAL(blobs[i].data, 0, attid);
1189                 }
1190
1191         }
1192
1193
1194         return WERR_OK;
1195 }
1196
1197 static WERROR _dsdb_syntax_OID_obj_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
1198                                                   const struct dsdb_attribute *attr,
1199                                                   const struct ldb_message_element *in,
1200                                                   TALLOC_CTX *mem_ctx,
1201                                                   struct drsuapi_DsReplicaAttribute *out)
1202 {
1203         unsigned int i;
1204         DATA_BLOB *blobs;
1205
1206         out->attid= dsdb_attribute_get_attid(attr,
1207                                              ctx->is_schema_nc);
1208         out->value_ctr.num_values= in->num_values;
1209         out->value_ctr.values= talloc_array(mem_ctx,
1210                                             struct drsuapi_DsAttributeValue,
1211                                             in->num_values);
1212         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
1213
1214         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
1215         W_ERROR_HAVE_NO_MEMORY(blobs);
1216
1217         for (i=0; i < in->num_values; i++) {
1218                 const struct dsdb_class *obj_class;
1219
1220                 out->value_ctr.values[i].blob= &blobs[i];
1221
1222                 blobs[i] = data_blob_talloc(blobs, NULL, 4);
1223                 W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
1224
1225                 /* in DRS windows puts the classes in the opposite
1226                    order to the order used in ldap */
1227                 obj_class = dsdb_class_by_lDAPDisplayName(ctx->schema,
1228                                                           (const char *)in->values[(in->num_values-1)-i].data);
1229                 if (!obj_class) {
1230                         return WERR_FOOBAR;
1231                 }
1232                 SIVAL(blobs[i].data, 0, obj_class->governsID_id);
1233         }
1234
1235
1236         return WERR_OK;
1237 }
1238
1239 static WERROR _dsdb_syntax_OID_attr_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
1240                                                    const struct dsdb_attribute *attr,
1241                                                    const struct ldb_message_element *in,
1242                                                    TALLOC_CTX *mem_ctx,
1243                                                    struct drsuapi_DsReplicaAttribute *out)
1244 {
1245         unsigned int i;
1246         DATA_BLOB *blobs;
1247
1248         out->attid= dsdb_attribute_get_attid(attr,
1249                                              ctx->is_schema_nc);
1250         out->value_ctr.num_values= in->num_values;
1251         out->value_ctr.values= talloc_array(mem_ctx,
1252                                             struct drsuapi_DsAttributeValue,
1253                                             in->num_values);
1254         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
1255
1256         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
1257         W_ERROR_HAVE_NO_MEMORY(blobs);
1258
1259         for (i=0; i < in->num_values; i++) {
1260                 const struct dsdb_attribute *obj_attr;
1261
1262                 out->value_ctr.values[i].blob= &blobs[i];
1263
1264                 blobs[i] = data_blob_talloc(blobs, NULL, 4);
1265                 W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
1266
1267                 obj_attr = dsdb_attribute_by_lDAPDisplayName(ctx->schema, (const char *)in->values[i].data);
1268                 if (!obj_attr) {
1269                         DEBUG(0, ("Unable to find attribute %s in the schema\n", (const char *)in->values[i].data));
1270                         return WERR_FOOBAR;
1271                 }
1272                 SIVAL(blobs[i].data, 0, obj_attr->attributeID_id);
1273         }
1274
1275
1276         return WERR_OK;
1277 }
1278
1279 static WERROR _dsdb_syntax_OID_oid_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
1280                                                   const struct dsdb_attribute *attr,
1281                                                   const struct ldb_message_element *in,
1282                                                   TALLOC_CTX *mem_ctx,
1283                                                   struct drsuapi_DsReplicaAttribute *out)
1284 {
1285         unsigned int i;
1286         DATA_BLOB *blobs;
1287
1288         out->attid= dsdb_attribute_get_attid(attr,
1289                                              ctx->is_schema_nc);
1290         out->value_ctr.num_values= in->num_values;
1291         out->value_ctr.values= talloc_array(mem_ctx,
1292                                             struct drsuapi_DsAttributeValue,
1293                                             in->num_values);
1294         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
1295
1296         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
1297         W_ERROR_HAVE_NO_MEMORY(blobs);
1298
1299         for (i=0; i < in->num_values; i++) {
1300                 uint32_t attid;
1301                 WERROR status;
1302
1303                 out->value_ctr.values[i].blob= &blobs[i];
1304
1305                 blobs[i] = data_blob_talloc(blobs, NULL, 4);
1306                 W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
1307
1308                 status = dsdb_schema_pfm_attid_from_oid(ctx->schema->prefixmap,
1309                                                         (const char *)in->values[i].data,
1310                                                         &attid);
1311                 W_ERROR_NOT_OK_RETURN(status);
1312
1313                 SIVAL(blobs[i].data, 0, attid);
1314         }
1315
1316         return WERR_OK;
1317 }
1318
1319 static WERROR dsdb_syntax_OID_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
1320                                              const struct dsdb_attribute *attr,
1321                                              const struct drsuapi_DsReplicaAttribute *in,
1322                                              TALLOC_CTX *mem_ctx,
1323                                              struct ldb_message_element *out)
1324 {
1325         WERROR werr;
1326
1327         switch (attr->attributeID_id) {
1328         case DRSUAPI_ATTID_objectClass:
1329         case DRSUAPI_ATTID_subClassOf:
1330         case DRSUAPI_ATTID_auxiliaryClass:
1331         case DRSUAPI_ATTID_systemAuxiliaryClass:
1332         case DRSUAPI_ATTID_systemPossSuperiors:
1333         case DRSUAPI_ATTID_possSuperiors:
1334                 werr = _dsdb_syntax_OID_obj_drsuapi_to_ldb(ctx, attr, in, mem_ctx, out);
1335                 break;
1336         case DRSUAPI_ATTID_systemMustContain:
1337         case DRSUAPI_ATTID_systemMayContain:
1338         case DRSUAPI_ATTID_mustContain:
1339         case DRSUAPI_ATTID_rDNAttId:
1340         case DRSUAPI_ATTID_transportAddressAttribute:
1341         case DRSUAPI_ATTID_mayContain:
1342                 werr = _dsdb_syntax_OID_attr_drsuapi_to_ldb(ctx, attr, in, mem_ctx, out);
1343                 break;
1344         case DRSUAPI_ATTID_governsID:
1345         case DRSUAPI_ATTID_attributeID:
1346         case DRSUAPI_ATTID_attributeSyntax:
1347                 werr = _dsdb_syntax_OID_oid_drsuapi_to_ldb(ctx, attr, in, mem_ctx, out);
1348                 break;
1349         default:
1350                 DEBUG(0,(__location__ ": Unknown handling for attributeID_id for %s\n",
1351                          attr->lDAPDisplayName));
1352                 return _dsdb_syntax_auto_OID_drsuapi_to_ldb(ctx, attr, in, mem_ctx, out);
1353         }
1354
1355         /* When we are doing the vampire of a schema, we don't want
1356          * the inability to reference an OID to get in the way.
1357          * Otherwise, we won't get the new schema with which to
1358          * understand this */
1359         if (!W_ERROR_IS_OK(werr) && ctx->schema->relax_OID_conversions) {
1360                 return _dsdb_syntax_OID_oid_drsuapi_to_ldb(ctx, attr, in, mem_ctx, out);
1361         }
1362         return werr;
1363 }
1364
1365 static WERROR dsdb_syntax_OID_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
1366                                              const struct dsdb_attribute *attr,
1367                                              const struct ldb_message_element *in,
1368                                              TALLOC_CTX *mem_ctx,
1369                                              struct drsuapi_DsReplicaAttribute *out)
1370 {
1371         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
1372                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
1373         }
1374
1375         switch (attr->attributeID_id) {
1376         case DRSUAPI_ATTID_objectClass:
1377         case DRSUAPI_ATTID_subClassOf:
1378         case DRSUAPI_ATTID_auxiliaryClass:
1379         case DRSUAPI_ATTID_systemAuxiliaryClass:
1380         case DRSUAPI_ATTID_systemPossSuperiors:
1381         case DRSUAPI_ATTID_possSuperiors:
1382                 return _dsdb_syntax_OID_obj_ldb_to_drsuapi(ctx, attr, in, mem_ctx, out);
1383         case DRSUAPI_ATTID_systemMustContain:
1384         case DRSUAPI_ATTID_systemMayContain:
1385         case DRSUAPI_ATTID_mustContain:
1386         case DRSUAPI_ATTID_rDNAttId:
1387         case DRSUAPI_ATTID_transportAddressAttribute:
1388         case DRSUAPI_ATTID_mayContain:
1389                 return _dsdb_syntax_OID_attr_ldb_to_drsuapi(ctx, attr, in, mem_ctx, out);
1390         case DRSUAPI_ATTID_governsID:
1391         case DRSUAPI_ATTID_attributeID:
1392         case DRSUAPI_ATTID_attributeSyntax:
1393                 return _dsdb_syntax_OID_oid_ldb_to_drsuapi(ctx, attr, in, mem_ctx, out);
1394         }
1395
1396         DEBUG(0,(__location__ ": Unknown handling for attributeID_id for %s\n",
1397                  attr->lDAPDisplayName));
1398
1399         return _dsdb_syntax_auto_OID_ldb_to_drsuapi(ctx, attr, in, mem_ctx, out);
1400 }
1401
1402 static WERROR _dsdb_syntax_OID_validate_numericoid(const struct dsdb_syntax_ctx *ctx,
1403                                                    const struct dsdb_attribute *attr,
1404                                                    const struct ldb_message_element *in)
1405 {
1406         unsigned int i;
1407         TALLOC_CTX *tmp_ctx;
1408
1409         tmp_ctx = talloc_new(ctx->ldb);
1410         W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
1411
1412         for (i=0; i < in->num_values; i++) {
1413                 DATA_BLOB blob;
1414                 char *oid_out;
1415                 const char *oid = (const char*)in->values[i].data;
1416
1417                 if (in->values[i].length == 0) {
1418                         talloc_free(tmp_ctx);
1419                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1420                 }
1421
1422                 if (!ber_write_OID_String(tmp_ctx, &blob, oid)) {
1423                         DEBUG(0,("ber_write_OID_String() failed for %s\n", oid));
1424                         talloc_free(tmp_ctx);
1425                         return WERR_INVALID_PARAMETER;
1426                 }
1427
1428                 if (!ber_read_OID_String(tmp_ctx, blob, &oid_out)) {
1429                         DEBUG(0,("ber_read_OID_String() failed for %s\n",
1430                                  hex_encode_talloc(tmp_ctx, blob.data, blob.length)));
1431                         talloc_free(tmp_ctx);
1432                         return WERR_INVALID_PARAMETER;
1433                 }
1434
1435                 if (strcmp(oid, oid_out) != 0) {
1436                         talloc_free(tmp_ctx);
1437                         return WERR_INVALID_PARAMETER;
1438                 }
1439         }
1440
1441         talloc_free(tmp_ctx);
1442         return WERR_OK;
1443 }
1444
1445 static WERROR dsdb_syntax_OID_validate_ldb(const struct dsdb_syntax_ctx *ctx,
1446                                            const struct dsdb_attribute *attr,
1447                                            const struct ldb_message_element *in)
1448 {
1449         WERROR status;
1450         struct drsuapi_DsReplicaAttribute drs_tmp;
1451         struct ldb_message_element ldb_tmp;
1452         TALLOC_CTX *tmp_ctx;
1453
1454         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
1455                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
1456         }
1457
1458         switch (attr->attributeID_id) {
1459         case DRSUAPI_ATTID_governsID:
1460         case DRSUAPI_ATTID_attributeID:
1461         case DRSUAPI_ATTID_attributeSyntax:
1462                 return _dsdb_syntax_OID_validate_numericoid(ctx, attr, in);
1463         }
1464
1465         /*
1466          * TODO: optimize and verify this code
1467          */
1468
1469         tmp_ctx = talloc_new(ctx->ldb);
1470         W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
1471
1472         status = dsdb_syntax_OID_ldb_to_drsuapi(ctx,
1473                                                 attr,
1474                                                 in,
1475                                                 tmp_ctx,
1476                                                 &drs_tmp);
1477         if (!W_ERROR_IS_OK(status)) {
1478                 talloc_free(tmp_ctx);
1479                 return status;
1480         }
1481
1482         status = dsdb_syntax_OID_drsuapi_to_ldb(ctx,
1483                                                 attr,
1484                                                 &drs_tmp,
1485                                                 tmp_ctx,
1486                                                 &ldb_tmp);
1487         if (!W_ERROR_IS_OK(status)) {
1488                 talloc_free(tmp_ctx);
1489                 return status;
1490         }
1491
1492         talloc_free(tmp_ctx);
1493         return WERR_OK;
1494 }
1495
1496 static WERROR dsdb_syntax_UNICODE_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
1497                                                  const struct dsdb_attribute *attr,
1498                                                  const struct drsuapi_DsReplicaAttribute *in,
1499                                                  TALLOC_CTX *mem_ctx,
1500                                                  struct ldb_message_element *out)
1501 {
1502         unsigned int i;
1503
1504         out->flags      = 0;
1505         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
1506         W_ERROR_HAVE_NO_MEMORY(out->name);
1507
1508         out->num_values = in->value_ctr.num_values;
1509         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
1510         W_ERROR_HAVE_NO_MEMORY(out->values);
1511
1512         for (i=0; i < out->num_values; i++) {
1513                 size_t converted_size = 0;
1514                 char *str;
1515
1516                 if (in->value_ctr.values[i].blob == NULL) {
1517                         return WERR_FOOBAR;
1518                 }
1519
1520                 if (in->value_ctr.values[i].blob->length == 0) {
1521                         return WERR_FOOBAR;
1522                 }
1523
1524                 if (!convert_string_talloc(out->values,
1525                                            CH_UTF16, CH_UNIX,
1526                                            in->value_ctr.values[i].blob->data,
1527                                            in->value_ctr.values[i].blob->length,
1528                                            (void **)&str, &converted_size)) {
1529                         return WERR_FOOBAR;
1530                 }
1531
1532                 out->values[i] = data_blob_const(str, converted_size);
1533         }
1534
1535         return WERR_OK;
1536 }
1537
1538 static WERROR dsdb_syntax_UNICODE_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
1539                                                  const struct dsdb_attribute *attr,
1540                                                  const struct ldb_message_element *in,
1541                                                  TALLOC_CTX *mem_ctx,
1542                                                  struct drsuapi_DsReplicaAttribute *out)
1543 {
1544         unsigned int i;
1545         DATA_BLOB *blobs;
1546
1547         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
1548                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
1549         }
1550
1551         out->attid                      = dsdb_attribute_get_attid(attr,
1552                                                                    ctx->is_schema_nc);
1553         out->value_ctr.num_values       = in->num_values;
1554         out->value_ctr.values           = talloc_array(mem_ctx,
1555                                                        struct drsuapi_DsAttributeValue,
1556                                                        in->num_values);
1557         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
1558
1559         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
1560         W_ERROR_HAVE_NO_MEMORY(blobs);
1561
1562         for (i=0; i < in->num_values; i++) {
1563                 out->value_ctr.values[i].blob   = &blobs[i];
1564
1565                 if (!convert_string_talloc(blobs,
1566                                            CH_UNIX, CH_UTF16,
1567                                            in->values[i].data, in->values[i].length,
1568                                            (void **)&blobs[i].data, &blobs[i].length)) {
1569                         return WERR_FOOBAR;
1570                 }
1571         }
1572
1573         return WERR_OK;
1574 }
1575
1576 static WERROR dsdb_syntax_UNICODE_validate_one_val(const struct dsdb_syntax_ctx *ctx,
1577                                                    const struct dsdb_attribute *attr,
1578                                                    const struct ldb_val *val)
1579 {
1580         void *dst = NULL;
1581         size_t size;
1582         bool ok;
1583
1584         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
1585                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
1586         }
1587
1588         ok = convert_string_talloc(ctx->ldb,
1589                                    CH_UNIX, CH_UTF16,
1590                                    val->data,
1591                                    val->length,
1592                                    (void **)&dst,
1593                                    &size);
1594         TALLOC_FREE(dst);
1595         if (!ok) {
1596                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1597         }
1598
1599         if (attr->rangeLower) {
1600                 if ((size/2) < *attr->rangeLower) {
1601                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1602                 }
1603         }
1604
1605         if (attr->rangeUpper) {
1606                 if ((size/2) > *attr->rangeUpper) {
1607                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1608                 }
1609         }
1610
1611         return WERR_OK;
1612 }
1613
1614 static WERROR dsdb_syntax_UNICODE_validate_ldb(const struct dsdb_syntax_ctx *ctx,
1615                                                const struct dsdb_attribute *attr,
1616                                                const struct ldb_message_element *in)
1617 {
1618         WERROR status;
1619         unsigned int i;
1620
1621         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
1622                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
1623         }
1624
1625         for (i=0; i < in->num_values; i++) {
1626                 if (in->values[i].length == 0) {
1627                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1628                 }
1629
1630                 status = dsdb_syntax_UNICODE_validate_one_val(ctx,
1631                                                               attr,
1632                                                               &in->values[i]);
1633                 if (!W_ERROR_IS_OK(status)) {
1634                         return status;
1635                 }
1636         }
1637
1638         return WERR_OK;
1639 }
1640
1641 static WERROR dsdb_syntax_one_DN_drsuapi_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
1642                                                 const struct dsdb_syntax *syntax,
1643                                                 const DATA_BLOB *in, DATA_BLOB *out)
1644 {
1645         struct drsuapi_DsReplicaObjectIdentifier3 id3;
1646         enum ndr_err_code ndr_err;
1647         DATA_BLOB guid_blob;
1648         struct ldb_dn *dn;
1649         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1650         int ret;
1651         NTSTATUS status;
1652
1653         if (!tmp_ctx) {
1654                 W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
1655         }
1656
1657         if (in == NULL) {
1658                 talloc_free(tmp_ctx);
1659                 return WERR_FOOBAR;
1660         }
1661
1662         if (in->length == 0) {
1663                 talloc_free(tmp_ctx);
1664                 return WERR_FOOBAR;
1665         }
1666
1667
1668         /* windows sometimes sends an extra two pad bytes here */
1669         ndr_err = ndr_pull_struct_blob(in,
1670                                        tmp_ctx, &id3,
1671                                        (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
1672         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1673                 status = ndr_map_error2ntstatus(ndr_err);
1674                 talloc_free(tmp_ctx);
1675                 return ntstatus_to_werror(status);
1676         }
1677
1678         dn = ldb_dn_new(tmp_ctx, ldb, id3.dn);
1679         if (!dn) {
1680                 talloc_free(tmp_ctx);
1681                 /* If this fails, it must be out of memory, as it does not do much parsing */
1682                 W_ERROR_HAVE_NO_MEMORY(dn);
1683         }
1684
1685         if (!GUID_all_zero(&id3.guid)) {
1686                 status = GUID_to_ndr_blob(&id3.guid, tmp_ctx, &guid_blob);
1687                 if (!NT_STATUS_IS_OK(status)) {
1688                         talloc_free(tmp_ctx);
1689                         return ntstatus_to_werror(status);
1690                 }
1691
1692                 ret = ldb_dn_set_extended_component(dn, "GUID", &guid_blob);
1693                 if (ret != LDB_SUCCESS) {
1694                         talloc_free(tmp_ctx);
1695                         return WERR_FOOBAR;
1696                 }
1697                 talloc_free(guid_blob.data);
1698         }
1699
1700         if (id3.__ndr_size_sid) {
1701                 DATA_BLOB sid_blob;
1702                 ndr_err = ndr_push_struct_blob(&sid_blob, tmp_ctx, &id3.sid,
1703                                                (ndr_push_flags_fn_t)ndr_push_dom_sid);
1704                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1705                         status = ndr_map_error2ntstatus(ndr_err);
1706                         talloc_free(tmp_ctx);
1707                         return ntstatus_to_werror(status);
1708                 }
1709
1710                 ret = ldb_dn_set_extended_component(dn, "SID", &sid_blob);
1711                 if (ret != LDB_SUCCESS) {
1712                         talloc_free(tmp_ctx);
1713                         return WERR_FOOBAR;
1714                 }
1715         }
1716
1717         *out = data_blob_string_const(ldb_dn_get_extended_linearized(mem_ctx, dn, 1));
1718         talloc_free(tmp_ctx);
1719         return WERR_OK;
1720 }
1721
1722 static WERROR dsdb_syntax_DN_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
1723                                             const struct dsdb_attribute *attr,
1724                                             const struct drsuapi_DsReplicaAttribute *in,
1725                                             TALLOC_CTX *mem_ctx,
1726                                             struct ldb_message_element *out)
1727 {
1728         unsigned int i;
1729
1730         out->flags      = 0;
1731         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
1732         W_ERROR_HAVE_NO_MEMORY(out->name);
1733
1734         out->num_values = in->value_ctr.num_values;
1735         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
1736         W_ERROR_HAVE_NO_MEMORY(out->values);
1737
1738         for (i=0; i < out->num_values; i++) {
1739                 WERROR status = dsdb_syntax_one_DN_drsuapi_to_ldb(out->values, ctx->ldb, attr->syntax,
1740                                                                   in->value_ctr.values[i].blob,
1741                                                                   &out->values[i]);
1742                 if (!W_ERROR_IS_OK(status)) {
1743                         return status;
1744                 }
1745
1746         }
1747
1748         return WERR_OK;
1749 }
1750
1751 static WERROR dsdb_syntax_DN_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
1752                                             const struct dsdb_attribute *attr,
1753                                             const struct ldb_message_element *in,
1754                                             TALLOC_CTX *mem_ctx,
1755                                             struct drsuapi_DsReplicaAttribute *out)
1756 {
1757         unsigned int i;
1758         DATA_BLOB *blobs;
1759
1760         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
1761                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
1762         }
1763
1764         out->attid                      = dsdb_attribute_get_attid(attr,
1765                                                                    ctx->is_schema_nc);
1766         out->value_ctr.num_values       = in->num_values;
1767         out->value_ctr.values           = talloc_array(mem_ctx,
1768                                                        struct drsuapi_DsAttributeValue,
1769                                                        in->num_values);
1770         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
1771
1772         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
1773         W_ERROR_HAVE_NO_MEMORY(blobs);
1774
1775         for (i=0; i < in->num_values; i++) {
1776                 struct drsuapi_DsReplicaObjectIdentifier3 id3;
1777                 enum ndr_err_code ndr_err;
1778                 struct ldb_dn *dn;
1779                 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1780                 NTSTATUS status;
1781
1782                 W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
1783
1784                 out->value_ctr.values[i].blob   = &blobs[i];
1785
1786                 dn = ldb_dn_from_ldb_val(tmp_ctx, ctx->ldb, &in->values[i]);
1787
1788                 W_ERROR_HAVE_NO_MEMORY(dn);
1789
1790                 ZERO_STRUCT(id3);
1791
1792                 status = dsdb_get_extended_dn_guid(dn, &id3.guid, "GUID");
1793                 if (!NT_STATUS_IS_OK(status) &&
1794                     !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1795                         talloc_free(tmp_ctx);
1796                         return ntstatus_to_werror(status);
1797                 }
1798
1799                 status = dsdb_get_extended_dn_sid(dn, &id3.sid, "SID");
1800                 if (!NT_STATUS_IS_OK(status) &&
1801                     !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1802                         talloc_free(tmp_ctx);
1803                         return ntstatus_to_werror(status);
1804                 }
1805
1806                 id3.dn = ldb_dn_get_linearized(dn);
1807
1808                 ndr_err = ndr_push_struct_blob(&blobs[i], blobs, &id3, (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1809                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1810                         status = ndr_map_error2ntstatus(ndr_err);
1811                         talloc_free(tmp_ctx);
1812                         return ntstatus_to_werror(status);
1813                 }
1814                 talloc_free(tmp_ctx);
1815         }
1816
1817         return WERR_OK;
1818 }
1819
1820 static WERROR dsdb_syntax_DN_validate_one_val(const struct dsdb_syntax_ctx *ctx,
1821                                               const struct dsdb_attribute *attr,
1822                                               const struct ldb_val *val,
1823                                               TALLOC_CTX *mem_ctx,
1824                                               struct dsdb_dn **_dsdb_dn)
1825 {
1826         static const char * const extended_list[] = { "GUID", "SID", NULL };
1827         enum ndr_err_code ndr_err;
1828         struct GUID guid;
1829         struct dom_sid sid;
1830         const DATA_BLOB *sid_blob;
1831         struct dsdb_dn *dsdb_dn;
1832         struct ldb_dn *dn;
1833         char *dn_str;
1834         struct ldb_dn *dn2;
1835         char *dn2_str;
1836         int num_components;
1837         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1838         NTSTATUS status;
1839
1840         W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
1841
1842         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
1843                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
1844         }
1845
1846         dsdb_dn = dsdb_dn_parse(tmp_ctx, ctx->ldb, val,
1847                                 attr->syntax->ldap_oid);
1848         if (!dsdb_dn) {
1849                 talloc_free(tmp_ctx);
1850                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1851         }
1852         dn = dsdb_dn->dn;
1853
1854         dn2 = ldb_dn_copy(tmp_ctx, dn);
1855         if (dn == NULL) {
1856                 talloc_free(tmp_ctx);
1857                 return WERR_NOMEM;
1858         }
1859
1860         num_components = ldb_dn_get_comp_num(dn);
1861
1862         status = dsdb_get_extended_dn_guid(dn, &guid, "GUID");
1863         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1864                 num_components++;
1865         } else if (!NT_STATUS_IS_OK(status)) {
1866                 talloc_free(tmp_ctx);
1867                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1868         }
1869
1870         sid_blob = ldb_dn_get_extended_component(dn, "SID");
1871         if (sid_blob) {
1872                 num_components++;
1873                 ndr_err = ndr_pull_struct_blob_all(sid_blob,
1874                                                    tmp_ctx,
1875                                                    &sid,
1876                                                    (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
1877                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1878                         talloc_free(tmp_ctx);
1879                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1880                 }
1881         }
1882
1883         /* Do not allow links to the RootDSE */
1884         if (num_components == 0) {
1885                 talloc_free(tmp_ctx);
1886                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1887         }
1888
1889         /*
1890          * We need to check that only "GUID" and "SID" are
1891          * specified as extended components, we do that
1892          * by comparing the dn's after removing all components
1893          * from one dn and only the allowed subset from the other
1894          * one.
1895          */
1896         ldb_dn_extended_filter(dn, extended_list);
1897
1898         dn_str = ldb_dn_get_extended_linearized(tmp_ctx, dn, 0);
1899         if (dn_str == NULL) {
1900                 talloc_free(tmp_ctx);
1901                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1902         }
1903         dn2_str = ldb_dn_get_extended_linearized(tmp_ctx, dn2, 0);
1904         if (dn2_str == NULL) {
1905                 talloc_free(tmp_ctx);
1906                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1907         }
1908
1909         if (strcmp(dn_str, dn2_str) != 0) {
1910                 talloc_free(tmp_ctx);
1911                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1912         }
1913
1914         *_dsdb_dn = talloc_move(mem_ctx, &dsdb_dn);
1915         talloc_free(tmp_ctx);
1916         return WERR_OK;
1917 }
1918
1919 static WERROR dsdb_syntax_DN_validate_ldb(const struct dsdb_syntax_ctx *ctx,
1920                                           const struct dsdb_attribute *attr,
1921                                           const struct ldb_message_element *in)
1922 {
1923         unsigned int i;
1924
1925         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
1926                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
1927         }
1928
1929         for (i=0; i < in->num_values; i++) {
1930                 WERROR status;
1931                 struct dsdb_dn *dsdb_dn;
1932                 TALLOC_CTX *tmp_ctx = talloc_new(ctx->ldb);
1933                 W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
1934
1935                 status = dsdb_syntax_DN_validate_one_val(ctx,
1936                                                          attr,
1937                                                          &in->values[i],
1938                                                          tmp_ctx, &dsdb_dn);
1939                 if (!W_ERROR_IS_OK(status)) {
1940                         talloc_free(tmp_ctx);
1941                         return status;
1942                 }
1943
1944                 if (dsdb_dn->dn_format != DSDB_NORMAL_DN) {
1945                         talloc_free(tmp_ctx);
1946                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1947                 }
1948
1949                 talloc_free(tmp_ctx);
1950         }
1951
1952         return WERR_OK;
1953 }
1954
1955 static WERROR dsdb_syntax_DN_BINARY_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
1956                                                    const struct dsdb_attribute *attr,
1957                                                    const struct drsuapi_DsReplicaAttribute *in,
1958                                                    TALLOC_CTX *mem_ctx,
1959                                                    struct ldb_message_element *out)
1960 {
1961         unsigned int i;
1962         int ret;
1963
1964         out->flags      = 0;
1965         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
1966         W_ERROR_HAVE_NO_MEMORY(out->name);
1967
1968         out->num_values = in->value_ctr.num_values;
1969         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
1970         W_ERROR_HAVE_NO_MEMORY(out->values);
1971
1972         for (i=0; i < out->num_values; i++) {
1973                 struct drsuapi_DsReplicaObjectIdentifier3Binary id3;
1974                 enum ndr_err_code ndr_err;
1975                 DATA_BLOB guid_blob;
1976                 struct ldb_dn *dn;
1977                 struct dsdb_dn *dsdb_dn;
1978                 NTSTATUS status;
1979                 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1980                 if (!tmp_ctx) {
1981                         W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
1982                 }
1983
1984                 if (in->value_ctr.values[i].blob == NULL) {
1985                         talloc_free(tmp_ctx);
1986                         return WERR_FOOBAR;
1987                 }
1988
1989                 if (in->value_ctr.values[i].blob->length == 0) {
1990                         talloc_free(tmp_ctx);
1991                         return WERR_FOOBAR;
1992                 }
1993
1994
1995                 /* windows sometimes sends an extra two pad bytes here */
1996                 ndr_err = ndr_pull_struct_blob(in->value_ctr.values[i].blob,
1997                                                tmp_ctx, &id3,
1998                                                (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3Binary);
1999                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2000                         status = ndr_map_error2ntstatus(ndr_err);
2001                         talloc_free(tmp_ctx);
2002                         return ntstatus_to_werror(status);
2003                 }
2004
2005                 dn = ldb_dn_new(tmp_ctx, ctx->ldb, id3.dn);
2006                 if (!dn) {
2007                         talloc_free(tmp_ctx);
2008                         /* If this fails, it must be out of memory, as it does not do much parsing */
2009                         W_ERROR_HAVE_NO_MEMORY(dn);
2010                 }
2011
2012                 if (!GUID_all_zero(&id3.guid)) {
2013                         status = GUID_to_ndr_blob(&id3.guid, tmp_ctx, &guid_blob);
2014                         if (!NT_STATUS_IS_OK(status)) {
2015                                 talloc_free(tmp_ctx);
2016                                 return ntstatus_to_werror(status);
2017                         }
2018
2019                         ret = ldb_dn_set_extended_component(dn, "GUID", &guid_blob);
2020                         if (ret != LDB_SUCCESS) {
2021                                 talloc_free(tmp_ctx);
2022                                 return WERR_FOOBAR;
2023                         }
2024                         talloc_free(guid_blob.data);
2025                 }
2026
2027                 if (id3.__ndr_size_sid) {
2028                         DATA_BLOB sid_blob;
2029                         ndr_err = ndr_push_struct_blob(&sid_blob, tmp_ctx, &id3.sid,
2030                                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
2031                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2032                                 status = ndr_map_error2ntstatus(ndr_err);
2033                                 talloc_free(tmp_ctx);
2034                                 return ntstatus_to_werror(status);
2035                         }
2036
2037                         ret = ldb_dn_set_extended_component(dn, "SID", &sid_blob);
2038                         if (ret != LDB_SUCCESS) {
2039                                 talloc_free(tmp_ctx);
2040                                 return WERR_FOOBAR;
2041                         }
2042                 }
2043
2044                 /* set binary stuff */
2045                 dsdb_dn = dsdb_dn_construct(tmp_ctx, dn, id3.binary, attr->syntax->ldap_oid);
2046                 if (!dsdb_dn) {
2047                         /* If this fails, it must be out of memory, we know the ldap_oid is valid */
2048                         talloc_free(tmp_ctx);
2049                         W_ERROR_HAVE_NO_MEMORY(dsdb_dn);
2050                 }
2051                 out->values[i] = data_blob_string_const(dsdb_dn_get_extended_linearized(out->values, dsdb_dn, 1));
2052                 talloc_free(tmp_ctx);
2053         }
2054
2055         return WERR_OK;
2056 }
2057
2058 static WERROR dsdb_syntax_DN_BINARY_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
2059                                                    const struct dsdb_attribute *attr,
2060                                                    const struct ldb_message_element *in,
2061                                                    TALLOC_CTX *mem_ctx,
2062                                                    struct drsuapi_DsReplicaAttribute *out)
2063 {
2064         unsigned int i;
2065         DATA_BLOB *blobs;
2066
2067         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
2068                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
2069         }
2070
2071         out->attid                      = dsdb_attribute_get_attid(attr,
2072                                                                    ctx->is_schema_nc);
2073         out->value_ctr.num_values       = in->num_values;
2074         out->value_ctr.values           = talloc_array(mem_ctx,
2075                                                        struct drsuapi_DsAttributeValue,
2076                                                        in->num_values);
2077         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
2078
2079         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
2080         W_ERROR_HAVE_NO_MEMORY(blobs);
2081
2082         for (i=0; i < in->num_values; i++) {
2083                 struct drsuapi_DsReplicaObjectIdentifier3Binary id3;
2084                 enum ndr_err_code ndr_err;
2085                 const DATA_BLOB *sid_blob;
2086                 struct dsdb_dn *dsdb_dn;
2087                 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2088                 NTSTATUS status;
2089
2090                 W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
2091
2092                 out->value_ctr.values[i].blob   = &blobs[i];
2093
2094                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ctx->ldb, &in->values[i], attr->syntax->ldap_oid);
2095
2096                 if (!dsdb_dn) {
2097                         talloc_free(tmp_ctx);
2098                         return ntstatus_to_werror(NT_STATUS_INVALID_PARAMETER);
2099                 }
2100
2101                 ZERO_STRUCT(id3);
2102
2103                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &id3.guid, "GUID");
2104                 if (!NT_STATUS_IS_OK(status) &&
2105                     !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2106                         talloc_free(tmp_ctx);
2107                         return ntstatus_to_werror(status);
2108                 }
2109
2110                 sid_blob = ldb_dn_get_extended_component(dsdb_dn->dn, "SID");
2111                 if (sid_blob) {
2112
2113                         ndr_err = ndr_pull_struct_blob_all(sid_blob,
2114                                                            tmp_ctx, &id3.sid,
2115                                                            (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
2116                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2117                                 status = ndr_map_error2ntstatus(ndr_err);
2118                                 talloc_free(tmp_ctx);
2119                                 return ntstatus_to_werror(status);
2120                         }
2121                 }
2122
2123                 id3.dn = ldb_dn_get_linearized(dsdb_dn->dn);
2124
2125                 /* get binary stuff */
2126                 id3.binary = dsdb_dn->extra_part;
2127
2128                 ndr_err = ndr_push_struct_blob(&blobs[i], blobs, &id3, (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3Binary);
2129                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2130                         status = ndr_map_error2ntstatus(ndr_err);
2131                         talloc_free(tmp_ctx);
2132                         return ntstatus_to_werror(status);
2133                 }
2134                 talloc_free(tmp_ctx);
2135         }
2136
2137         return WERR_OK;
2138 }
2139
2140 static WERROR dsdb_syntax_DN_BINARY_validate_ldb(const struct dsdb_syntax_ctx *ctx,
2141                                                  const struct dsdb_attribute *attr,
2142                                                  const struct ldb_message_element *in)
2143 {
2144         unsigned int i;
2145
2146         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
2147                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
2148         }
2149
2150         for (i=0; i < in->num_values; i++) {
2151                 WERROR status;
2152                 struct dsdb_dn *dsdb_dn;
2153                 TALLOC_CTX *tmp_ctx = talloc_new(ctx->ldb);
2154                 W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
2155
2156                 status = dsdb_syntax_DN_validate_one_val(ctx,
2157                                                          attr,
2158                                                          &in->values[i],
2159                                                          tmp_ctx, &dsdb_dn);
2160                 if (!W_ERROR_IS_OK(status)) {
2161                         talloc_free(tmp_ctx);
2162                         return status;
2163                 }
2164
2165                 if (dsdb_dn->dn_format != DSDB_BINARY_DN) {
2166                         talloc_free(tmp_ctx);
2167                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
2168                 }
2169
2170                 status = dsdb_syntax_DATA_BLOB_validate_one_val(ctx,
2171                                                                 attr,
2172                                                                 &dsdb_dn->extra_part);
2173                 if (!W_ERROR_IS_OK(status)) {
2174                         talloc_free(tmp_ctx);
2175                         return status;
2176                 }
2177
2178                 talloc_free(tmp_ctx);
2179         }
2180
2181         return WERR_OK;
2182 }
2183
2184 static WERROR dsdb_syntax_DN_STRING_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
2185                                                    const struct dsdb_attribute *attr,
2186                                                    const struct drsuapi_DsReplicaAttribute *in,
2187                                                    TALLOC_CTX *mem_ctx,
2188                                                    struct ldb_message_element *out)
2189 {
2190         return dsdb_syntax_DN_BINARY_drsuapi_to_ldb(ctx,
2191                                                     attr,
2192                                                     in,
2193                                                     mem_ctx,
2194                                                     out);
2195 }
2196
2197 static WERROR dsdb_syntax_DN_STRING_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
2198                                                    const struct dsdb_attribute *attr,
2199                                                    const struct ldb_message_element *in,
2200                                                    TALLOC_CTX *mem_ctx,
2201                                                    struct drsuapi_DsReplicaAttribute *out)
2202 {
2203         return dsdb_syntax_DN_BINARY_ldb_to_drsuapi(ctx,
2204                                                     attr,
2205                                                     in,
2206                                                     mem_ctx,
2207                                                     out);
2208 }
2209
2210 static WERROR dsdb_syntax_DN_STRING_validate_ldb(const struct dsdb_syntax_ctx *ctx,
2211                                                  const struct dsdb_attribute *attr,
2212                                                  const struct ldb_message_element *in)
2213 {
2214         unsigned int i;
2215
2216         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
2217                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
2218         }
2219
2220         for (i=0; i < in->num_values; i++) {
2221                 WERROR status;
2222                 struct dsdb_dn *dsdb_dn;
2223                 TALLOC_CTX *tmp_ctx = talloc_new(ctx->ldb);
2224                 W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
2225
2226                 status = dsdb_syntax_DN_validate_one_val(ctx,
2227                                                          attr,
2228                                                          &in->values[i],
2229                                                          tmp_ctx, &dsdb_dn);
2230                 if (!W_ERROR_IS_OK(status)) {
2231                         talloc_free(tmp_ctx);
2232                         return status;
2233                 }
2234
2235                 if (dsdb_dn->dn_format != DSDB_STRING_DN) {
2236                         talloc_free(tmp_ctx);
2237                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
2238                 }
2239
2240                 status = dsdb_syntax_UNICODE_validate_one_val(ctx,
2241                                                               attr,
2242                                                               &dsdb_dn->extra_part);
2243                 if (!W_ERROR_IS_OK(status)) {
2244                         talloc_free(tmp_ctx);
2245                         return status;
2246                 }
2247
2248                 talloc_free(tmp_ctx);
2249         }
2250
2251         return WERR_OK;
2252 }
2253
2254 static WERROR dsdb_syntax_PRESENTATION_ADDRESS_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
2255                                                               const struct dsdb_attribute *attr,
2256                                                               const struct drsuapi_DsReplicaAttribute *in,
2257                                                               TALLOC_CTX *mem_ctx,
2258                                                               struct ldb_message_element *out)
2259 {
2260         unsigned int i;
2261
2262         out->flags      = 0;
2263         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
2264         W_ERROR_HAVE_NO_MEMORY(out->name);
2265
2266         out->num_values = in->value_ctr.num_values;
2267         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
2268         W_ERROR_HAVE_NO_MEMORY(out->values);
2269
2270         for (i=0; i < out->num_values; i++) {
2271                 size_t len;
2272                 size_t converted_size = 0;
2273                 char *str;
2274
2275                 if (in->value_ctr.values[i].blob == NULL) {
2276                         return WERR_FOOBAR;
2277                 }
2278
2279                 if (in->value_ctr.values[i].blob->length < 4) {
2280                         return WERR_FOOBAR;
2281                 }
2282
2283                 len = IVAL(in->value_ctr.values[i].blob->data, 0);
2284
2285                 if (len != in->value_ctr.values[i].blob->length) {
2286                         return WERR_FOOBAR;
2287                 }
2288
2289                 if (!convert_string_talloc(out->values, CH_UTF16, CH_UNIX,
2290                                            in->value_ctr.values[i].blob->data+4,
2291                                            in->value_ctr.values[i].blob->length-4,
2292                                            (void **)&str, &converted_size)) {
2293                         return WERR_FOOBAR;
2294                 }
2295
2296                 out->values[i] = data_blob_string_const(str);
2297         }
2298
2299         return WERR_OK;
2300 }
2301
2302 static WERROR dsdb_syntax_PRESENTATION_ADDRESS_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
2303                                                               const struct dsdb_attribute *attr,
2304                                                               const struct ldb_message_element *in,
2305                                                               TALLOC_CTX *mem_ctx,
2306                                                               struct drsuapi_DsReplicaAttribute *out)
2307 {
2308         unsigned int i;
2309         DATA_BLOB *blobs;
2310
2311         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
2312                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
2313         }
2314
2315         out->attid                      = dsdb_attribute_get_attid(attr,
2316                                                                    ctx->is_schema_nc);
2317         out->value_ctr.num_values       = in->num_values;
2318         out->value_ctr.values           = talloc_array(mem_ctx,
2319                                                        struct drsuapi_DsAttributeValue,
2320                                                        in->num_values);
2321         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
2322
2323         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
2324         W_ERROR_HAVE_NO_MEMORY(blobs);
2325
2326         for (i=0; i < in->num_values; i++) {
2327                 uint8_t *data;
2328                 size_t ret;
2329
2330                 out->value_ctr.values[i].blob   = &blobs[i];
2331
2332                 if (!convert_string_talloc(blobs, CH_UNIX, CH_UTF16,
2333                                            in->values[i].data,
2334                                            in->values[i].length,
2335                                            (void **)&data, &ret)) {
2336                         return WERR_FOOBAR;
2337                 }
2338
2339                 blobs[i] = data_blob_talloc(blobs, NULL, 4 + ret);
2340                 W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
2341
2342                 SIVAL(blobs[i].data, 0, 4 + ret);
2343
2344                 if (ret > 0) {
2345                         memcpy(blobs[i].data + 4, data, ret);
2346                         talloc_free(data);
2347                 }
2348         }
2349
2350         return WERR_OK;
2351 }
2352
2353 static WERROR dsdb_syntax_PRESENTATION_ADDRESS_validate_ldb(const struct dsdb_syntax_ctx *ctx,
2354                                                             const struct dsdb_attribute *attr,
2355                                                             const struct ldb_message_element *in)
2356 {
2357         return dsdb_syntax_UNICODE_validate_ldb(ctx,
2358                                                 attr,
2359                                                 in);
2360 }
2361
2362 #define OMOBJECTCLASS(val) { .length = sizeof(val) - 1, .data = discard_const_p(uint8_t, val) }
2363
2364 static const struct dsdb_syntax dsdb_syntaxes[] = {
2365         {
2366                 .name                   = "Boolean",
2367                 .ldap_oid               = LDB_SYNTAX_BOOLEAN,
2368                 .oMSyntax               = 1,
2369                 .attributeSyntax_oid    = "2.5.5.8",
2370                 .drsuapi_to_ldb         = dsdb_syntax_BOOL_drsuapi_to_ldb,
2371                 .ldb_to_drsuapi         = dsdb_syntax_BOOL_ldb_to_drsuapi,
2372                 .validate_ldb           = dsdb_syntax_BOOL_validate_ldb,
2373                 .equality               = "booleanMatch",
2374                 .comment                = "Boolean",
2375                 .auto_normalise         = true
2376         },{
2377                 .name                   = "Integer",
2378                 .ldap_oid               = LDB_SYNTAX_INTEGER,
2379                 .oMSyntax               = 2,
2380                 .attributeSyntax_oid    = "2.5.5.9",
2381                 .drsuapi_to_ldb         = dsdb_syntax_INT32_drsuapi_to_ldb,
2382                 .ldb_to_drsuapi         = dsdb_syntax_INT32_ldb_to_drsuapi,
2383                 .validate_ldb           = dsdb_syntax_INT32_validate_ldb,
2384                 .equality               = "integerMatch",
2385                 .comment                = "Integer",
2386                 .ldb_syntax             = LDB_SYNTAX_SAMBA_INT32,
2387                 .auto_normalise         = true
2388         },{
2389                 .name                   = "String(Octet)",
2390                 .ldap_oid               = LDB_SYNTAX_OCTET_STRING,
2391                 .oMSyntax               = 4,
2392                 .attributeSyntax_oid    = "2.5.5.10",
2393                 .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
2394                 .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
2395                 .validate_ldb           = dsdb_syntax_DATA_BLOB_validate_ldb,
2396                 .equality               = "octetStringMatch",
2397                 .comment                = "Octet String",
2398                 .userParameters         = true
2399         },{
2400                 .name                   = "String(Sid)",
2401                 .ldap_oid               = LDB_SYNTAX_OCTET_STRING,
2402                 .oMSyntax               = 4,
2403                 .attributeSyntax_oid    = "2.5.5.17",
2404                 .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
2405                 .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
2406                 .validate_ldb           = dsdb_syntax_DATA_BLOB_validate_ldb,
2407                 .equality               = "octetStringMatch",
2408                 .comment                = "Octet String - Security Identifier (SID)",
2409                 .ldb_syntax             = LDB_SYNTAX_SAMBA_SID
2410         },{
2411                 .name                   = "String(Object-Identifier)",
2412                 .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.38",
2413                 .oMSyntax               = 6,
2414                 .attributeSyntax_oid    = "2.5.5.2",
2415                 .drsuapi_to_ldb         = dsdb_syntax_OID_drsuapi_to_ldb,
2416                 .ldb_to_drsuapi         = dsdb_syntax_OID_ldb_to_drsuapi,
2417                 .validate_ldb           = dsdb_syntax_OID_validate_ldb,
2418                 .equality               = "caseIgnoreMatch", /* Would use "objectIdentifierMatch" but most are ldap attribute/class names */
2419                 .comment                = "OID String",
2420                 .ldb_syntax             = LDB_SYNTAX_DIRECTORY_STRING
2421         },{
2422                 .name                   = "Enumeration",
2423                 .ldap_oid               = LDB_SYNTAX_INTEGER,
2424                 .oMSyntax               = 10,
2425                 .attributeSyntax_oid    = "2.5.5.9",
2426                 .drsuapi_to_ldb         = dsdb_syntax_INT32_drsuapi_to_ldb,
2427                 .ldb_to_drsuapi         = dsdb_syntax_INT32_ldb_to_drsuapi,
2428                 .validate_ldb           = dsdb_syntax_INT32_validate_ldb,
2429                 .ldb_syntax             = LDB_SYNTAX_SAMBA_INT32,
2430                 .auto_normalise         = true
2431         },{
2432         /* not used in w2k3 forest */
2433                 .name                   = "String(Numeric)",
2434                 .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.36",
2435                 .oMSyntax               = 18,
2436                 .attributeSyntax_oid    = "2.5.5.6",
2437                 .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
2438                 .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
2439                 .validate_ldb           = dsdb_syntax_DATA_BLOB_validate_ldb,
2440                 .equality               = "numericStringMatch",
2441                 .substring              = "numericStringSubstringsMatch",
2442                 .comment                = "Numeric String",
2443                 .ldb_syntax             = LDB_SYNTAX_DIRECTORY_STRING,
2444         },{
2445                 .name                   = "String(Printable)",
2446                 .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.44",
2447                 .oMSyntax               = 19,
2448                 .attributeSyntax_oid    = "2.5.5.5",
2449                 .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
2450                 .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
2451                 .validate_ldb           = dsdb_syntax_DATA_BLOB_validate_ldb,
2452                 .ldb_syntax             = LDB_SYNTAX_OCTET_STRING,
2453         },{
2454                 .name                   = "String(Teletex)",
2455                 .ldap_oid               = "1.2.840.113556.1.4.905",
2456                 .oMSyntax               = 20,
2457                 .attributeSyntax_oid    = "2.5.5.4",
2458                 .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
2459                 .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
2460                 .validate_ldb           = dsdb_syntax_DATA_BLOB_validate_ldb,
2461                 .equality               = "caseIgnoreMatch",
2462                 .substring              = "caseIgnoreSubstringsMatch",
2463                 .comment                = "Case Insensitive String",
2464                 .ldb_syntax             = LDB_SYNTAX_DIRECTORY_STRING,
2465         },{
2466                 .name                   = "String(IA5)",
2467                 .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.26",
2468                 .oMSyntax               = 22,
2469                 .attributeSyntax_oid    = "2.5.5.5",
2470                 .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
2471                 .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
2472                 .validate_ldb           = dsdb_syntax_DATA_BLOB_validate_ldb,
2473                 .equality               = "caseExactIA5Match",
2474                 .comment                = "Printable String",
2475                 .ldb_syntax             = LDB_SYNTAX_OCTET_STRING,
2476         },{
2477                 .name                   = "String(UTC-Time)",
2478                 .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.53",
2479                 .oMSyntax               = 23,
2480                 .attributeSyntax_oid    = "2.5.5.11",
2481                 .drsuapi_to_ldb         = dsdb_syntax_NTTIME_UTC_drsuapi_to_ldb,
2482                 .ldb_to_drsuapi         = dsdb_syntax_NTTIME_UTC_ldb_to_drsuapi,
2483                 .validate_ldb           = dsdb_syntax_NTTIME_UTC_validate_ldb,
2484                 .equality               = "generalizedTimeMatch",
2485                 .comment                = "UTC Time",
2486                 .auto_normalise         = true
2487         },{
2488                 .name                   = "String(Generalized-Time)",
2489                 .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.24",
2490                 .oMSyntax               = 24,
2491                 .attributeSyntax_oid    = "2.5.5.11",
2492                 .drsuapi_to_ldb         = dsdb_syntax_NTTIME_drsuapi_to_ldb,
2493                 .ldb_to_drsuapi         = dsdb_syntax_NTTIME_ldb_to_drsuapi,
2494                 .validate_ldb           = dsdb_syntax_NTTIME_validate_ldb,
2495                 .equality               = "generalizedTimeMatch",
2496                 .comment                = "Generalized Time",
2497                 .auto_normalise         = true
2498         },{
2499         /* not used in w2k3 schema */
2500                 .name                   = "String(Case Sensitive)",
2501                 .ldap_oid               = "1.2.840.113556.1.4.1362",
2502                 .oMSyntax               = 27,
2503                 .attributeSyntax_oid    = "2.5.5.3",
2504                 .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
2505                 .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
2506                 .validate_ldb           = dsdb_syntax_DATA_BLOB_validate_ldb,
2507                 .equality               = "caseExactMatch",
2508                 .substring              = "caseExactSubstringsMatch",
2509                 /* TODO (kim): according to LDAP rfc we should be using same comparison
2510                  * as Directory String (LDB_SYNTAX_DIRECTORY_STRING), but case sensitive.
2511                  * But according to ms docs binary compare should do the job:
2512                  * http://msdn.microsoft.com/en-us/library/cc223200(v=PROT.10).aspx */
2513                 .ldb_syntax             = LDB_SYNTAX_OCTET_STRING,
2514         },{
2515                 .name                   = "String(Unicode)",
2516                 .ldap_oid               = LDB_SYNTAX_DIRECTORY_STRING,
2517                 .oMSyntax               = 64,
2518                 .attributeSyntax_oid    = "2.5.5.12",
2519                 .drsuapi_to_ldb         = dsdb_syntax_UNICODE_drsuapi_to_ldb,
2520                 .ldb_to_drsuapi         = dsdb_syntax_UNICODE_ldb_to_drsuapi,
2521                 .validate_ldb           = dsdb_syntax_UNICODE_validate_ldb,
2522                 .equality               = "caseIgnoreMatch",
2523                 .substring              = "caseIgnoreSubstringsMatch",
2524                 .comment                = "Directory String",
2525         },{
2526                 .name                   = "Interval/LargeInteger",
2527                 .ldap_oid               = "1.2.840.113556.1.4.906",
2528                 .oMSyntax               = 65,
2529                 .attributeSyntax_oid    = "2.5.5.16",
2530                 .drsuapi_to_ldb         = dsdb_syntax_INT64_drsuapi_to_ldb,
2531                 .ldb_to_drsuapi         = dsdb_syntax_INT64_ldb_to_drsuapi,
2532                 .validate_ldb           = dsdb_syntax_INT64_validate_ldb,
2533                 .equality               = "integerMatch",
2534                 .comment                = "Large Integer",
2535                 .ldb_syntax             = LDB_SYNTAX_INTEGER,
2536                 .auto_normalise         = true
2537         },{
2538                 .name                   = "String(NT-Sec-Desc)",
2539                 .ldap_oid               = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
2540                 .oMSyntax               = 66,
2541                 .attributeSyntax_oid    = "2.5.5.15",
2542                 .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
2543                 .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
2544                 .validate_ldb           = dsdb_syntax_DATA_BLOB_validate_ldb,
2545         },{
2546                 .name                   = "Object(DS-DN)",
2547                 .ldap_oid               = LDB_SYNTAX_DN,
2548                 .oMSyntax               = 127,
2549                 .oMObjectClass          = OMOBJECTCLASS("\x2b\x0c\x02\x87\x73\x1c\x00\x85\x4a"),
2550                 .attributeSyntax_oid    = "2.5.5.1",
2551                 .drsuapi_to_ldb         = dsdb_syntax_DN_drsuapi_to_ldb,
2552                 .ldb_to_drsuapi         = dsdb_syntax_DN_ldb_to_drsuapi,
2553                 .validate_ldb           = dsdb_syntax_DN_validate_ldb,
2554                 .equality               = "distinguishedNameMatch",
2555                 .comment                = "Object(DS-DN) == a DN",
2556         },{
2557                 .name                   = "Object(DN-Binary)",
2558                 .ldap_oid               = DSDB_SYNTAX_BINARY_DN,
2559                 .oMSyntax               = 127,
2560                 .oMObjectClass          = OMOBJECTCLASS("\x2a\x86\x48\x86\xf7\x14\x01\x01\x01\x0b"),
2561                 .attributeSyntax_oid    = "2.5.5.7",
2562                 .drsuapi_to_ldb         = dsdb_syntax_DN_BINARY_drsuapi_to_ldb,
2563                 .ldb_to_drsuapi         = dsdb_syntax_DN_BINARY_ldb_to_drsuapi,
2564                 .validate_ldb           = dsdb_syntax_DN_BINARY_validate_ldb,
2565                 .equality               = "octetStringMatch",
2566                 .comment                = "OctetString: Binary+DN",
2567         },{
2568         /* not used in w2k3 schema, but used in Exchange schema*/
2569                 .name                   = "Object(OR-Name)",
2570                 .ldap_oid               = DSDB_SYNTAX_OR_NAME,
2571                 .oMSyntax               = 127,
2572                 .oMObjectClass          = OMOBJECTCLASS("\x56\x06\x01\x02\x05\x0b\x1D"),
2573                 .attributeSyntax_oid    = "2.5.5.7",
2574                 .drsuapi_to_ldb         = dsdb_syntax_DN_BINARY_drsuapi_to_ldb,
2575                 .ldb_to_drsuapi         = dsdb_syntax_DN_BINARY_ldb_to_drsuapi,
2576                 .validate_ldb           = dsdb_syntax_DN_BINARY_validate_ldb,
2577                 .equality               = "caseIgnoreMatch",
2578                 .ldb_syntax             = LDB_SYNTAX_DN,
2579         },{
2580         /*
2581          * TODO: verify if DATA_BLOB is correct here...!
2582          *
2583          *       repsFrom and repsTo are the only attributes using
2584          *       this attribute syntax, but they're not replicated...
2585          */
2586                 .name                   = "Object(Replica-Link)",
2587                 .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.40",
2588                 .oMSyntax               = 127,
2589                 .oMObjectClass          = OMOBJECTCLASS("\x2a\x86\x48\x86\xf7\x14\x01\x01\x01\x06"),
2590                 .attributeSyntax_oid    = "2.5.5.10",
2591                 .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
2592                 .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
2593                 .validate_ldb           = dsdb_syntax_DATA_BLOB_validate_ldb,
2594         },{
2595                 .name                   = "Object(Presentation-Address)",
2596                 .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.43",
2597                 .oMSyntax               = 127,
2598                 .oMObjectClass          = OMOBJECTCLASS("\x2b\x0c\x02\x87\x73\x1c\x00\x85\x5c"),
2599                 .attributeSyntax_oid    = "2.5.5.13",
2600                 .drsuapi_to_ldb         = dsdb_syntax_PRESENTATION_ADDRESS_drsuapi_to_ldb,
2601                 .ldb_to_drsuapi         = dsdb_syntax_PRESENTATION_ADDRESS_ldb_to_drsuapi,
2602                 .validate_ldb           = dsdb_syntax_PRESENTATION_ADDRESS_validate_ldb,
2603                 .comment                = "Presentation Address",
2604                 .ldb_syntax             = LDB_SYNTAX_DIRECTORY_STRING,
2605         },{
2606         /* not used in w2k3 schema */
2607                 .name                   = "Object(Access-Point)",
2608                 .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.2",
2609                 .oMSyntax               = 127,
2610                 .oMObjectClass          = OMOBJECTCLASS("\x2b\x0c\x02\x87\x73\x1c\x00\x85\x3e"),
2611                 .attributeSyntax_oid    = "2.5.5.14",
2612                 .drsuapi_to_ldb         = dsdb_syntax_FOOBAR_drsuapi_to_ldb,
2613                 .ldb_to_drsuapi         = dsdb_syntax_FOOBAR_ldb_to_drsuapi,
2614                 .validate_ldb           = dsdb_syntax_FOOBAR_validate_ldb,
2615                 .ldb_syntax             = LDB_SYNTAX_DIRECTORY_STRING,
2616         },{
2617         /* not used in w2k3 schema */
2618                 .name                   = "Object(DN-String)",
2619                 .ldap_oid               = DSDB_SYNTAX_STRING_DN,
2620                 .oMSyntax               = 127,
2621                 .oMObjectClass          = OMOBJECTCLASS("\x2a\x86\x48\x86\xf7\x14\x01\x01\x01\x0c"),
2622                 .attributeSyntax_oid    = "2.5.5.14",
2623                 .drsuapi_to_ldb         = dsdb_syntax_DN_STRING_drsuapi_to_ldb,
2624                 .ldb_to_drsuapi         = dsdb_syntax_DN_STRING_ldb_to_drsuapi,
2625                 .validate_ldb           = dsdb_syntax_DN_STRING_validate_ldb,
2626                 .equality               = "octetStringMatch",
2627                 .comment                = "OctetString: String+DN",
2628         }
2629 };
2630
2631 const struct dsdb_syntax *find_syntax_map_by_ad_oid(const char *ad_oid)
2632 {
2633         unsigned int i;
2634         for (i=0; dsdb_syntaxes[i].ldap_oid; i++) {
2635                 if (strcasecmp(ad_oid, dsdb_syntaxes[i].attributeSyntax_oid) == 0) {
2636                         return &dsdb_syntaxes[i];
2637                 }
2638         }
2639         return NULL;
2640 }
2641
2642 const struct dsdb_syntax *find_syntax_map_by_ad_syntax(int oMSyntax)
2643 {
2644         unsigned int i;
2645         for (i=0; dsdb_syntaxes[i].ldap_oid; i++) {
2646                 if (oMSyntax == dsdb_syntaxes[i].oMSyntax) {
2647                         return &dsdb_syntaxes[i];
2648                 }
2649         }
2650         return NULL;
2651 }
2652
2653 const struct dsdb_syntax *find_syntax_map_by_standard_oid(const char *standard_oid)
2654 {
2655         unsigned int i;
2656         for (i=0; dsdb_syntaxes[i].ldap_oid; i++) {
2657                 if (strcasecmp(standard_oid, dsdb_syntaxes[i].ldap_oid) == 0) {
2658                         return &dsdb_syntaxes[i];
2659                 }
2660         }
2661         return NULL;
2662 }
2663
2664 const struct dsdb_syntax *dsdb_syntax_for_attribute(const struct dsdb_attribute *attr)
2665 {
2666         unsigned int i;
2667
2668         for (i=0; i < ARRAY_SIZE(dsdb_syntaxes); i++) {
2669                 /*
2670                  * We must pretend that userParamters was declared
2671                  * binary string, so we can store the 'UTF16' (not
2672                  * really string) structure as given over SAMR to samba
2673                  */
2674                 if (dsdb_syntaxes[i].userParameters &&
2675                     (strcasecmp(attr->lDAPDisplayName, "userParameters") == 0))
2676                 {
2677                         return &dsdb_syntaxes[i];
2678                 }
2679                 if (attr->oMSyntax != dsdb_syntaxes[i].oMSyntax) continue;
2680
2681                 if (attr->oMObjectClass.length != dsdb_syntaxes[i].oMObjectClass.length) continue;
2682
2683                 if (attr->oMObjectClass.length) {
2684                         int ret;
2685                         ret = memcmp(attr->oMObjectClass.data,
2686                                      dsdb_syntaxes[i].oMObjectClass.data,
2687                                      attr->oMObjectClass.length);
2688                         if (ret != 0) continue;
2689                 }
2690
2691                 if (strcmp(attr->attributeSyntax_oid, dsdb_syntaxes[i].attributeSyntax_oid) != 0) continue;
2692
2693                 return &dsdb_syntaxes[i];
2694         }
2695
2696         return NULL;
2697 }
2698
2699 WERROR dsdb_attribute_drsuapi_to_ldb(struct ldb_context *ldb,
2700                                      const struct dsdb_schema *schema,
2701                                      const struct dsdb_schema_prefixmap *pfm_remote,
2702                                      const struct drsuapi_DsReplicaAttribute *in,
2703                                      TALLOC_CTX *mem_ctx,
2704                                      struct ldb_message_element *out)
2705 {
2706         const struct dsdb_attribute *sa;
2707         struct dsdb_syntax_ctx syntax_ctx;
2708         uint32_t attid_local;
2709
2710         /* use default syntax conversion context */
2711         dsdb_syntax_ctx_init(&syntax_ctx, ldb, schema);
2712         syntax_ctx.pfm_remote = pfm_remote;
2713
2714         switch (dsdb_pfm_get_attid_type(in->attid)) {
2715         case DSDB_ATTID_TYPE_PFM:
2716                 /* map remote ATTID to local ATTID */
2717                 if (!dsdb_syntax_attid_from_remote_attid(&syntax_ctx, mem_ctx, in->attid, &attid_local)) {
2718                         DEBUG(0,(__location__ ": Can't find local ATTID for 0x%08X\n",
2719                                  in->attid));
2720                         return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
2721                 }
2722                 break;
2723         case DSDB_ATTID_TYPE_INTID:
2724                 /* use IntId value directly */
2725                 attid_local = in->attid;
2726                 break;
2727         default:
2728                 /* we should never get here */
2729                 DEBUG(0,(__location__ ": Invalid ATTID type passed for conversion - 0x%08X\n",
2730                          in->attid));
2731                 return WERR_INVALID_PARAMETER;
2732         }
2733
2734         sa = dsdb_attribute_by_attributeID_id(schema, attid_local);
2735         if (!sa) {
2736                 DEBUG(1,(__location__ ": Unknown attributeID_id 0x%08X\n", in->attid));
2737                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
2738         }
2739
2740         return sa->syntax->drsuapi_to_ldb(&syntax_ctx, sa, in, mem_ctx, out);
2741 }
2742
2743 WERROR dsdb_attribute_ldb_to_drsuapi(struct ldb_context *ldb,
2744                                      const struct dsdb_schema *schema,
2745                                      const struct ldb_message_element *in,
2746                                      TALLOC_CTX *mem_ctx,
2747                                      struct drsuapi_DsReplicaAttribute *out)
2748 {
2749         const struct dsdb_attribute *sa;
2750         struct dsdb_syntax_ctx syntax_ctx;
2751
2752         sa = dsdb_attribute_by_lDAPDisplayName(schema, in->name);
2753         if (!sa) {
2754                 return WERR_DS_ATT_NOT_DEF_IN_SCHEMA;
2755         }
2756
2757         /* use default syntax conversion context */
2758         dsdb_syntax_ctx_init(&syntax_ctx, ldb, schema);
2759
2760         return sa->syntax->ldb_to_drsuapi(&syntax_ctx, sa, in, mem_ctx, out);
2761 }
2762