s3:utils change data_blob_dup_talloc() to take a DATA_BLOB by value
[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_FOOBAR;
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_FOOBAR;
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_FOOBAR;
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_FOOBAR;
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_FOOBAR;
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_FOOBAR;
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_FOOBAR;
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_FOOBAR;
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_FOOBAR;
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_FOOBAR;
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_FOOBAR;
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_FOOBAR;
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_FOOBAR;
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                         return WERR_FOOBAR;
1058                 }
1059
1060                 if (in->value_ctr.values[i].blob->length != 4) {
1061                         return WERR_FOOBAR;
1062                 }
1063
1064                 v = IVAL(in->value_ctr.values[i].blob->data, 0);
1065
1066                 /* convert remote ATTID to local ATTID */
1067                 if (!dsdb_syntax_attid_from_remote_attid(ctx, mem_ctx, v, &v)) {
1068                         DEBUG(1,(__location__ ": Failed to map remote ATTID to local ATTID!\n"));
1069                         return WERR_FOOBAR;
1070                 }
1071
1072                 a = dsdb_attribute_by_attributeID_id(ctx->schema, v);
1073                 if (!a) {
1074                         DEBUG(1,(__location__ ": Unknown attributeID_id 0x%08X\n", v));
1075                         return WERR_FOOBAR;
1076                 }
1077
1078                 str = talloc_strdup(out->values, a->lDAPDisplayName);
1079                 W_ERROR_HAVE_NO_MEMORY(str);
1080
1081                 /* the values need to be reversed */
1082                 out->values[out->num_values - (i + 1)] = data_blob_string_const(str);
1083         }
1084
1085         return WERR_OK;
1086 }
1087
1088 static WERROR _dsdb_syntax_OID_oid_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
1089                                                   const struct dsdb_attribute *attr,
1090                                                   const struct drsuapi_DsReplicaAttribute *in,
1091                                                   TALLOC_CTX *mem_ctx,
1092                                                   struct ldb_message_element *out)
1093 {
1094         unsigned int i;
1095         const struct dsdb_schema_prefixmap *prefixmap;
1096
1097         if (ctx->pfm_remote != NULL) {
1098                 prefixmap = ctx->pfm_remote;
1099         } else {
1100                 prefixmap = ctx->schema->prefixmap;
1101         }
1102         SMB_ASSERT(prefixmap);
1103
1104         out->flags      = 0;
1105         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
1106         W_ERROR_HAVE_NO_MEMORY(out->name);
1107
1108         out->num_values = in->value_ctr.num_values;
1109         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
1110         W_ERROR_HAVE_NO_MEMORY(out->values);
1111
1112         for (i=0; i < out->num_values; i++) {
1113                 uint32_t attid;
1114                 WERROR status;
1115                 const char *oid;
1116
1117                 if (in->value_ctr.values[i].blob == NULL) {
1118                         return WERR_FOOBAR;
1119                 }
1120
1121                 if (in->value_ctr.values[i].blob->length != 4) {
1122                         return WERR_FOOBAR;
1123                 }
1124
1125                 attid = IVAL(in->value_ctr.values[i].blob->data, 0);
1126
1127                 status = dsdb_schema_pfm_oid_from_attid(prefixmap, attid,
1128                                                         out->values, &oid);
1129                 if (!W_ERROR_IS_OK(status)) {
1130                         DEBUG(0,(__location__ ": Error: Unknown ATTID 0x%08X\n",
1131                                  attid));
1132                         return status;
1133                 }
1134
1135                 out->values[i] = data_blob_string_const(oid);
1136         }
1137
1138         return WERR_OK;
1139 }
1140
1141 static WERROR _dsdb_syntax_auto_OID_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
1142                                                    const struct dsdb_attribute *attr,
1143                                                    const struct ldb_message_element *in,
1144                                                    TALLOC_CTX *mem_ctx,
1145                                                    struct drsuapi_DsReplicaAttribute *out)
1146 {
1147         unsigned int i;
1148         DATA_BLOB *blobs;
1149
1150         out->attid= dsdb_attribute_get_attid(attr,
1151                                              ctx->is_schema_nc);
1152         out->value_ctr.num_values= in->num_values;
1153         out->value_ctr.values= talloc_array(mem_ctx,
1154                                             struct drsuapi_DsAttributeValue,
1155                                             in->num_values);
1156         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
1157
1158         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
1159         W_ERROR_HAVE_NO_MEMORY(blobs);
1160
1161         for (i=0; i < in->num_values; i++) {
1162                 const struct dsdb_class *obj_class;
1163                 const struct dsdb_attribute *obj_attr;
1164                 struct ldb_val *v;
1165
1166                 out->value_ctr.values[i].blob= &blobs[i];
1167
1168                 blobs[i] = data_blob_talloc(blobs, NULL, 4);
1169                 W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
1170
1171                 /* in DRS windows puts the classes in the opposite
1172                    order to the order used in ldap */
1173                 v = &in->values[(in->num_values-1)-i];
1174
1175                 if ((obj_class = dsdb_class_by_lDAPDisplayName_ldb_val(ctx->schema, v))) {
1176                         SIVAL(blobs[i].data, 0, obj_class->governsID_id);
1177                 } else if ((obj_attr = dsdb_attribute_by_lDAPDisplayName_ldb_val(ctx->schema, v))) {
1178                         SIVAL(blobs[i].data, 0, obj_attr->attributeID_id);
1179                 } else {
1180                         uint32_t attid;
1181                         WERROR werr;
1182                         werr = dsdb_schema_pfm_attid_from_oid(ctx->schema->prefixmap,
1183                                                               (const char *)v->data,
1184                                                               &attid);
1185                         W_ERROR_NOT_OK_RETURN(werr);
1186                         SIVAL(blobs[i].data, 0, attid);
1187                 }
1188
1189         }
1190
1191
1192         return WERR_OK;
1193 }
1194
1195 static WERROR _dsdb_syntax_OID_obj_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
1196                                                   const struct dsdb_attribute *attr,
1197                                                   const struct ldb_message_element *in,
1198                                                   TALLOC_CTX *mem_ctx,
1199                                                   struct drsuapi_DsReplicaAttribute *out)
1200 {
1201         unsigned int i;
1202         DATA_BLOB *blobs;
1203
1204         out->attid= dsdb_attribute_get_attid(attr,
1205                                              ctx->is_schema_nc);
1206         out->value_ctr.num_values= in->num_values;
1207         out->value_ctr.values= talloc_array(mem_ctx,
1208                                             struct drsuapi_DsAttributeValue,
1209                                             in->num_values);
1210         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
1211
1212         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
1213         W_ERROR_HAVE_NO_MEMORY(blobs);
1214
1215         for (i=0; i < in->num_values; i++) {
1216                 const struct dsdb_class *obj_class;
1217
1218                 out->value_ctr.values[i].blob= &blobs[i];
1219
1220                 blobs[i] = data_blob_talloc(blobs, NULL, 4);
1221                 W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
1222
1223                 /* in DRS windows puts the classes in the opposite
1224                    order to the order used in ldap */
1225                 obj_class = dsdb_class_by_lDAPDisplayName(ctx->schema,
1226                                                           (const char *)in->values[(in->num_values-1)-i].data);
1227                 if (!obj_class) {
1228                         return WERR_FOOBAR;
1229                 }
1230                 SIVAL(blobs[i].data, 0, obj_class->governsID_id);
1231         }
1232
1233
1234         return WERR_OK;
1235 }
1236
1237 static WERROR _dsdb_syntax_OID_attr_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
1238                                                    const struct dsdb_attribute *attr,
1239                                                    const struct ldb_message_element *in,
1240                                                    TALLOC_CTX *mem_ctx,
1241                                                    struct drsuapi_DsReplicaAttribute *out)
1242 {
1243         unsigned int i;
1244         DATA_BLOB *blobs;
1245
1246         out->attid= dsdb_attribute_get_attid(attr,
1247                                              ctx->is_schema_nc);
1248         out->value_ctr.num_values= in->num_values;
1249         out->value_ctr.values= talloc_array(mem_ctx,
1250                                             struct drsuapi_DsAttributeValue,
1251                                             in->num_values);
1252         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
1253
1254         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
1255         W_ERROR_HAVE_NO_MEMORY(blobs);
1256
1257         for (i=0; i < in->num_values; i++) {
1258                 const struct dsdb_attribute *obj_attr;
1259
1260                 out->value_ctr.values[i].blob= &blobs[i];
1261
1262                 blobs[i] = data_blob_talloc(blobs, NULL, 4);
1263                 W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
1264
1265                 obj_attr = dsdb_attribute_by_lDAPDisplayName(ctx->schema, (const char *)in->values[i].data);
1266                 if (!obj_attr) {
1267                         return WERR_FOOBAR;
1268                 }
1269                 SIVAL(blobs[i].data, 0, obj_attr->attributeID_id);
1270         }
1271
1272
1273         return WERR_OK;
1274 }
1275
1276 static WERROR _dsdb_syntax_OID_oid_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
1277                                                   const struct dsdb_attribute *attr,
1278                                                   const struct ldb_message_element *in,
1279                                                   TALLOC_CTX *mem_ctx,
1280                                                   struct drsuapi_DsReplicaAttribute *out)
1281 {
1282         unsigned int i;
1283         DATA_BLOB *blobs;
1284
1285         out->attid= dsdb_attribute_get_attid(attr,
1286                                              ctx->is_schema_nc);
1287         out->value_ctr.num_values= in->num_values;
1288         out->value_ctr.values= talloc_array(mem_ctx,
1289                                             struct drsuapi_DsAttributeValue,
1290                                             in->num_values);
1291         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
1292
1293         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
1294         W_ERROR_HAVE_NO_MEMORY(blobs);
1295
1296         for (i=0; i < in->num_values; i++) {
1297                 uint32_t attid;
1298                 WERROR status;
1299
1300                 out->value_ctr.values[i].blob= &blobs[i];
1301
1302                 blobs[i] = data_blob_talloc(blobs, NULL, 4);
1303                 W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
1304
1305                 status = dsdb_schema_pfm_attid_from_oid(ctx->schema->prefixmap,
1306                                                         (const char *)in->values[i].data,
1307                                                         &attid);
1308                 W_ERROR_NOT_OK_RETURN(status);
1309
1310                 SIVAL(blobs[i].data, 0, attid);
1311         }
1312
1313         return WERR_OK;
1314 }
1315
1316 static WERROR dsdb_syntax_OID_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
1317                                              const struct dsdb_attribute *attr,
1318                                              const struct drsuapi_DsReplicaAttribute *in,
1319                                              TALLOC_CTX *mem_ctx,
1320                                              struct ldb_message_element *out)
1321 {
1322         WERROR werr;
1323
1324         switch (attr->attributeID_id) {
1325         case DRSUAPI_ATTID_objectClass:
1326         case DRSUAPI_ATTID_subClassOf:
1327         case DRSUAPI_ATTID_auxiliaryClass:
1328         case DRSUAPI_ATTID_systemAuxiliaryClass:
1329         case DRSUAPI_ATTID_systemPossSuperiors:
1330         case DRSUAPI_ATTID_possSuperiors:
1331                 werr = _dsdb_syntax_OID_obj_drsuapi_to_ldb(ctx, attr, in, mem_ctx, out);
1332                 break;
1333         case DRSUAPI_ATTID_systemMustContain:
1334         case DRSUAPI_ATTID_systemMayContain:
1335         case DRSUAPI_ATTID_mustContain:
1336         case DRSUAPI_ATTID_rDNAttId:
1337         case DRSUAPI_ATTID_transportAddressAttribute:
1338         case DRSUAPI_ATTID_mayContain:
1339                 werr = _dsdb_syntax_OID_attr_drsuapi_to_ldb(ctx, attr, in, mem_ctx, out);
1340                 break;
1341         case DRSUAPI_ATTID_governsID:
1342         case DRSUAPI_ATTID_attributeID:
1343         case DRSUAPI_ATTID_attributeSyntax:
1344                 werr = _dsdb_syntax_OID_oid_drsuapi_to_ldb(ctx, attr, in, mem_ctx, out);
1345                 break;
1346         default:
1347                 DEBUG(0,(__location__ ": Unknown handling for attributeID_id for %s\n",
1348                          attr->lDAPDisplayName));
1349                 return _dsdb_syntax_auto_OID_drsuapi_to_ldb(ctx, attr, in, mem_ctx, out);
1350         }
1351
1352         /* When we are doing the vampire of a schema, we don't want
1353          * the inability to reference an OID to get in the way.
1354          * Otherwise, we won't get the new schema with which to
1355          * understand this */
1356         if (!W_ERROR_IS_OK(werr) && ctx->schema->relax_OID_conversions) {
1357                 return _dsdb_syntax_OID_oid_drsuapi_to_ldb(ctx, attr, in, mem_ctx, out);
1358         }
1359         return werr;
1360 }
1361
1362 static WERROR dsdb_syntax_OID_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
1363                                              const struct dsdb_attribute *attr,
1364                                              const struct ldb_message_element *in,
1365                                              TALLOC_CTX *mem_ctx,
1366                                              struct drsuapi_DsReplicaAttribute *out)
1367 {
1368         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
1369                 return WERR_FOOBAR;
1370         }
1371
1372         switch (attr->attributeID_id) {
1373         case DRSUAPI_ATTID_objectClass:
1374         case DRSUAPI_ATTID_subClassOf:
1375         case DRSUAPI_ATTID_auxiliaryClass:
1376         case DRSUAPI_ATTID_systemAuxiliaryClass:
1377         case DRSUAPI_ATTID_systemPossSuperiors:
1378         case DRSUAPI_ATTID_possSuperiors:
1379                 return _dsdb_syntax_OID_obj_ldb_to_drsuapi(ctx, attr, in, mem_ctx, out);
1380         case DRSUAPI_ATTID_systemMustContain:
1381         case DRSUAPI_ATTID_systemMayContain:
1382         case DRSUAPI_ATTID_mustContain:
1383         case DRSUAPI_ATTID_rDNAttId:
1384         case DRSUAPI_ATTID_transportAddressAttribute:
1385         case DRSUAPI_ATTID_mayContain:
1386                 return _dsdb_syntax_OID_attr_ldb_to_drsuapi(ctx, attr, in, mem_ctx, out);
1387         case DRSUAPI_ATTID_governsID:
1388         case DRSUAPI_ATTID_attributeID:
1389         case DRSUAPI_ATTID_attributeSyntax:
1390                 return _dsdb_syntax_OID_oid_ldb_to_drsuapi(ctx, attr, in, mem_ctx, out);
1391         }
1392
1393         DEBUG(0,(__location__ ": Unknown handling for attributeID_id for %s\n",
1394                  attr->lDAPDisplayName));
1395
1396         return _dsdb_syntax_auto_OID_ldb_to_drsuapi(ctx, attr, in, mem_ctx, out);
1397 }
1398
1399 static WERROR _dsdb_syntax_OID_validate_numericoid(const struct dsdb_syntax_ctx *ctx,
1400                                                    const struct dsdb_attribute *attr,
1401                                                    const struct ldb_message_element *in)
1402 {
1403         unsigned int i;
1404         TALLOC_CTX *tmp_ctx;
1405
1406         tmp_ctx = talloc_new(ctx->ldb);
1407         W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
1408
1409         for (i=0; i < in->num_values; i++) {
1410                 DATA_BLOB blob;
1411                 char *oid_out;
1412                 const char *oid = (const char*)in->values[i].data;
1413
1414                 if (in->values[i].length == 0) {
1415                         talloc_free(tmp_ctx);
1416                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1417                 }
1418
1419                 if (!ber_write_OID_String(tmp_ctx, &blob, oid)) {
1420                         DEBUG(0,("ber_write_OID_String() failed for %s\n", oid));
1421                         talloc_free(tmp_ctx);
1422                         return WERR_INVALID_PARAMETER;
1423                 }
1424
1425                 if (!ber_read_OID_String(tmp_ctx, blob, &oid_out)) {
1426                         DEBUG(0,("ber_read_OID_String() failed for %s\n",
1427                                  hex_encode_talloc(tmp_ctx, blob.data, blob.length)));
1428                         talloc_free(tmp_ctx);
1429                         return WERR_INVALID_PARAMETER;
1430                 }
1431
1432                 if (strcmp(oid, oid_out) != 0) {
1433                         talloc_free(tmp_ctx);
1434                         return WERR_INVALID_PARAMETER;
1435                 }
1436         }
1437
1438         talloc_free(tmp_ctx);
1439         return WERR_OK;
1440 }
1441
1442 static WERROR dsdb_syntax_OID_validate_ldb(const struct dsdb_syntax_ctx *ctx,
1443                                            const struct dsdb_attribute *attr,
1444                                            const struct ldb_message_element *in)
1445 {
1446         WERROR status;
1447         struct drsuapi_DsReplicaAttribute drs_tmp;
1448         struct ldb_message_element ldb_tmp;
1449         TALLOC_CTX *tmp_ctx;
1450
1451         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
1452                 return WERR_FOOBAR;
1453         }
1454
1455         switch (attr->attributeID_id) {
1456         case DRSUAPI_ATTID_governsID:
1457         case DRSUAPI_ATTID_attributeID:
1458         case DRSUAPI_ATTID_attributeSyntax:
1459                 return _dsdb_syntax_OID_validate_numericoid(ctx, attr, in);
1460         }
1461
1462         /*
1463          * TODO: optimize and verify this code
1464          */
1465
1466         tmp_ctx = talloc_new(ctx->ldb);
1467         W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
1468
1469         status = dsdb_syntax_OID_ldb_to_drsuapi(ctx,
1470                                                 attr,
1471                                                 in,
1472                                                 tmp_ctx,
1473                                                 &drs_tmp);
1474         if (!W_ERROR_IS_OK(status)) {
1475                 talloc_free(tmp_ctx);
1476                 return status;
1477         }
1478
1479         status = dsdb_syntax_OID_drsuapi_to_ldb(ctx,
1480                                                 attr,
1481                                                 &drs_tmp,
1482                                                 tmp_ctx,
1483                                                 &ldb_tmp);
1484         if (!W_ERROR_IS_OK(status)) {
1485                 talloc_free(tmp_ctx);
1486                 return status;
1487         }
1488
1489         talloc_free(tmp_ctx);
1490         return WERR_OK;
1491 }
1492
1493 static WERROR dsdb_syntax_UNICODE_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
1494                                                  const struct dsdb_attribute *attr,
1495                                                  const struct drsuapi_DsReplicaAttribute *in,
1496                                                  TALLOC_CTX *mem_ctx,
1497                                                  struct ldb_message_element *out)
1498 {
1499         unsigned int i;
1500
1501         out->flags      = 0;
1502         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
1503         W_ERROR_HAVE_NO_MEMORY(out->name);
1504
1505         out->num_values = in->value_ctr.num_values;
1506         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
1507         W_ERROR_HAVE_NO_MEMORY(out->values);
1508
1509         for (i=0; i < out->num_values; i++) {
1510                 size_t converted_size = 0;
1511                 char *str;
1512
1513                 if (in->value_ctr.values[i].blob == NULL) {
1514                         return WERR_FOOBAR;
1515                 }
1516
1517                 if (in->value_ctr.values[i].blob->length == 0) {
1518                         return WERR_FOOBAR;
1519                 }
1520
1521                 if (!convert_string_talloc(out->values,
1522                                            CH_UTF16, CH_UNIX,
1523                                            in->value_ctr.values[i].blob->data,
1524                                            in->value_ctr.values[i].blob->length,
1525                                            (void **)&str, &converted_size)) {
1526                         return WERR_FOOBAR;
1527                 }
1528
1529                 out->values[i] = data_blob_string_const(str);
1530         }
1531
1532         return WERR_OK;
1533 }
1534
1535 static WERROR dsdb_syntax_UNICODE_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
1536                                                  const struct dsdb_attribute *attr,
1537                                                  const struct ldb_message_element *in,
1538                                                  TALLOC_CTX *mem_ctx,
1539                                                  struct drsuapi_DsReplicaAttribute *out)
1540 {
1541         unsigned int i;
1542         DATA_BLOB *blobs;
1543
1544         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
1545                 return WERR_FOOBAR;
1546         }
1547
1548         out->attid                      = dsdb_attribute_get_attid(attr,
1549                                                                    ctx->is_schema_nc);
1550         out->value_ctr.num_values       = in->num_values;
1551         out->value_ctr.values           = talloc_array(mem_ctx,
1552                                                        struct drsuapi_DsAttributeValue,
1553                                                        in->num_values);
1554         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
1555
1556         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
1557         W_ERROR_HAVE_NO_MEMORY(blobs);
1558
1559         for (i=0; i < in->num_values; i++) {
1560                 out->value_ctr.values[i].blob   = &blobs[i];
1561
1562                 if (!convert_string_talloc(blobs,
1563                                            CH_UNIX, CH_UTF16,
1564                                            in->values[i].data, in->values[i].length,
1565                                            (void **)&blobs[i].data, &blobs[i].length)) {
1566                         return WERR_FOOBAR;
1567                 }
1568         }
1569
1570         return WERR_OK;
1571 }
1572
1573 static WERROR dsdb_syntax_UNICODE_validate_one_val(const struct dsdb_syntax_ctx *ctx,
1574                                                    const struct dsdb_attribute *attr,
1575                                                    const struct ldb_val *val)
1576 {
1577         void *dst = NULL;
1578         size_t size;
1579         bool ok;
1580
1581         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
1582                 return WERR_FOOBAR;
1583         }
1584
1585         ok = convert_string_talloc(ctx->ldb,
1586                                    CH_UNIX, CH_UTF16,
1587                                    val->data,
1588                                    val->length,
1589                                    (void **)&dst,
1590                                    &size);
1591         TALLOC_FREE(dst);
1592         if (!ok) {
1593                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1594         }
1595
1596         if (attr->rangeLower) {
1597                 if ((size/2) < *attr->rangeLower) {
1598                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1599                 }
1600         }
1601
1602         if (attr->rangeUpper) {
1603                 if ((size/2) > *attr->rangeUpper) {
1604                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1605                 }
1606         }
1607
1608         return WERR_OK;
1609 }
1610
1611 static WERROR dsdb_syntax_UNICODE_validate_ldb(const struct dsdb_syntax_ctx *ctx,
1612                                                const struct dsdb_attribute *attr,
1613                                                const struct ldb_message_element *in)
1614 {
1615         WERROR status;
1616         unsigned int i;
1617
1618         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
1619                 return WERR_FOOBAR;
1620         }
1621
1622         for (i=0; i < in->num_values; i++) {
1623                 if (in->values[i].length == 0) {
1624                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1625                 }
1626
1627                 status = dsdb_syntax_UNICODE_validate_one_val(ctx,
1628                                                               attr,
1629                                                               &in->values[i]);
1630                 if (!W_ERROR_IS_OK(status)) {
1631                         return status;
1632                 }
1633         }
1634
1635         return WERR_OK;
1636 }
1637
1638 static WERROR dsdb_syntax_one_DN_drsuapi_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
1639                                                 const struct dsdb_syntax *syntax,
1640                                                 const DATA_BLOB *in, DATA_BLOB *out)
1641 {
1642         struct drsuapi_DsReplicaObjectIdentifier3 id3;
1643         enum ndr_err_code ndr_err;
1644         DATA_BLOB guid_blob;
1645         struct ldb_dn *dn;
1646         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1647         int ret;
1648         NTSTATUS status;
1649
1650         if (!tmp_ctx) {
1651                 W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
1652         }
1653
1654         if (in == NULL) {
1655                 talloc_free(tmp_ctx);
1656                 return WERR_FOOBAR;
1657         }
1658
1659         if (in->length == 0) {
1660                 talloc_free(tmp_ctx);
1661                 return WERR_FOOBAR;
1662         }
1663
1664
1665         /* windows sometimes sends an extra two pad bytes here */
1666         ndr_err = ndr_pull_struct_blob(in,
1667                                        tmp_ctx, &id3,
1668                                        (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
1669         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1670                 status = ndr_map_error2ntstatus(ndr_err);
1671                 talloc_free(tmp_ctx);
1672                 return ntstatus_to_werror(status);
1673         }
1674
1675         dn = ldb_dn_new(tmp_ctx, ldb, id3.dn);
1676         if (!dn) {
1677                 talloc_free(tmp_ctx);
1678                 /* If this fails, it must be out of memory, as it does not do much parsing */
1679                 W_ERROR_HAVE_NO_MEMORY(dn);
1680         }
1681
1682         if (!GUID_all_zero(&id3.guid)) {
1683                 status = GUID_to_ndr_blob(&id3.guid, tmp_ctx, &guid_blob);
1684                 if (!NT_STATUS_IS_OK(status)) {
1685                         talloc_free(tmp_ctx);
1686                         return ntstatus_to_werror(status);
1687                 }
1688
1689                 ret = ldb_dn_set_extended_component(dn, "GUID", &guid_blob);
1690                 if (ret != LDB_SUCCESS) {
1691                         talloc_free(tmp_ctx);
1692                         return WERR_FOOBAR;
1693                 }
1694                 talloc_free(guid_blob.data);
1695         }
1696
1697         if (id3.__ndr_size_sid) {
1698                 DATA_BLOB sid_blob;
1699                 ndr_err = ndr_push_struct_blob(&sid_blob, tmp_ctx, &id3.sid,
1700                                                (ndr_push_flags_fn_t)ndr_push_dom_sid);
1701                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1702                         status = ndr_map_error2ntstatus(ndr_err);
1703                         talloc_free(tmp_ctx);
1704                         return ntstatus_to_werror(status);
1705                 }
1706
1707                 ret = ldb_dn_set_extended_component(dn, "SID", &sid_blob);
1708                 if (ret != LDB_SUCCESS) {
1709                         talloc_free(tmp_ctx);
1710                         return WERR_FOOBAR;
1711                 }
1712         }
1713
1714         *out = data_blob_string_const(ldb_dn_get_extended_linearized(mem_ctx, dn, 1));
1715         talloc_free(tmp_ctx);
1716         return WERR_OK;
1717 }
1718
1719 static WERROR dsdb_syntax_DN_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
1720                                             const struct dsdb_attribute *attr,
1721                                             const struct drsuapi_DsReplicaAttribute *in,
1722                                             TALLOC_CTX *mem_ctx,
1723                                             struct ldb_message_element *out)
1724 {
1725         unsigned int i;
1726
1727         out->flags      = 0;
1728         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
1729         W_ERROR_HAVE_NO_MEMORY(out->name);
1730
1731         out->num_values = in->value_ctr.num_values;
1732         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
1733         W_ERROR_HAVE_NO_MEMORY(out->values);
1734
1735         for (i=0; i < out->num_values; i++) {
1736                 WERROR status = dsdb_syntax_one_DN_drsuapi_to_ldb(out->values, ctx->ldb, attr->syntax,
1737                                                                   in->value_ctr.values[i].blob,
1738                                                                   &out->values[i]);
1739                 if (!W_ERROR_IS_OK(status)) {
1740                         return status;
1741                 }
1742
1743         }
1744
1745         return WERR_OK;
1746 }
1747
1748 static WERROR dsdb_syntax_DN_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
1749                                             const struct dsdb_attribute *attr,
1750                                             const struct ldb_message_element *in,
1751                                             TALLOC_CTX *mem_ctx,
1752                                             struct drsuapi_DsReplicaAttribute *out)
1753 {
1754         unsigned int i;
1755         DATA_BLOB *blobs;
1756
1757         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
1758                 return WERR_FOOBAR;
1759         }
1760
1761         out->attid                      = dsdb_attribute_get_attid(attr,
1762                                                                    ctx->is_schema_nc);
1763         out->value_ctr.num_values       = in->num_values;
1764         out->value_ctr.values           = talloc_array(mem_ctx,
1765                                                        struct drsuapi_DsAttributeValue,
1766                                                        in->num_values);
1767         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
1768
1769         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
1770         W_ERROR_HAVE_NO_MEMORY(blobs);
1771
1772         for (i=0; i < in->num_values; i++) {
1773                 struct drsuapi_DsReplicaObjectIdentifier3 id3;
1774                 enum ndr_err_code ndr_err;
1775                 struct ldb_dn *dn;
1776                 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1777                 NTSTATUS status;
1778
1779                 W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
1780
1781                 out->value_ctr.values[i].blob   = &blobs[i];
1782
1783                 dn = ldb_dn_from_ldb_val(tmp_ctx, ctx->ldb, &in->values[i]);
1784
1785                 W_ERROR_HAVE_NO_MEMORY(dn);
1786
1787                 ZERO_STRUCT(id3);
1788
1789                 status = dsdb_get_extended_dn_guid(dn, &id3.guid, "GUID");
1790                 if (!NT_STATUS_IS_OK(status) &&
1791                     !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1792                         talloc_free(tmp_ctx);
1793                         return ntstatus_to_werror(status);
1794                 }
1795
1796                 status = dsdb_get_extended_dn_sid(dn, &id3.sid, "SID");
1797                 if (!NT_STATUS_IS_OK(status) &&
1798                     !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1799                         talloc_free(tmp_ctx);
1800                         return ntstatus_to_werror(status);
1801                 }
1802
1803                 id3.dn = ldb_dn_get_linearized(dn);
1804
1805                 ndr_err = ndr_push_struct_blob(&blobs[i], blobs, &id3, (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1806                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1807                         status = ndr_map_error2ntstatus(ndr_err);
1808                         talloc_free(tmp_ctx);
1809                         return ntstatus_to_werror(status);
1810                 }
1811                 talloc_free(tmp_ctx);
1812         }
1813
1814         return WERR_OK;
1815 }
1816
1817 static WERROR dsdb_syntax_DN_validate_one_val(const struct dsdb_syntax_ctx *ctx,
1818                                               const struct dsdb_attribute *attr,
1819                                               const struct ldb_val *val,
1820                                               TALLOC_CTX *mem_ctx,
1821                                               struct dsdb_dn **_dsdb_dn)
1822 {
1823         static const char * const extended_list[] = { "GUID", "SID", NULL };
1824         enum ndr_err_code ndr_err;
1825         struct GUID guid;
1826         struct dom_sid sid;
1827         const DATA_BLOB *sid_blob;
1828         struct dsdb_dn *dsdb_dn;
1829         struct ldb_dn *dn;
1830         char *dn_str;
1831         struct ldb_dn *dn2;
1832         char *dn2_str;
1833         int num_components;
1834         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1835         NTSTATUS status;
1836
1837         W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
1838
1839         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
1840                 return WERR_FOOBAR;
1841         }
1842
1843         dsdb_dn = dsdb_dn_parse(tmp_ctx, ctx->ldb, val,
1844                                 attr->syntax->ldap_oid);
1845         if (!dsdb_dn) {
1846                 talloc_free(tmp_ctx);
1847                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1848         }
1849         dn = dsdb_dn->dn;
1850
1851         dn2 = ldb_dn_copy(tmp_ctx, dn);
1852         if (dn == NULL) {
1853                 talloc_free(tmp_ctx);
1854                 return WERR_NOMEM;
1855         }
1856
1857         num_components = ldb_dn_get_comp_num(dn);
1858
1859         status = dsdb_get_extended_dn_guid(dn, &guid, "GUID");
1860         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1861                 num_components++;
1862         } else if (!NT_STATUS_IS_OK(status)) {
1863                 talloc_free(tmp_ctx);
1864                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1865         }
1866
1867         sid_blob = ldb_dn_get_extended_component(dn, "SID");
1868         if (sid_blob) {
1869                 num_components++;
1870                 ndr_err = ndr_pull_struct_blob_all(sid_blob,
1871                                                    tmp_ctx,
1872                                                    &sid,
1873                                                    (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
1874                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1875                         talloc_free(tmp_ctx);
1876                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1877                 }
1878         }
1879
1880         /* Do not allow links to the RootDSE */
1881         if (num_components == 0) {
1882                 talloc_free(tmp_ctx);
1883                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1884         }
1885
1886         /*
1887          * We need to check that only "GUID" and "SID" are
1888          * specified as extended components, we do that
1889          * by comparing the dn's after removing all components
1890          * from one dn and only the allowed subset from the other
1891          * one.
1892          */
1893         ldb_dn_extended_filter(dn, extended_list);
1894
1895         dn_str = ldb_dn_get_extended_linearized(tmp_ctx, dn, 0);
1896         if (dn_str == NULL) {
1897                 talloc_free(tmp_ctx);
1898                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1899         }
1900         dn2_str = ldb_dn_get_extended_linearized(tmp_ctx, dn2, 0);
1901         if (dn2_str == NULL) {
1902                 talloc_free(tmp_ctx);
1903                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1904         }
1905
1906         if (strcmp(dn_str, dn2_str) != 0) {
1907                 talloc_free(tmp_ctx);
1908                 return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1909         }
1910
1911         *_dsdb_dn = talloc_move(mem_ctx, &dsdb_dn);
1912         talloc_free(tmp_ctx);
1913         return WERR_OK;
1914 }
1915
1916 static WERROR dsdb_syntax_DN_validate_ldb(const struct dsdb_syntax_ctx *ctx,
1917                                           const struct dsdb_attribute *attr,
1918                                           const struct ldb_message_element *in)
1919 {
1920         unsigned int i;
1921
1922         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
1923                 return WERR_FOOBAR;
1924         }
1925
1926         for (i=0; i < in->num_values; i++) {
1927                 WERROR status;
1928                 struct dsdb_dn *dsdb_dn;
1929                 TALLOC_CTX *tmp_ctx = talloc_new(ctx->ldb);
1930                 W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
1931
1932                 status = dsdb_syntax_DN_validate_one_val(ctx,
1933                                                          attr,
1934                                                          &in->values[i],
1935                                                          tmp_ctx, &dsdb_dn);
1936                 if (!W_ERROR_IS_OK(status)) {
1937                         talloc_free(tmp_ctx);
1938                         return status;
1939                 }
1940
1941                 if (dsdb_dn->dn_format != DSDB_NORMAL_DN) {
1942                         talloc_free(tmp_ctx);
1943                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
1944                 }
1945
1946                 talloc_free(tmp_ctx);
1947         }
1948
1949         return WERR_OK;
1950 }
1951
1952 static WERROR dsdb_syntax_DN_BINARY_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
1953                                                    const struct dsdb_attribute *attr,
1954                                                    const struct drsuapi_DsReplicaAttribute *in,
1955                                                    TALLOC_CTX *mem_ctx,
1956                                                    struct ldb_message_element *out)
1957 {
1958         unsigned int i;
1959         int ret;
1960
1961         out->flags      = 0;
1962         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
1963         W_ERROR_HAVE_NO_MEMORY(out->name);
1964
1965         out->num_values = in->value_ctr.num_values;
1966         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
1967         W_ERROR_HAVE_NO_MEMORY(out->values);
1968
1969         for (i=0; i < out->num_values; i++) {
1970                 struct drsuapi_DsReplicaObjectIdentifier3Binary id3;
1971                 enum ndr_err_code ndr_err;
1972                 DATA_BLOB guid_blob;
1973                 struct ldb_dn *dn;
1974                 struct dsdb_dn *dsdb_dn;
1975                 NTSTATUS status;
1976                 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1977                 if (!tmp_ctx) {
1978                         W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
1979                 }
1980
1981                 if (in->value_ctr.values[i].blob == NULL) {
1982                         talloc_free(tmp_ctx);
1983                         return WERR_FOOBAR;
1984                 }
1985
1986                 if (in->value_ctr.values[i].blob->length == 0) {
1987                         talloc_free(tmp_ctx);
1988                         return WERR_FOOBAR;
1989                 }
1990
1991
1992                 /* windows sometimes sends an extra two pad bytes here */
1993                 ndr_err = ndr_pull_struct_blob(in->value_ctr.values[i].blob,
1994                                                tmp_ctx, &id3,
1995                                                (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3Binary);
1996                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1997                         status = ndr_map_error2ntstatus(ndr_err);
1998                         talloc_free(tmp_ctx);
1999                         return ntstatus_to_werror(status);
2000                 }
2001
2002                 dn = ldb_dn_new(tmp_ctx, ctx->ldb, id3.dn);
2003                 if (!dn) {
2004                         talloc_free(tmp_ctx);
2005                         /* If this fails, it must be out of memory, as it does not do much parsing */
2006                         W_ERROR_HAVE_NO_MEMORY(dn);
2007                 }
2008
2009                 if (!GUID_all_zero(&id3.guid)) {
2010                         status = GUID_to_ndr_blob(&id3.guid, tmp_ctx, &guid_blob);
2011                         if (!NT_STATUS_IS_OK(status)) {
2012                                 talloc_free(tmp_ctx);
2013                                 return ntstatus_to_werror(status);
2014                         }
2015
2016                         ret = ldb_dn_set_extended_component(dn, "GUID", &guid_blob);
2017                         if (ret != LDB_SUCCESS) {
2018                                 talloc_free(tmp_ctx);
2019                                 return WERR_FOOBAR;
2020                         }
2021                         talloc_free(guid_blob.data);
2022                 }
2023
2024                 if (id3.__ndr_size_sid) {
2025                         DATA_BLOB sid_blob;
2026                         ndr_err = ndr_push_struct_blob(&sid_blob, tmp_ctx, &id3.sid,
2027                                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
2028                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2029                                 status = ndr_map_error2ntstatus(ndr_err);
2030                                 talloc_free(tmp_ctx);
2031                                 return ntstatus_to_werror(status);
2032                         }
2033
2034                         ret = ldb_dn_set_extended_component(dn, "SID", &sid_blob);
2035                         if (ret != LDB_SUCCESS) {
2036                                 talloc_free(tmp_ctx);
2037                                 return WERR_FOOBAR;
2038                         }
2039                 }
2040
2041                 /* set binary stuff */
2042                 dsdb_dn = dsdb_dn_construct(tmp_ctx, dn, id3.binary, attr->syntax->ldap_oid);
2043                 if (!dsdb_dn) {
2044                         /* If this fails, it must be out of memory, we know the ldap_oid is valid */
2045                         talloc_free(tmp_ctx);
2046                         W_ERROR_HAVE_NO_MEMORY(dsdb_dn);
2047                 }
2048                 out->values[i] = data_blob_string_const(dsdb_dn_get_extended_linearized(out->values, dsdb_dn, 1));
2049                 talloc_free(tmp_ctx);
2050         }
2051
2052         return WERR_OK;
2053 }
2054
2055 static WERROR dsdb_syntax_DN_BINARY_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
2056                                                    const struct dsdb_attribute *attr,
2057                                                    const struct ldb_message_element *in,
2058                                                    TALLOC_CTX *mem_ctx,
2059                                                    struct drsuapi_DsReplicaAttribute *out)
2060 {
2061         unsigned int i;
2062         DATA_BLOB *blobs;
2063
2064         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
2065                 return WERR_FOOBAR;
2066         }
2067
2068         out->attid                      = dsdb_attribute_get_attid(attr,
2069                                                                    ctx->is_schema_nc);
2070         out->value_ctr.num_values       = in->num_values;
2071         out->value_ctr.values           = talloc_array(mem_ctx,
2072                                                        struct drsuapi_DsAttributeValue,
2073                                                        in->num_values);
2074         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
2075
2076         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
2077         W_ERROR_HAVE_NO_MEMORY(blobs);
2078
2079         for (i=0; i < in->num_values; i++) {
2080                 struct drsuapi_DsReplicaObjectIdentifier3Binary id3;
2081                 enum ndr_err_code ndr_err;
2082                 const DATA_BLOB *sid_blob;
2083                 struct dsdb_dn *dsdb_dn;
2084                 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
2085                 NTSTATUS status;
2086
2087                 W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
2088
2089                 out->value_ctr.values[i].blob   = &blobs[i];
2090
2091                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ctx->ldb, &in->values[i], attr->syntax->ldap_oid);
2092
2093                 if (!dsdb_dn) {
2094                         talloc_free(tmp_ctx);
2095                         return ntstatus_to_werror(NT_STATUS_INVALID_PARAMETER);
2096                 }
2097
2098                 ZERO_STRUCT(id3);
2099
2100                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &id3.guid, "GUID");
2101                 if (!NT_STATUS_IS_OK(status) &&
2102                     !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2103                         talloc_free(tmp_ctx);
2104                         return ntstatus_to_werror(status);
2105                 }
2106
2107                 sid_blob = ldb_dn_get_extended_component(dsdb_dn->dn, "SID");
2108                 if (sid_blob) {
2109
2110                         ndr_err = ndr_pull_struct_blob_all(sid_blob,
2111                                                            tmp_ctx, &id3.sid,
2112                                                            (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
2113                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2114                                 status = ndr_map_error2ntstatus(ndr_err);
2115                                 talloc_free(tmp_ctx);
2116                                 return ntstatus_to_werror(status);
2117                         }
2118                 }
2119
2120                 id3.dn = ldb_dn_get_linearized(dsdb_dn->dn);
2121
2122                 /* get binary stuff */
2123                 id3.binary = dsdb_dn->extra_part;
2124
2125                 ndr_err = ndr_push_struct_blob(&blobs[i], blobs, &id3, (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3Binary);
2126                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2127                         status = ndr_map_error2ntstatus(ndr_err);
2128                         talloc_free(tmp_ctx);
2129                         return ntstatus_to_werror(status);
2130                 }
2131                 talloc_free(tmp_ctx);
2132         }
2133
2134         return WERR_OK;
2135 }
2136
2137 static WERROR dsdb_syntax_DN_BINARY_validate_ldb(const struct dsdb_syntax_ctx *ctx,
2138                                                  const struct dsdb_attribute *attr,
2139                                                  const struct ldb_message_element *in)
2140 {
2141         unsigned int i;
2142
2143         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
2144                 return WERR_FOOBAR;
2145         }
2146
2147         for (i=0; i < in->num_values; i++) {
2148                 WERROR status;
2149                 struct dsdb_dn *dsdb_dn;
2150                 TALLOC_CTX *tmp_ctx = talloc_new(ctx->ldb);
2151                 W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
2152
2153                 status = dsdb_syntax_DN_validate_one_val(ctx,
2154                                                          attr,
2155                                                          &in->values[i],
2156                                                          tmp_ctx, &dsdb_dn);
2157                 if (!W_ERROR_IS_OK(status)) {
2158                         talloc_free(tmp_ctx);
2159                         return status;
2160                 }
2161
2162                 if (dsdb_dn->dn_format != DSDB_BINARY_DN) {
2163                         talloc_free(tmp_ctx);
2164                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
2165                 }
2166
2167                 status = dsdb_syntax_DATA_BLOB_validate_one_val(ctx,
2168                                                                 attr,
2169                                                                 &dsdb_dn->extra_part);
2170                 if (!W_ERROR_IS_OK(status)) {
2171                         talloc_free(tmp_ctx);
2172                         return status;
2173                 }
2174
2175                 talloc_free(tmp_ctx);
2176         }
2177
2178         return WERR_OK;
2179 }
2180
2181 static WERROR dsdb_syntax_DN_STRING_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
2182                                                    const struct dsdb_attribute *attr,
2183                                                    const struct drsuapi_DsReplicaAttribute *in,
2184                                                    TALLOC_CTX *mem_ctx,
2185                                                    struct ldb_message_element *out)
2186 {
2187         return dsdb_syntax_DN_BINARY_drsuapi_to_ldb(ctx,
2188                                                     attr,
2189                                                     in,
2190                                                     mem_ctx,
2191                                                     out);
2192 }
2193
2194 static WERROR dsdb_syntax_DN_STRING_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
2195                                                    const struct dsdb_attribute *attr,
2196                                                    const struct ldb_message_element *in,
2197                                                    TALLOC_CTX *mem_ctx,
2198                                                    struct drsuapi_DsReplicaAttribute *out)
2199 {
2200         return dsdb_syntax_DN_BINARY_ldb_to_drsuapi(ctx,
2201                                                     attr,
2202                                                     in,
2203                                                     mem_ctx,
2204                                                     out);
2205 }
2206
2207 static WERROR dsdb_syntax_DN_STRING_validate_ldb(const struct dsdb_syntax_ctx *ctx,
2208                                                  const struct dsdb_attribute *attr,
2209                                                  const struct ldb_message_element *in)
2210 {
2211         unsigned int i;
2212
2213         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
2214                 return WERR_FOOBAR;
2215         }
2216
2217         for (i=0; i < in->num_values; i++) {
2218                 WERROR status;
2219                 struct dsdb_dn *dsdb_dn;
2220                 TALLOC_CTX *tmp_ctx = talloc_new(ctx->ldb);
2221                 W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
2222
2223                 status = dsdb_syntax_DN_validate_one_val(ctx,
2224                                                          attr,
2225                                                          &in->values[i],
2226                                                          tmp_ctx, &dsdb_dn);
2227                 if (!W_ERROR_IS_OK(status)) {
2228                         talloc_free(tmp_ctx);
2229                         return status;
2230                 }
2231
2232                 if (dsdb_dn->dn_format != DSDB_STRING_DN) {
2233                         talloc_free(tmp_ctx);
2234                         return WERR_DS_INVALID_ATTRIBUTE_SYNTAX;
2235                 }
2236
2237                 status = dsdb_syntax_UNICODE_validate_one_val(ctx,
2238                                                               attr,
2239                                                               &dsdb_dn->extra_part);
2240                 if (!W_ERROR_IS_OK(status)) {
2241                         talloc_free(tmp_ctx);
2242                         return status;
2243                 }
2244
2245                 talloc_free(tmp_ctx);
2246         }
2247
2248         return WERR_OK;
2249 }
2250
2251 static WERROR dsdb_syntax_PRESENTATION_ADDRESS_drsuapi_to_ldb(const struct dsdb_syntax_ctx *ctx,
2252                                                               const struct dsdb_attribute *attr,
2253                                                               const struct drsuapi_DsReplicaAttribute *in,
2254                                                               TALLOC_CTX *mem_ctx,
2255                                                               struct ldb_message_element *out)
2256 {
2257         unsigned int i;
2258
2259         out->flags      = 0;
2260         out->name       = talloc_strdup(mem_ctx, attr->lDAPDisplayName);
2261         W_ERROR_HAVE_NO_MEMORY(out->name);
2262
2263         out->num_values = in->value_ctr.num_values;
2264         out->values     = talloc_array(mem_ctx, struct ldb_val, out->num_values);
2265         W_ERROR_HAVE_NO_MEMORY(out->values);
2266
2267         for (i=0; i < out->num_values; i++) {
2268                 size_t len;
2269                 size_t converted_size = 0;
2270                 char *str;
2271
2272                 if (in->value_ctr.values[i].blob == NULL) {
2273                         return WERR_FOOBAR;
2274                 }
2275
2276                 if (in->value_ctr.values[i].blob->length < 4) {
2277                         return WERR_FOOBAR;
2278                 }
2279
2280                 len = IVAL(in->value_ctr.values[i].blob->data, 0);
2281
2282                 if (len != in->value_ctr.values[i].blob->length) {
2283                         return WERR_FOOBAR;
2284                 }
2285
2286                 if (!convert_string_talloc(out->values, CH_UTF16, CH_UNIX,
2287                                            in->value_ctr.values[i].blob->data+4,
2288                                            in->value_ctr.values[i].blob->length-4,
2289                                            (void **)&str, &converted_size)) {
2290                         return WERR_FOOBAR;
2291                 }
2292
2293                 out->values[i] = data_blob_string_const(str);
2294         }
2295
2296         return WERR_OK;
2297 }
2298
2299 static WERROR dsdb_syntax_PRESENTATION_ADDRESS_ldb_to_drsuapi(const struct dsdb_syntax_ctx *ctx,
2300                                                               const struct dsdb_attribute *attr,
2301                                                               const struct ldb_message_element *in,
2302                                                               TALLOC_CTX *mem_ctx,
2303                                                               struct drsuapi_DsReplicaAttribute *out)
2304 {
2305         unsigned int i;
2306         DATA_BLOB *blobs;
2307
2308         if (attr->attributeID_id == DRSUAPI_ATTID_INVALID) {
2309                 return WERR_FOOBAR;
2310         }
2311
2312         out->attid                      = dsdb_attribute_get_attid(attr,
2313                                                                    ctx->is_schema_nc);
2314         out->value_ctr.num_values       = in->num_values;
2315         out->value_ctr.values           = talloc_array(mem_ctx,
2316                                                        struct drsuapi_DsAttributeValue,
2317                                                        in->num_values);
2318         W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values);
2319
2320         blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values);
2321         W_ERROR_HAVE_NO_MEMORY(blobs);
2322
2323         for (i=0; i < in->num_values; i++) {
2324                 uint8_t *data;
2325                 size_t ret;
2326
2327                 out->value_ctr.values[i].blob   = &blobs[i];
2328
2329                 if (!convert_string_talloc(blobs, CH_UNIX, CH_UTF16,
2330                                            in->values[i].data,
2331                                            in->values[i].length,
2332                                            (void **)&data, &ret)) {
2333                         return WERR_FOOBAR;
2334                 }
2335
2336                 blobs[i] = data_blob_talloc(blobs, NULL, 4 + ret);
2337                 W_ERROR_HAVE_NO_MEMORY(blobs[i].data);
2338
2339                 SIVAL(blobs[i].data, 0, 4 + ret);
2340
2341                 if (ret > 0) {
2342                         memcpy(blobs[i].data + 4, data, ret);
2343                         talloc_free(data);
2344                 }
2345         }
2346
2347         return WERR_OK;
2348 }
2349
2350 static WERROR dsdb_syntax_PRESENTATION_ADDRESS_validate_ldb(const struct dsdb_syntax_ctx *ctx,
2351                                                             const struct dsdb_attribute *attr,
2352                                                             const struct ldb_message_element *in)
2353 {
2354         return dsdb_syntax_UNICODE_validate_ldb(ctx,
2355                                                 attr,
2356                                                 in);
2357 }
2358
2359 #define OMOBJECTCLASS(val) { .length = sizeof(val) - 1, .data = discard_const_p(uint8_t, val) }
2360
2361 static const struct dsdb_syntax dsdb_syntaxes[] = {
2362         {
2363                 .name                   = "Boolean",
2364                 .ldap_oid               = LDB_SYNTAX_BOOLEAN,
2365                 .oMSyntax               = 1,
2366                 .attributeSyntax_oid    = "2.5.5.8",
2367                 .drsuapi_to_ldb         = dsdb_syntax_BOOL_drsuapi_to_ldb,
2368                 .ldb_to_drsuapi         = dsdb_syntax_BOOL_ldb_to_drsuapi,
2369                 .validate_ldb           = dsdb_syntax_BOOL_validate_ldb,
2370                 .equality               = "booleanMatch",
2371                 .comment                = "Boolean",
2372                 .auto_normalise         = true
2373         },{
2374                 .name                   = "Integer",
2375                 .ldap_oid               = LDB_SYNTAX_INTEGER,
2376                 .oMSyntax               = 2,
2377                 .attributeSyntax_oid    = "2.5.5.9",
2378                 .drsuapi_to_ldb         = dsdb_syntax_INT32_drsuapi_to_ldb,
2379                 .ldb_to_drsuapi         = dsdb_syntax_INT32_ldb_to_drsuapi,
2380                 .validate_ldb           = dsdb_syntax_INT32_validate_ldb,
2381                 .equality               = "integerMatch",
2382                 .comment                = "Integer",
2383                 .ldb_syntax             = LDB_SYNTAX_SAMBA_INT32,
2384                 .auto_normalise         = true
2385         },{
2386                 .name                   = "String(Octet)",
2387                 .ldap_oid               = LDB_SYNTAX_OCTET_STRING,
2388                 .oMSyntax               = 4,
2389                 .attributeSyntax_oid    = "2.5.5.10",
2390                 .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
2391                 .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
2392                 .validate_ldb           = dsdb_syntax_DATA_BLOB_validate_ldb,
2393                 .equality               = "octetStringMatch",
2394                 .comment                = "Octet String",
2395         },{
2396                 .name                   = "String(Sid)",
2397                 .ldap_oid               = LDB_SYNTAX_OCTET_STRING,
2398                 .oMSyntax               = 4,
2399                 .attributeSyntax_oid    = "2.5.5.17",
2400                 .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
2401                 .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
2402                 .validate_ldb           = dsdb_syntax_DATA_BLOB_validate_ldb,
2403                 .equality               = "octetStringMatch",
2404                 .comment                = "Octet String - Security Identifier (SID)",
2405                 .ldb_syntax             = LDB_SYNTAX_SAMBA_SID
2406         },{
2407                 .name                   = "String(Object-Identifier)",
2408                 .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.38",
2409                 .oMSyntax               = 6,
2410                 .attributeSyntax_oid    = "2.5.5.2",
2411                 .drsuapi_to_ldb         = dsdb_syntax_OID_drsuapi_to_ldb,
2412                 .ldb_to_drsuapi         = dsdb_syntax_OID_ldb_to_drsuapi,
2413                 .validate_ldb           = dsdb_syntax_OID_validate_ldb,
2414                 .equality               = "caseIgnoreMatch", /* Would use "objectIdentifierMatch" but most are ldap attribute/class names */
2415                 .comment                = "OID String",
2416                 .ldb_syntax             = LDB_SYNTAX_DIRECTORY_STRING
2417         },{
2418                 .name                   = "Enumeration",
2419                 .ldap_oid               = LDB_SYNTAX_INTEGER,
2420                 .oMSyntax               = 10,
2421                 .attributeSyntax_oid    = "2.5.5.9",
2422                 .drsuapi_to_ldb         = dsdb_syntax_INT32_drsuapi_to_ldb,
2423                 .ldb_to_drsuapi         = dsdb_syntax_INT32_ldb_to_drsuapi,
2424                 .validate_ldb           = dsdb_syntax_INT32_validate_ldb,
2425                 .ldb_syntax             = LDB_SYNTAX_SAMBA_INT32,
2426                 .auto_normalise         = true
2427         },{
2428         /* not used in w2k3 forest */
2429                 .name                   = "String(Numeric)",
2430                 .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.36",
2431                 .oMSyntax               = 18,
2432                 .attributeSyntax_oid    = "2.5.5.6",
2433                 .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
2434                 .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
2435                 .validate_ldb           = dsdb_syntax_DATA_BLOB_validate_ldb,
2436                 .equality               = "numericStringMatch",
2437                 .substring              = "numericStringSubstringsMatch",
2438                 .comment                = "Numeric String",
2439                 .ldb_syntax             = LDB_SYNTAX_DIRECTORY_STRING,
2440         },{
2441                 .name                   = "String(Printable)",
2442                 .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.44",
2443                 .oMSyntax               = 19,
2444                 .attributeSyntax_oid    = "2.5.5.5",
2445                 .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
2446                 .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
2447                 .validate_ldb           = dsdb_syntax_DATA_BLOB_validate_ldb,
2448                 .ldb_syntax             = LDB_SYNTAX_OCTET_STRING,
2449         },{
2450                 .name                   = "String(Teletex)",
2451                 .ldap_oid               = "1.2.840.113556.1.4.905",
2452                 .oMSyntax               = 20,
2453                 .attributeSyntax_oid    = "2.5.5.4",
2454                 .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
2455                 .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
2456                 .validate_ldb           = dsdb_syntax_DATA_BLOB_validate_ldb,
2457                 .equality               = "caseIgnoreMatch",
2458                 .substring              = "caseIgnoreSubstringsMatch",
2459                 .comment                = "Case Insensitive String",
2460                 .ldb_syntax             = LDB_SYNTAX_DIRECTORY_STRING,
2461         },{
2462                 .name                   = "String(IA5)",
2463                 .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.26",
2464                 .oMSyntax               = 22,
2465                 .attributeSyntax_oid    = "2.5.5.5",
2466                 .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
2467                 .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
2468                 .validate_ldb           = dsdb_syntax_DATA_BLOB_validate_ldb,
2469                 .equality               = "caseExactIA5Match",
2470                 .comment                = "Printable String",
2471                 .ldb_syntax             = LDB_SYNTAX_OCTET_STRING,
2472         },{
2473                 .name                   = "String(UTC-Time)",
2474                 .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.53",
2475                 .oMSyntax               = 23,
2476                 .attributeSyntax_oid    = "2.5.5.11",
2477                 .drsuapi_to_ldb         = dsdb_syntax_NTTIME_UTC_drsuapi_to_ldb,
2478                 .ldb_to_drsuapi         = dsdb_syntax_NTTIME_UTC_ldb_to_drsuapi,
2479                 .validate_ldb           = dsdb_syntax_NTTIME_UTC_validate_ldb,
2480                 .equality               = "generalizedTimeMatch",
2481                 .comment                = "UTC Time",
2482                 .auto_normalise         = true
2483         },{
2484                 .name                   = "String(Generalized-Time)",
2485                 .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.24",
2486                 .oMSyntax               = 24,
2487                 .attributeSyntax_oid    = "2.5.5.11",
2488                 .drsuapi_to_ldb         = dsdb_syntax_NTTIME_drsuapi_to_ldb,
2489                 .ldb_to_drsuapi         = dsdb_syntax_NTTIME_ldb_to_drsuapi,
2490                 .validate_ldb           = dsdb_syntax_NTTIME_validate_ldb,
2491                 .equality               = "generalizedTimeMatch",
2492                 .comment                = "Generalized Time",
2493                 .ldb_syntax             = LDB_SYNTAX_UTC_TIME,
2494                 .auto_normalise         = true
2495         },{
2496         /* not used in w2k3 schema */
2497                 .name                   = "String(Case Sensitive)",
2498                 .ldap_oid               = "1.2.840.113556.1.4.1362",
2499                 .oMSyntax               = 27,
2500                 .attributeSyntax_oid    = "2.5.5.3",
2501                 .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
2502                 .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
2503                 .validate_ldb           = dsdb_syntax_DATA_BLOB_validate_ldb,
2504                 .equality               = "caseExactMatch",
2505                 .substring              = "caseExactSubstringsMatch",
2506                 /* TODO (kim): according to LDAP rfc we should be using same comparison
2507                  * as Directory String (LDB_SYNTAX_DIRECTORY_STRING), but case sensitive.
2508                  * But according to ms docs binary compare should do the job:
2509                  * http://msdn.microsoft.com/en-us/library/cc223200(v=PROT.10).aspx */
2510                 .ldb_syntax             = LDB_SYNTAX_OCTET_STRING,
2511         },{
2512                 .name                   = "String(Unicode)",
2513                 .ldap_oid               = LDB_SYNTAX_DIRECTORY_STRING,
2514                 .oMSyntax               = 64,
2515                 .attributeSyntax_oid    = "2.5.5.12",
2516                 .drsuapi_to_ldb         = dsdb_syntax_UNICODE_drsuapi_to_ldb,
2517                 .ldb_to_drsuapi         = dsdb_syntax_UNICODE_ldb_to_drsuapi,
2518                 .validate_ldb           = dsdb_syntax_UNICODE_validate_ldb,
2519                 .equality               = "caseIgnoreMatch",
2520                 .substring              = "caseIgnoreSubstringsMatch",
2521                 .comment                = "Directory String",
2522         },{
2523                 .name                   = "Interval/LargeInteger",
2524                 .ldap_oid               = "1.2.840.113556.1.4.906",
2525                 .oMSyntax               = 65,
2526                 .attributeSyntax_oid    = "2.5.5.16",
2527                 .drsuapi_to_ldb         = dsdb_syntax_INT64_drsuapi_to_ldb,
2528                 .ldb_to_drsuapi         = dsdb_syntax_INT64_ldb_to_drsuapi,
2529                 .validate_ldb           = dsdb_syntax_INT64_validate_ldb,
2530                 .equality               = "integerMatch",
2531                 .comment                = "Large Integer",
2532                 .ldb_syntax             = LDB_SYNTAX_INTEGER,
2533                 .auto_normalise         = true
2534         },{
2535                 .name                   = "String(NT-Sec-Desc)",
2536                 .ldap_oid               = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
2537                 .oMSyntax               = 66,
2538                 .attributeSyntax_oid    = "2.5.5.15",
2539                 .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
2540                 .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
2541                 .validate_ldb           = dsdb_syntax_DATA_BLOB_validate_ldb,
2542         },{
2543                 .name                   = "Object(DS-DN)",
2544                 .ldap_oid               = LDB_SYNTAX_DN,
2545                 .oMSyntax               = 127,
2546                 .oMObjectClass          = OMOBJECTCLASS("\x2b\x0c\x02\x87\x73\x1c\x00\x85\x4a"),
2547                 .attributeSyntax_oid    = "2.5.5.1",
2548                 .drsuapi_to_ldb         = dsdb_syntax_DN_drsuapi_to_ldb,
2549                 .ldb_to_drsuapi         = dsdb_syntax_DN_ldb_to_drsuapi,
2550                 .validate_ldb           = dsdb_syntax_DN_validate_ldb,
2551                 .equality               = "distinguishedNameMatch",
2552                 .comment                = "Object(DS-DN) == a DN",
2553         },{
2554                 .name                   = "Object(DN-Binary)",
2555                 .ldap_oid               = DSDB_SYNTAX_BINARY_DN,
2556                 .oMSyntax               = 127,
2557                 .oMObjectClass          = OMOBJECTCLASS("\x2a\x86\x48\x86\xf7\x14\x01\x01\x01\x0b"),
2558                 .attributeSyntax_oid    = "2.5.5.7",
2559                 .drsuapi_to_ldb         = dsdb_syntax_DN_BINARY_drsuapi_to_ldb,
2560                 .ldb_to_drsuapi         = dsdb_syntax_DN_BINARY_ldb_to_drsuapi,
2561                 .validate_ldb           = dsdb_syntax_DN_BINARY_validate_ldb,
2562                 .equality               = "octetStringMatch",
2563                 .comment                = "OctetString: Binary+DN",
2564         },{
2565         /* not used in w2k3 schema, but used in Exchange schema*/
2566                 .name                   = "Object(OR-Name)",
2567                 .ldap_oid               = DSDB_SYNTAX_OR_NAME,
2568                 .oMSyntax               = 127,
2569                 .oMObjectClass          = OMOBJECTCLASS("\x56\x06\x01\x02\x05\x0b\x1D"),
2570                 .attributeSyntax_oid    = "2.5.5.7",
2571                 .drsuapi_to_ldb         = dsdb_syntax_DN_BINARY_drsuapi_to_ldb,
2572                 .ldb_to_drsuapi         = dsdb_syntax_DN_BINARY_ldb_to_drsuapi,
2573                 .validate_ldb           = dsdb_syntax_DN_BINARY_validate_ldb,
2574                 .equality               = "caseIgnoreMatch",
2575                 .ldb_syntax             = LDB_SYNTAX_DN,
2576         },{
2577         /*
2578          * TODO: verify if DATA_BLOB is correct here...!
2579          *
2580          *       repsFrom and repsTo are the only attributes using
2581          *       this attribute syntax, but they're not replicated...
2582          */
2583                 .name                   = "Object(Replica-Link)",
2584                 .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.40",
2585                 .oMSyntax               = 127,
2586                 .oMObjectClass          = OMOBJECTCLASS("\x2a\x86\x48\x86\xf7\x14\x01\x01\x01\x06"),
2587                 .attributeSyntax_oid    = "2.5.5.10",
2588                 .drsuapi_to_ldb         = dsdb_syntax_DATA_BLOB_drsuapi_to_ldb,
2589                 .ldb_to_drsuapi         = dsdb_syntax_DATA_BLOB_ldb_to_drsuapi,
2590                 .validate_ldb           = dsdb_syntax_DATA_BLOB_validate_ldb,
2591         },{
2592                 .name                   = "Object(Presentation-Address)",
2593                 .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.43",
2594                 .oMSyntax               = 127,
2595                 .oMObjectClass          = OMOBJECTCLASS("\x2b\x0c\x02\x87\x73\x1c\x00\x85\x5c"),
2596                 .attributeSyntax_oid    = "2.5.5.13",
2597                 .drsuapi_to_ldb         = dsdb_syntax_PRESENTATION_ADDRESS_drsuapi_to_ldb,
2598                 .ldb_to_drsuapi         = dsdb_syntax_PRESENTATION_ADDRESS_ldb_to_drsuapi,
2599                 .validate_ldb           = dsdb_syntax_PRESENTATION_ADDRESS_validate_ldb,
2600                 .comment                = "Presentation Address",
2601                 .ldb_syntax             = LDB_SYNTAX_DIRECTORY_STRING,
2602         },{
2603         /* not used in w2k3 schema */
2604                 .name                   = "Object(Access-Point)",
2605                 .ldap_oid               = "1.3.6.1.4.1.1466.115.121.1.2",
2606                 .oMSyntax               = 127,
2607                 .oMObjectClass          = OMOBJECTCLASS("\x2b\x0c\x02\x87\x73\x1c\x00\x85\x3e"),
2608                 .attributeSyntax_oid    = "2.5.5.14",
2609                 .drsuapi_to_ldb         = dsdb_syntax_FOOBAR_drsuapi_to_ldb,
2610                 .ldb_to_drsuapi         = dsdb_syntax_FOOBAR_ldb_to_drsuapi,
2611                 .validate_ldb           = dsdb_syntax_FOOBAR_validate_ldb,
2612                 .ldb_syntax             = LDB_SYNTAX_DIRECTORY_STRING,
2613         },{
2614         /* not used in w2k3 schema */
2615                 .name                   = "Object(DN-String)",
2616                 .ldap_oid               = DSDB_SYNTAX_STRING_DN,
2617                 .oMSyntax               = 127,
2618                 .oMObjectClass          = OMOBJECTCLASS("\x2a\x86\x48\x86\xf7\x14\x01\x01\x01\x0c"),
2619                 .attributeSyntax_oid    = "2.5.5.14",
2620                 .drsuapi_to_ldb         = dsdb_syntax_DN_STRING_drsuapi_to_ldb,
2621                 .ldb_to_drsuapi         = dsdb_syntax_DN_STRING_ldb_to_drsuapi,
2622                 .validate_ldb           = dsdb_syntax_DN_STRING_validate_ldb,
2623                 .equality               = "octetStringMatch",
2624                 .comment                = "OctetString: String+DN",
2625         }
2626 };
2627
2628 const struct dsdb_syntax *find_syntax_map_by_ad_oid(const char *ad_oid)
2629 {
2630         unsigned int i;
2631         for (i=0; dsdb_syntaxes[i].ldap_oid; i++) {
2632                 if (strcasecmp(ad_oid, dsdb_syntaxes[i].attributeSyntax_oid) == 0) {
2633                         return &dsdb_syntaxes[i];
2634                 }
2635         }
2636         return NULL;
2637 }
2638
2639 const struct dsdb_syntax *find_syntax_map_by_ad_syntax(int oMSyntax)
2640 {
2641         unsigned int i;
2642         for (i=0; dsdb_syntaxes[i].ldap_oid; i++) {
2643                 if (oMSyntax == dsdb_syntaxes[i].oMSyntax) {
2644                         return &dsdb_syntaxes[i];
2645                 }
2646         }
2647         return NULL;
2648 }
2649
2650 const struct dsdb_syntax *find_syntax_map_by_standard_oid(const char *standard_oid)
2651 {
2652         unsigned int i;
2653         for (i=0; dsdb_syntaxes[i].ldap_oid; i++) {
2654                 if (strcasecmp(standard_oid, dsdb_syntaxes[i].ldap_oid) == 0) {
2655                         return &dsdb_syntaxes[i];
2656                 }
2657         }
2658         return NULL;
2659 }
2660
2661 const struct dsdb_syntax *dsdb_syntax_for_attribute(const struct dsdb_attribute *attr)
2662 {
2663         unsigned int i;
2664
2665         for (i=0; i < ARRAY_SIZE(dsdb_syntaxes); i++) {
2666                 if (attr->oMSyntax != dsdb_syntaxes[i].oMSyntax) continue;
2667
2668                 if (attr->oMObjectClass.length != dsdb_syntaxes[i].oMObjectClass.length) continue;
2669
2670                 if (attr->oMObjectClass.length) {
2671                         int ret;
2672                         ret = memcmp(attr->oMObjectClass.data,
2673                                      dsdb_syntaxes[i].oMObjectClass.data,
2674                                      attr->oMObjectClass.length);
2675                         if (ret != 0) continue;
2676                 }
2677
2678                 if (strcmp(attr->attributeSyntax_oid, dsdb_syntaxes[i].attributeSyntax_oid) != 0) continue;
2679
2680                 return &dsdb_syntaxes[i];
2681         }
2682
2683         return NULL;
2684 }
2685
2686 WERROR dsdb_attribute_drsuapi_to_ldb(struct ldb_context *ldb,
2687                                      const struct dsdb_schema *schema,
2688                                      const struct dsdb_schema_prefixmap *pfm_remote,
2689                                      const struct drsuapi_DsReplicaAttribute *in,
2690                                      TALLOC_CTX *mem_ctx,
2691                                      struct ldb_message_element *out)
2692 {
2693         const struct dsdb_attribute *sa;
2694         struct dsdb_syntax_ctx syntax_ctx;
2695         uint32_t attid_local;
2696
2697         /* use default syntax conversion context */
2698         dsdb_syntax_ctx_init(&syntax_ctx, ldb, schema);
2699         syntax_ctx.pfm_remote = pfm_remote;
2700
2701         switch (dsdb_pfm_get_attid_type(in->attid)) {
2702         case DSDB_ATTID_TYPE_PFM:
2703                 /* map remote ATTID to local ATTID */
2704                 if (!dsdb_syntax_attid_from_remote_attid(&syntax_ctx, mem_ctx, in->attid, &attid_local)) {
2705                         DEBUG(0,(__location__ ": Can't find local ATTID for 0x%08X\n",
2706                                  in->attid));
2707                         return WERR_FOOBAR;
2708                 }
2709                 break;
2710         case DSDB_ATTID_TYPE_INTID:
2711                 /* use IntId value directly */
2712                 attid_local = in->attid;
2713                 break;
2714         default:
2715                 /* we should never get here */
2716                 DEBUG(0,(__location__ ": Invalid ATTID type passed for conversion - 0x%08X\n",
2717                          in->attid));
2718                 return WERR_INVALID_PARAMETER;
2719         }
2720
2721         sa = dsdb_attribute_by_attributeID_id(schema, attid_local);
2722         if (!sa) {
2723                 DEBUG(1,(__location__ ": Unknown attributeID_id 0x%08X\n", in->attid));
2724                 return WERR_FOOBAR;
2725         }
2726
2727         return sa->syntax->drsuapi_to_ldb(&syntax_ctx, sa, in, mem_ctx, out);
2728 }
2729
2730 WERROR dsdb_attribute_ldb_to_drsuapi(struct ldb_context *ldb,
2731                                      const struct dsdb_schema *schema,
2732                                      const struct ldb_message_element *in,
2733                                      TALLOC_CTX *mem_ctx,
2734                                      struct drsuapi_DsReplicaAttribute *out)
2735 {
2736         const struct dsdb_attribute *sa;
2737         struct dsdb_syntax_ctx syntax_ctx;
2738
2739         sa = dsdb_attribute_by_lDAPDisplayName(schema, in->name);
2740         if (!sa) {
2741                 return WERR_FOOBAR;
2742         }
2743
2744         /* use default syntax conversion context */
2745         dsdb_syntax_ctx_init(&syntax_ctx, ldb, schema);
2746
2747         return sa->syntax->ldb_to_drsuapi(&syntax_ctx, sa, in, mem_ctx, out);
2748 }
2749