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