r13372: fixes ... still no joy
[kai/samba.git] / source / libcli / ldap / ldap_controls.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    LDAP protocol helper functions for SAMBA
4    
5    Copyright (C) Simo Sorce 2005
6     
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20    
21 */
22
23 #include "includes.h"
24 #include "system/iconv.h"
25 #include "libcli/util/asn_1.h"
26 #include "libcli/ldap/ldap.h"
27 #include "lib/ldb/include/ldb.h"
28
29 struct control_handler {
30         const char *oid;
31         BOOL (*decode)(void *mem_ctx, DATA_BLOB in, void **out);
32         BOOL (*encode)(void *mem_ctx, void *in, DATA_BLOB *out);
33 };
34
35 static BOOL decode_server_sort_response(void *mem_ctx, DATA_BLOB in, void **out)
36 {
37         DATA_BLOB attr;
38         struct asn1_data data;
39         struct ldb_sort_resp_control *lsrc;
40
41         if (!asn1_load(&data, in)) {
42                 return False;
43         }
44
45         lsrc = talloc(mem_ctx, struct ldb_sort_resp_control);
46         if (!lsrc) {
47                 return False;
48         }
49
50         if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
51                 return False;
52         }
53
54         if (!asn1_read_enumerated(&data, &(lsrc->result))) {
55                 return False;
56         }
57
58         lsrc->attr_desc = NULL;
59         if (asn1_peek_tag(&data, ASN1_OCTET_STRING)) {
60                 if (!asn1_read_OctetString(&data, &attr)) {
61                         return False;
62                 }
63                 lsrc->attr_desc = talloc_strndup(lsrc, (const char *)attr.data, attr.length);
64                 if (!lsrc->attr_desc) {
65                         return False;
66                 }
67         }
68
69         if (!asn1_end_tag(&data)) {
70                 return False;
71         }
72
73         *out = lsrc;
74
75         return True;
76 }
77
78 static BOOL decode_server_sort_request(void *mem_ctx, DATA_BLOB in, void **out)
79 {
80         DATA_BLOB attr;
81         DATA_BLOB rule;
82         struct asn1_data data;
83         struct ldb_server_sort_control **lssc;
84         int num;
85
86         if (!asn1_load(&data, in)) {
87                 return False;
88         }
89
90         if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
91                 return False;
92         }
93
94         lssc = NULL;
95
96         for (num = 0; asn1_peek_tag(&data, ASN1_SEQUENCE(0)); num++) {
97                 lssc = talloc_realloc(mem_ctx, lssc, struct ldb_server_sort_control *, num + 2);
98                 if (!lssc) {
99                         return False;
100                 }
101                 lssc[num] = talloc(lssc, struct ldb_server_sort_control);
102                 if (!lssc[num]) {
103                         return False;
104                 }
105
106                 if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
107                         return False;
108                 }
109
110                 if (!asn1_read_OctetString(&data, &attr)) {
111                         return False;
112                 }
113
114                 lssc[num]->attributeName = talloc_strndup(lssc[num], (const char *)attr.data, attr.length);
115                 if (!lssc [num]->attributeName) {
116                         return False;
117                 }
118         
119                 if (asn1_peek_tag(&data, ASN1_OCTET_STRING)) {
120                         if (!asn1_read_OctetString(&data, &rule)) {
121                                 return False;
122                         }
123                         lssc[num]->orderingRule = talloc_strndup(lssc[num], (const char *)rule.data, rule.length);
124                         if (!lssc[num]->orderingRule) {
125                                 return False;
126                         }
127                 }
128
129                 if (asn1_peek_tag(&data, ASN1_BOOLEAN)) {
130                         if (!asn1_read_BOOLEAN(&data, &(lssc[num]->reverse))) {
131                         return False;
132                         }
133                 }
134         
135                 if (!asn1_end_tag(&data)) {
136                         return False;
137                 }
138         }
139
140         lssc[num] = NULL;
141
142         if (!asn1_end_tag(&data)) {
143                 return False;
144         }
145
146         *out = lssc;
147
148         return True;
149 }
150
151 static BOOL decode_extended_dn_request(void *mem_ctx, DATA_BLOB in, void **out)
152 {
153         struct asn1_data data;
154         struct ldb_extended_dn_control *ledc;
155
156         if (!asn1_load(&data, in)) {
157                 return False;
158         }
159
160         ledc = talloc(mem_ctx, struct ldb_extended_dn_control);
161         if (!ledc) {
162                 return False;
163         }
164
165         if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
166                 return False;
167         }
168
169         if (!asn1_read_Integer(&data, &(ledc->type))) {
170                 return False;
171         }
172         
173         if (!asn1_end_tag(&data)) {
174                 return False;
175         }
176
177         *out = ledc;
178
179         return True;
180 }
181
182 static BOOL decode_paged_results_request(void *mem_ctx, DATA_BLOB in, void **out)
183 {
184         DATA_BLOB cookie;
185         struct asn1_data data;
186         struct ldb_paged_control *lprc;
187
188         if (!asn1_load(&data, in)) {
189                 return False;
190         }
191
192         lprc = talloc(mem_ctx, struct ldb_paged_control);
193         if (!lprc) {
194                 return False;
195         }
196
197         if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
198                 return False;
199         }
200
201         if (!asn1_read_Integer(&data, &(lprc->size))) {
202                 return False;
203         }
204         
205         if (!asn1_read_OctetString(&data, &cookie)) {
206                 return False;
207         }
208         lprc->cookie_len = cookie.length;
209         if (lprc->cookie_len) {
210                 lprc->cookie = talloc_memdup(lprc, cookie.data, cookie.length);
211
212                 if (!(lprc->cookie)) {
213                         return False;
214                 }
215         } else {
216                 lprc->cookie = NULL;
217         }
218
219         if (!asn1_end_tag(&data)) {
220                 return False;
221         }
222
223         *out = lprc;
224
225         return True;
226 }
227
228 static BOOL decode_dirsync_request(void *mem_ctx, DATA_BLOB in, void **out)
229 {
230         DATA_BLOB cookie;
231         struct asn1_data data;
232         struct ldb_dirsync_control *ldc;
233
234         if (!asn1_load(&data, in)) {
235                 return False;
236         }
237
238         ldc = talloc(mem_ctx, struct ldb_dirsync_control);
239         if (!ldc) {
240                 return False;
241         }
242
243         if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
244                 return False;
245         }
246
247         if (!asn1_read_Integer(&data, &(ldc->flags))) {
248                 return False;
249         }
250         
251         if (!asn1_read_Integer(&data, &(ldc->max_attributes))) {
252                 return False;
253         }
254         
255         if (!asn1_read_OctetString(&data, &cookie)) {
256                 return False;
257         }
258         ldc->cookie_len = cookie.length;
259         if (ldc->cookie_len) {
260                 ldc->cookie = talloc_memdup(ldc, cookie.data, cookie.length);
261
262                 if (!(ldc->cookie)) {
263                         return False;
264                 }
265         } else {
266                 ldc->cookie = NULL;
267         }
268
269         if (!asn1_end_tag(&data)) {
270                 return False;
271         }
272
273         *out = ldc;
274
275         return True;
276 }
277
278 /* seem that this controls has 2 forms one in case it is used with
279  * a Search Request and another when used ina Search Response
280  */
281 static BOOL decode_asq_control(void *mem_ctx, DATA_BLOB in, void **out)
282 {
283         DATA_BLOB source_attribute;
284         struct asn1_data data;
285         struct ldb_asq_control *lac;
286
287         if (!asn1_load(&data, in)) {
288                 return False;
289         }
290
291         lac = talloc(mem_ctx, struct ldb_asq_control);
292         if (!lac) {
293                 return False;
294         }
295
296         if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
297                 return False;
298         }
299
300         if (asn1_peek_tag(&data, ASN1_OCTET_STRING)) {
301
302                 if (!asn1_read_OctetString(&data, &source_attribute)) {
303                         return False;
304                 }
305                 lac->src_attr_len = source_attribute.length;
306                 if (lac->src_attr_len) {
307                         lac->source_attribute = talloc_strndup(lac, (char *)source_attribute.data, source_attribute.length);
308
309                         if (!(lac->source_attribute)) {
310                                 return False;
311                         }
312                 } else {
313                         lac->source_attribute = NULL;
314                 }
315
316                 lac->request = 1;
317
318         } else if (asn1_peek_tag(&data, ASN1_ENUMERATED)) {
319
320                 if (!asn1_read_enumerated(&data, &(lac->result))) {
321                         return False;
322                 }
323
324                 lac->request = 0;
325
326         } else {
327                 return False;
328         }
329
330         if (!asn1_end_tag(&data)) {
331                 return False;
332         }
333
334         *out = lac;
335
336         return True;
337 }
338
339 static BOOL decode_notification_request(void *mem_ctx, DATA_BLOB in, void **out)
340 {
341         if (in.length != 0) {
342                 return False;
343         }
344
345         return True;
346 }
347
348 static BOOL decode_manageDSAIT_request(void *mem_ctx, DATA_BLOB in, void **out)
349 {
350         if (in.length != 0) {
351                 return False;
352         }
353
354         return True;
355 }
356
357 static BOOL decode_vlv_request(void *mem_ctx, DATA_BLOB in, void **out)
358 {
359         DATA_BLOB assertion_value, context_id;
360         struct asn1_data data;
361         struct ldb_vlv_req_control *lvrc;
362
363         if (!asn1_load(&data, in)) {
364                 return False;
365         }
366
367         lvrc = talloc(mem_ctx, struct ldb_vlv_req_control);
368         if (!lvrc) {
369                 return False;
370         }
371
372         if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
373                 return False;
374         }
375
376         if (!asn1_read_Integer(&data, &(lvrc->beforeCount))) {
377                 return False;
378         }
379         
380         if (!asn1_read_Integer(&data, &(lvrc->afterCount))) {
381                 return False;
382         }
383
384         if (asn1_peek_tag(&data, ASN1_SEQUENCE(0))) {
385
386                 lvrc->type = 0;
387                 
388                 if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
389                         return False;
390                 }
391
392                 if (!asn1_read_Integer(&data, &(lvrc->match.byOffset.offset))) {
393                         return False;
394                 }
395
396                 if (!asn1_read_Integer(&data, &(lvrc->match.byOffset.contentCount))) {
397                         return False;
398                 }
399
400                 if (!asn1_end_tag(&data)) {
401                         return False;
402                 }
403
404         } else {
405
406                 lvrc->type = 1;
407
408                 if (!asn1_read_OctetString(&data, &assertion_value)) {
409                         return False;
410                 }
411                 lvrc->match.gtOrEq.value_len = assertion_value.length;
412                 if (lvrc->match.gtOrEq.value_len) {
413                         lvrc->match.gtOrEq.value = talloc_memdup(lvrc, assertion_value.data, assertion_value.length);
414
415                         if (!(lvrc->match.gtOrEq.value)) {
416                                 return False;
417                         }
418                 } else {
419                         lvrc->match.gtOrEq.value = NULL;
420                 }
421         }
422
423         if (asn1_peek_tag(&data, ASN1_OCTET_STRING)) {
424                 if (!asn1_read_OctetString(&data, &context_id)) {
425                         return False;
426                 }
427                 lvrc->ctxid_len = context_id.length;
428                 if (lvrc->ctxid_len) {
429                         lvrc->contextId = talloc_memdup(lvrc, context_id.data, context_id.length);
430
431                         if (!(lvrc->contextId)) {
432                                 return False;
433                         }
434                 } else {
435                         lvrc->contextId = NULL;
436                 }
437         } else {
438                 lvrc->contextId = NULL;
439                 lvrc->ctxid_len = 0;
440         }
441
442         if (!asn1_end_tag(&data)) {
443                 return False;
444         }
445
446         *out = lvrc;
447
448         return True;
449 }
450
451 static BOOL decode_vlv_response(void *mem_ctx, DATA_BLOB in, void **out)
452 {
453         DATA_BLOB context_id;
454         struct asn1_data data;
455         struct ldb_vlv_resp_control *lvrc;
456
457         if (!asn1_load(&data, in)) {
458                 return False;
459         }
460
461         lvrc = talloc(mem_ctx, struct ldb_vlv_resp_control);
462         if (!lvrc) {
463                 return False;
464         }
465
466         if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
467                 return False;
468         }
469
470         if (!asn1_read_Integer(&data, &(lvrc->targetPosition))) {
471                 return False;
472         }
473         
474         if (!asn1_read_Integer(&data, &(lvrc->contentCount))) {
475                 return False;
476         }
477         
478         if (!asn1_read_enumerated(&data, &(lvrc->vlv_result))) {
479                 return False;
480         }
481
482         if (asn1_peek_tag(&data, ASN1_OCTET_STRING)) {
483                 if (!asn1_read_OctetString(&data, &context_id)) {
484                         return False;
485                 }
486                 lvrc->contextId = talloc_strndup(lvrc, (const char *)context_id.data, context_id.length);
487                 if (!lvrc->contextId) {
488                         return False;
489                 }
490                 lvrc->ctxid_len = context_id.length;
491         } else {
492                 lvrc->contextId = NULL;
493                 lvrc->ctxid_len = 0;
494         }
495
496         if (!asn1_end_tag(&data)) {
497                 return False;
498         }
499
500         *out = lvrc;
501
502         return True;
503 }
504
505 static BOOL encode_server_sort_response(void *mem_ctx, void *in, DATA_BLOB *out)
506 {
507         struct ldb_sort_resp_control *lsrc = talloc_get_type(in, struct ldb_sort_resp_control);
508         struct asn1_data data;
509
510         ZERO_STRUCT(data);
511
512         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
513                 return False;
514         }
515
516         if (!asn1_write_enumerated(&data, lsrc->result)) {
517                 return False;
518         }
519
520         if (lsrc->attr_desc) {
521                 if (!asn1_write_OctetString(&data, lsrc->attr_desc, strlen(lsrc->attr_desc))) {
522                         return False;
523                 }
524         }
525
526         if (!asn1_pop_tag(&data)) {
527                 return False;
528         }
529
530         *out = data_blob_talloc(mem_ctx, data.data, data.length);
531         if (out->data == NULL) {
532                 return False;
533         }
534
535         return True;
536 }
537
538 static BOOL encode_server_sort_request(void *mem_ctx, void *in, DATA_BLOB *out)
539 {
540         struct ldb_server_sort_control **lssc = talloc_get_type(in, struct ldb_server_sort_control *);
541         struct asn1_data data;
542         int num;
543
544         ZERO_STRUCT(data);
545
546         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
547                 return False;
548         }
549
550         for (num = 0; lssc[num]; num++) {
551                 if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
552                         return False;
553                 }
554                 
555                 if (!asn1_write_OctetString(&data, lssc[num]->attributeName, strlen(lssc[num]->attributeName))) {
556                         return False;
557                 }
558
559                 if (lssc[num]->orderingRule) {
560                         if (!asn1_write_OctetString(&data, lssc[num]->orderingRule, strlen(lssc[num]->orderingRule))) {
561                                 return False;
562                         }
563                 }
564
565                 if (lssc[num]->reverse) {
566                         if (!asn1_write_BOOLEAN(&data, lssc[num]->reverse)) {
567                                 return False;
568                         }
569                 }
570
571                 if (!asn1_pop_tag(&data)) {
572                         return False;
573                 }
574         }
575
576         if (!asn1_pop_tag(&data)) {
577                 return False;
578         }
579
580         *out = data_blob_talloc(mem_ctx, data.data, data.length);
581         if (out->data == NULL) {
582                 return False;
583         }
584
585         return True;
586 }
587
588 static BOOL encode_extended_dn_request(void *mem_ctx, void *in, DATA_BLOB *out)
589 {
590         struct ldb_extended_dn_control *ledc = talloc_get_type(in, struct ldb_extended_dn_control);
591         struct asn1_data data;
592
593         ZERO_STRUCT(data);
594
595         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
596                 return False;
597         }
598
599         if (!asn1_write_Integer(&data, ledc->type)) {
600                 return False;
601         }
602
603         if (!asn1_pop_tag(&data)) {
604                 return False;
605         }
606
607         *out = data_blob_talloc(mem_ctx, data.data, data.length);
608         if (out->data == NULL) {
609                 return False;
610         }
611
612         return True;
613 }
614
615 static BOOL encode_paged_results_request(void *mem_ctx, void *in, DATA_BLOB *out)
616 {
617         struct ldb_paged_control *lprc = talloc_get_type(in, struct ldb_paged_control);
618         struct asn1_data data;
619
620         ZERO_STRUCT(data);
621
622         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
623                 return False;
624         }
625
626         if (!asn1_write_Integer(&data, lprc->size)) {
627                 return False;
628         }
629
630         if (!asn1_write_OctetString(&data, lprc->cookie, lprc->cookie_len)) {
631                 return False;
632         }       
633
634         if (!asn1_pop_tag(&data)) {
635                 return False;
636         }
637
638         *out = data_blob_talloc(mem_ctx, data.data, data.length);
639         if (out->data == NULL) {
640                 return False;
641         }
642
643         return True;
644 }
645
646 /* seem that this controls has 2 forms one in case it is used with
647  * a Search Request and another when used ina Search Response
648  */
649 static BOOL encode_asq_control(void *mem_ctx, void *in, DATA_BLOB *out)
650 {
651         struct ldb_asq_control *lac = talloc_get_type(in, struct ldb_asq_control);
652         struct asn1_data data;
653
654         ZERO_STRUCT(data);
655
656         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
657                 return False;
658         }
659
660         if (lac->request) {
661
662                 if (!asn1_write_OctetString(&data, lac->source_attribute, lac->src_attr_len)) {
663                         return False;
664                 }
665         } else {
666                 if (!asn1_write_enumerated(&data, lac->result)) {
667                         return False;
668                 }
669         }
670
671         if (!asn1_pop_tag(&data)) {
672                 return False;
673         }
674
675         *out = data_blob_talloc(mem_ctx, data.data, data.length);
676         if (out->data == NULL) {
677                 return False;
678         }
679
680         return True;
681 }
682
683 static BOOL encode_dirsync_request(void *mem_ctx, void *in, DATA_BLOB *out)
684 {
685         struct ldb_dirsync_control *ldc = talloc_get_type(in, struct ldb_dirsync_control);
686         struct asn1_data data;
687
688         ZERO_STRUCT(data);
689
690         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
691                 return False;
692         }
693
694         if (!asn1_write_Integer(&data, ldc->flags)) {
695                 return False;
696         }
697
698         if (!asn1_write_Integer(&data, ldc->max_attributes)) {
699                 return False;
700         }
701
702         if (!asn1_write_OctetString(&data, ldc->cookie, ldc->cookie_len)) {
703                 return False;
704         }       
705
706         if (!asn1_pop_tag(&data)) {
707                 return False;
708         }
709
710         *out = data_blob_talloc(mem_ctx, data.data, data.length);
711         if (out->data == NULL) {
712                 return False;
713         }
714
715         return True;
716 }
717
718 static BOOL encode_notification_request(void *mem_ctx, void *in, DATA_BLOB *out)
719 {
720         if (in) {
721                 return False;
722         }
723
724         *out = data_blob(NULL, 0);
725         return True;
726 }
727
728 static BOOL encode_manageDSAIT_request(void *mem_ctx, void *in, DATA_BLOB *out)
729 {
730         if (in) {
731                 return False;
732         }
733
734         *out = data_blob(NULL, 0);
735         return True;
736 }
737
738 static BOOL encode_vlv_request(void *mem_ctx, void *in, DATA_BLOB *out)
739 {
740         struct ldb_vlv_req_control *lvrc = talloc_get_type(in, struct ldb_vlv_req_control);
741         struct asn1_data data;
742
743         ZERO_STRUCT(data);
744
745         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
746                 return False;
747         }
748
749         if (!asn1_write_Integer(&data, lvrc->beforeCount)) {
750                 return False;
751         }
752
753         if (!asn1_write_Integer(&data, lvrc->afterCount)) {
754                 return False;
755         }
756
757         if (lvrc->type == 0) {
758                 if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
759                         return False;
760                 }
761                 
762                 if (!asn1_write_Integer(&data, lvrc->match.byOffset.offset)) {
763                         return False;
764                 }
765
766                 if (!asn1_write_Integer(&data, lvrc->match.byOffset.contentCount)) {
767                         return False;
768                 }
769
770                 if (!asn1_pop_tag(&data)) {
771                         return False;
772                 }
773         } else {
774                 
775                 if (!asn1_write_OctetString(&data, lvrc->match.gtOrEq.value, lvrc->match.gtOrEq.value_len)) {
776                         return False;
777                 }
778         }
779
780         if (lvrc->ctxid_len) {
781                 if (!asn1_write_OctetString(&data, lvrc->contextId, lvrc->ctxid_len)) {
782                         return False;
783                 }
784         }
785
786         if (!asn1_pop_tag(&data)) {
787                 return False;
788         }
789
790         *out = data_blob_talloc(mem_ctx, data.data, data.length);
791         if (out->data == NULL) {
792                 return False;
793         }
794
795         return True;
796 }
797
798 static BOOL encode_vlv_response(void *mem_ctx, void *in, DATA_BLOB *out)
799 {
800         struct ldb_vlv_resp_control *lvrc = talloc_get_type(in, struct ldb_vlv_resp_control);
801         struct asn1_data data;
802
803         ZERO_STRUCT(data);
804
805         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
806                 return False;
807         }
808
809         if (!asn1_write_Integer(&data, lvrc->targetPosition)) {
810                 return False;
811         }
812
813         if (!asn1_write_Integer(&data, lvrc->contentCount)) {
814                 return False;
815         }
816
817         if (!asn1_write_enumerated(&data, lvrc->vlv_result)) {
818                 return False;
819         }
820
821         if (lvrc->ctxid_len) {
822                 if (!asn1_write_OctetString(&data, lvrc->contextId, lvrc->ctxid_len)) {
823                         return False;
824                 }
825         }
826
827         if (!asn1_pop_tag(&data)) {
828                 return False;
829         }
830
831         *out = data_blob_talloc(mem_ctx, data.data, data.length);
832         if (out->data == NULL) {
833                 return False;
834         }
835
836         return True;
837 }
838
839 struct control_handler ldap_known_controls[] = {
840         { "1.2.840.113556.1.4.319", decode_paged_results_request, encode_paged_results_request },
841         { "1.2.840.113556.1.4.529", decode_extended_dn_request, encode_extended_dn_request },
842         { "1.2.840.113556.1.4.473", decode_server_sort_request, encode_server_sort_request },
843         { "1.2.840.113556.1.4.474", decode_server_sort_response, encode_server_sort_response },
844         { "1.2.840.113556.1.4.1504", decode_asq_control, encode_asq_control },
845         { "1.2.840.113556.1.4.841", decode_dirsync_request, encode_dirsync_request },
846         { "1.2.840.113556.1.4.528", decode_notification_request, encode_notification_request },
847         { "2.16.840.1.113730.3.4.2", decode_manageDSAIT_request, encode_manageDSAIT_request },
848         { "2.16.840.1.113730.3.4.9", decode_vlv_request, encode_vlv_request },
849         { "2.16.840.1.113730.3.4.10", decode_vlv_response, encode_vlv_response },
850         { NULL, NULL, NULL }
851 };
852
853 BOOL ldap_decode_control(void *mem_ctx, struct asn1_data *data, struct ldap_Control *ctrl)
854 {
855         int i;
856         DATA_BLOB oid;
857         DATA_BLOB value;
858
859         if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
860                 return False;
861         }
862
863         if (!asn1_read_OctetString(data, &oid)) {
864                 return False;
865         }
866         ctrl->oid = talloc_strndup(mem_ctx, (char *)oid.data, oid.length);
867         if (!(ctrl->oid)) {
868                 return False;
869         }
870
871         if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
872                 if (!asn1_read_BOOLEAN(data, &(ctrl->critical))) {
873                         return False;
874                 }
875         } else {
876                 ctrl->critical = False;
877         }
878
879         ctrl->value = NULL;
880
881         for (i = 0; ldap_known_controls[i].oid != NULL; i++) {
882                 if (strcmp(ldap_known_controls[i].oid, ctrl->oid) == 0) {
883                         
884                         if (!asn1_read_OctetString(data, &value)) {
885                                 return False;
886                         }
887                         if (!ldap_known_controls[i].decode(mem_ctx, value, &(ctrl->value))) {
888                                 return False;
889                         }
890                         break;
891                 }
892         }
893         if (ldap_known_controls[i].oid == NULL) {
894                 return False;
895         }
896
897         if (!asn1_end_tag(data)) {
898                 return False;
899         }
900
901         return True;
902 }
903
904 BOOL ldap_encode_control(void *mem_ctx, struct asn1_data *data, struct ldap_Control *ctrl)
905 {
906         DATA_BLOB value;
907         int i;
908
909         if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
910                 return False;
911         }
912         
913         if (!asn1_write_OctetString(data, ctrl->oid, strlen(ctrl->oid))) {
914                 return False;
915         }
916         
917         if (ctrl->critical) {
918                 if (!asn1_write_BOOLEAN(data, ctrl->critical)) {
919                         return False;
920                 }
921         }
922
923         for (i = 0; ldap_known_controls[i].oid != NULL; i++) {
924                 if (strcmp(ldap_known_controls[i].oid, ctrl->oid) == 0) {
925                         if (!ldap_known_controls[i].encode(mem_ctx, ctrl->value, &value)) {
926                                 return False;
927                         }
928                         break;
929                 }
930         }
931         if (ldap_known_controls[i].oid == NULL) {
932                 return False;
933         }
934
935         if (value.length != 0) {
936                 if (!asn1_write_OctetString(data, value.data, value.length)) {
937                         return False;
938                 }
939         }
940
941         if (!asn1_pop_tag(data)) {
942                 return False;
943         }
944
945         return True;
946 }