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