r13354: Add tests to check that controls work properly
[vlendec/samba-autobuild/.git] / source4 / 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, 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 encode_server_sort_response(void *mem_ctx, void *in, DATA_BLOB *out)
358 {
359         struct ldb_sort_resp_control *lsrc = talloc_get_type(in, struct ldb_sort_resp_control);
360         struct asn1_data data;
361
362         ZERO_STRUCT(data);
363
364         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
365                 return False;
366         }
367
368         if (!asn1_write_enumerated(&data, lsrc->result)) {
369                 return False;
370         }
371
372         if (lsrc->attr_desc) {
373                 if (!asn1_write_OctetString(&data, lsrc->attr_desc, strlen(lsrc->attr_desc))) {
374                         return False;
375                 }
376         }
377
378         if (!asn1_pop_tag(&data)) {
379                 return False;
380         }
381
382         *out = data_blob_talloc(mem_ctx, data.data, data.length);
383         if (out->data == NULL) {
384                 return False;
385         }
386
387         return True;
388 }
389
390 static BOOL encode_server_sort_request(void *mem_ctx, void *in, DATA_BLOB *out)
391 {
392         struct ldb_server_sort_control **lssc = talloc_get_type(in, struct ldb_server_sort_control *);
393         struct asn1_data data;
394         int num;
395
396         ZERO_STRUCT(data);
397
398         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
399                 return False;
400         }
401
402         for (num = 0; lssc[num]; num++) {
403                 if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
404                         return False;
405                 }
406                 
407                 if (!asn1_write_OctetString(&data, lssc[num]->attributeName, strlen(lssc[num]->attributeName))) {
408                         return False;
409                 }
410
411                 if (lssc[num]->orderingRule) {
412                         if (!asn1_write_OctetString(&data, lssc[num]->orderingRule, strlen(lssc[num]->orderingRule))) {
413                                 return False;
414                         }
415                 }
416
417                 if (lssc[num]->reverse) {
418                         if (!asn1_write_BOOLEAN(&data, lssc[num]->reverse)) {
419                                 return False;
420                         }
421                 }
422
423                 if (!asn1_pop_tag(&data)) {
424                         return False;
425                 }
426         }
427
428         if (!asn1_pop_tag(&data)) {
429                 return False;
430         }
431
432         *out = data_blob_talloc(mem_ctx, data.data, data.length);
433         if (out->data == NULL) {
434                 return False;
435         }
436
437         return True;
438 }
439
440 static BOOL encode_extended_dn_request(void *mem_ctx, void *in, DATA_BLOB *out)
441 {
442         struct ldb_extended_dn_control *ledc = talloc_get_type(in, struct ldb_extended_dn_control);
443         struct asn1_data data;
444
445         ZERO_STRUCT(data);
446
447         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
448                 return False;
449         }
450
451         if (!asn1_write_Integer(&data, ledc->type)) {
452                 return False;
453         }
454
455         if (!asn1_pop_tag(&data)) {
456                 return False;
457         }
458
459         *out = data_blob_talloc(mem_ctx, data.data, data.length);
460         if (out->data == NULL) {
461                 return False;
462         }
463
464         return True;
465 }
466
467 static BOOL encode_paged_results_request(void *mem_ctx, void *in, DATA_BLOB *out)
468 {
469         struct ldb_paged_control *lprc = talloc_get_type(in, struct ldb_paged_control);
470         struct asn1_data data;
471
472         ZERO_STRUCT(data);
473
474         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
475                 return False;
476         }
477
478         if (!asn1_write_Integer(&data, lprc->size)) {
479                 return False;
480         }
481
482         if (!asn1_write_OctetString(&data, lprc->cookie, lprc->cookie_len)) {
483                 return False;
484         }       
485
486         if (!asn1_pop_tag(&data)) {
487                 return False;
488         }
489
490         *out = data_blob_talloc(mem_ctx, data.data, data.length);
491         if (out->data == NULL) {
492                 return False;
493         }
494
495         return True;
496 }
497
498 /* seem that this controls has 2 forms one in case it is used with
499  * a Search Request and another when used ina Search Response
500  */
501 static BOOL encode_asq_control(void *mem_ctx, void *in, DATA_BLOB *out)
502 {
503         struct ldb_asq_control *lac = talloc_get_type(in, struct ldb_asq_control);
504         struct asn1_data data;
505
506         ZERO_STRUCT(data);
507
508         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
509                 return False;
510         }
511
512         if (lac->request) {
513
514                 if (!asn1_write_OctetString(&data, lac->source_attribute, lac->src_attr_len)) {
515                         return False;
516                 }
517         } else {
518                 if (!asn1_write_enumerated(&data, lac->result)) {
519                         return False;
520                 }
521         }
522
523         if (!asn1_pop_tag(&data)) {
524                 return False;
525         }
526
527         *out = data_blob_talloc(mem_ctx, data.data, data.length);
528         if (out->data == NULL) {
529                 return False;
530         }
531
532         return True;
533 }
534
535 static BOOL encode_dirsync_request(void *mem_ctx, void *in, DATA_BLOB *out)
536 {
537         struct ldb_dirsync_control *ldc = talloc_get_type(in, struct ldb_dirsync_control);
538         struct asn1_data data;
539
540         ZERO_STRUCT(data);
541
542         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
543                 return False;
544         }
545
546         if (!asn1_write_Integer(&data, ldc->flags)) {
547                 return False;
548         }
549
550         if (!asn1_write_Integer(&data, ldc->max_attributes)) {
551                 return False;
552         }
553
554         if (!asn1_write_OctetString(&data, ldc->cookie, ldc->cookie_len)) {
555                 return False;
556         }       
557
558         if (!asn1_pop_tag(&data)) {
559                 return False;
560         }
561
562         *out = data_blob_talloc(mem_ctx, data.data, data.length);
563         if (out->data == NULL) {
564                 return False;
565         }
566
567         return True;
568 }
569
570 static BOOL encode_notification_request(void *mem_ctx, void *in, DATA_BLOB *out)
571 {
572         if (in) {
573                 return False;
574         }
575
576         *out = data_blob(NULL, 0);
577         return True;
578 }
579
580 static BOOL encode_manageDSAIT_request(void *mem_ctx, void *in, DATA_BLOB *out)
581 {
582         if (in) {
583                 return False;
584         }
585
586         *out = data_blob(NULL, 0);
587         return True;
588 }
589
590 struct control_handler ldap_known_controls[] = {
591         { "1.2.840.113556.1.4.319", decode_paged_results_request, encode_paged_results_request },
592         { "1.2.840.113556.1.4.529", decode_extended_dn_request, encode_extended_dn_request },
593         { "1.2.840.113556.1.4.473", decode_server_sort_request, encode_server_sort_request },
594         { "1.2.840.113556.1.4.474", decode_server_sort_response, encode_server_sort_response },
595         { "1.2.840.113556.1.4.1504", decode_asq_control, encode_asq_control },
596         { "1.2.840.113556.1.4.841", decode_dirsync_request, encode_dirsync_request },
597         { "1.2.840.113556.1.4.528", decode_notification_request, encode_notification_request },
598         { "2.16.840.1.113730.3.4.2", decode_manageDSAIT_request, encode_manageDSAIT_request },
599         { NULL, NULL, NULL }
600 };
601
602 BOOL ldap_decode_control(void *mem_ctx, struct asn1_data *data, struct ldap_Control *ctrl)
603 {
604         int i;
605         DATA_BLOB oid;
606         DATA_BLOB value;
607
608         if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
609                 return False;
610         }
611
612         if (!asn1_read_OctetString(data, &oid)) {
613                 return False;
614         }
615         ctrl->oid = talloc_strndup(mem_ctx, (char *)oid.data, oid.length);
616         if (!(ctrl->oid)) {
617                 return False;
618         }
619
620         if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
621                 if (!asn1_read_BOOLEAN(data, &(ctrl->critical))) {
622                         return False;
623                 }
624         } else {
625                 ctrl->critical = False;
626         }
627
628         ctrl->value = NULL;
629
630         for (i = 0; ldap_known_controls[i].oid != NULL; i++) {
631                 if (strcmp(ldap_known_controls[i].oid, ctrl->oid) == 0) {
632                         
633                         if (!asn1_read_OctetString(data, &value)) {
634                                 return False;
635                         }
636                         if (!ldap_known_controls[i].decode(mem_ctx, value, &(ctrl->value))) {
637                                 return False;
638                         }
639                         break;
640                 }
641         }
642         if (ldap_known_controls[i].oid == NULL) {
643                 return False;
644         }
645
646         if (!asn1_end_tag(data)) {
647                 return False;
648         }
649
650         return True;
651 }
652
653 BOOL ldap_encode_control(void *mem_ctx, struct asn1_data *data, struct ldap_Control *ctrl)
654 {
655         DATA_BLOB value;
656         int i;
657
658         if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
659                 return False;
660         }
661         
662         if (!asn1_write_OctetString(data, ctrl->oid, strlen(ctrl->oid))) {
663                 return False;
664         }
665         
666         if (ctrl->critical) {
667                 if (!asn1_write_BOOLEAN(data, ctrl->critical)) {
668                         return False;
669                 }
670         }
671
672         for (i = 0; ldap_known_controls[i].oid != NULL; i++) {
673                 if (strcmp(ldap_known_controls[i].oid, ctrl->oid) == 0) {
674                         if (!ldap_known_controls[i].encode(mem_ctx, ctrl->value, &value)) {
675                                 return False;
676                         }
677                         break;
678                 }
679         }
680         if (ldap_known_controls[i].oid == NULL) {
681                 return False;
682         }
683
684         if (value.length != 0) {
685                 if (!asn1_write_OctetString(data, value.data, value.length)) {
686                         return False;
687                 }
688         }
689
690         if (!asn1_pop_tag(data)) {
691                 return False;
692         }
693
694         return True;
695 }