r12925: implement client side of ASQ control
[sfrench/samba-autobuild/.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, 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], 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], 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 /* seem that this controls has 2 forms one in case it is used with
229  * a Search Request and another when used ina Search Response
230  */
231 static BOOL decode_asq_control(void *mem_ctx, DATA_BLOB in, void **out)
232 {
233         DATA_BLOB source_attribute;
234         struct asn1_data data;
235         struct ldb_asq_control *lac;
236
237         if (!asn1_load(&data, in)) {
238                 return False;
239         }
240
241         lac = talloc(mem_ctx, struct ldb_asq_control);
242         if (!lac) {
243                 return False;
244         }
245
246         if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
247                 return False;
248         }
249
250         if (asn1_peek_tag(&data, ASN1_OCTET_STRING)) {
251
252                 if (!asn1_read_OctetString(&data, &source_attribute)) {
253                         return False;
254                 }
255                 lac->src_attr_len = source_attribute.length;
256                 if (lac->src_attr_len) {
257                         lac->source_attribute = talloc_memdup(lac, source_attribute.data, source_attribute.length);
258
259                         if (!(lac->source_attribute)) {
260                                 return False;
261                         }
262                 } else {
263                         lac->source_attribute = NULL;
264                 }
265
266                 lac->request = 1;
267
268         } else if (asn1_peek_tag(&data, ASN1_ENUMERATED)) {
269
270                 if (!asn1_read_enumerated(&data, &(lac->result))) {
271                         return False;
272                 }
273
274                 lac->request = 0;
275
276         } else {
277                 return False;
278         }
279
280         if (!asn1_end_tag(&data)) {
281                 return False;
282         }
283
284         *out = lac;
285
286         return True;
287 }
288
289 static BOOL encode_server_sort_response(void *mem_ctx, void *in, DATA_BLOB *out)
290 {
291         struct ldb_sort_resp_control *lsrc = talloc_get_type(in, struct ldb_sort_resp_control);
292         struct asn1_data data;
293
294         ZERO_STRUCT(data);
295
296         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
297                 return False;
298         }
299
300         if (!asn1_write_enumerated(&data, lsrc->result)) {
301                 return False;
302         }
303
304         if (lsrc->attr_desc) {
305                 if (!asn1_write_OctetString(&data, lsrc->attr_desc, strlen(lsrc->attr_desc))) {
306                         return False;
307                 }
308         }
309
310         if (!asn1_pop_tag(&data)) {
311                 return False;
312         }
313
314         *out = data_blob_talloc(mem_ctx, data.data, data.length);
315         if (out->data == NULL) {
316                 return False;
317         }
318
319         return True;
320 }
321
322 static BOOL encode_server_sort_request(void *mem_ctx, void *in, DATA_BLOB *out)
323 {
324         struct ldb_server_sort_control **lssc = talloc_get_type(in, struct ldb_server_sort_control *);
325         struct asn1_data data;
326         int num;
327
328         ZERO_STRUCT(data);
329
330         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
331                 return False;
332         }
333
334         for (num = 0; lssc[num]; num++) {
335                 if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
336                         return False;
337                 }
338                 
339                 if (!asn1_write_OctetString(&data, lssc[num]->attributeName, strlen(lssc[num]->attributeName))) {
340                         return False;
341                 }
342
343                 if (lssc[num]->orderingRule) {
344                         if (!asn1_write_OctetString(&data, lssc[num]->orderingRule, strlen(lssc[num]->orderingRule))) {
345                                 return False;
346                         }
347                 }
348
349                 if (lssc[num]->reverse) {
350                         if (!asn1_write_BOOLEAN(&data, lssc[num]->reverse)) {
351                                 return False;
352                         }
353                 }
354
355                 if (!asn1_pop_tag(&data)) {
356                         return False;
357                 }
358         }
359
360         if (!asn1_pop_tag(&data)) {
361                 return False;
362         }
363
364         *out = data_blob_talloc(mem_ctx, data.data, data.length);
365         if (out->data == NULL) {
366                 return False;
367         }
368
369         return True;
370 }
371
372 static BOOL encode_extended_dn_request(void *mem_ctx, void *in, DATA_BLOB *out)
373 {
374         struct ldb_extended_dn_control *ledc = talloc_get_type(in, struct ldb_extended_dn_control);
375         struct asn1_data data;
376
377         ZERO_STRUCT(data);
378
379         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
380                 return False;
381         }
382
383         if (!asn1_write_Integer(&data, ledc->type)) {
384                 return False;
385         }
386
387         if (!asn1_pop_tag(&data)) {
388                 return False;
389         }
390
391         *out = data_blob_talloc(mem_ctx, data.data, data.length);
392         if (out->data == NULL) {
393                 return False;
394         }
395
396         return True;
397 }
398
399 static BOOL encode_paged_results_request(void *mem_ctx, void *in, DATA_BLOB *out)
400 {
401         struct ldb_paged_control *lprc = talloc_get_type(in, struct ldb_paged_control);
402         struct asn1_data data;
403
404         ZERO_STRUCT(data);
405
406         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
407                 return False;
408         }
409
410         if (!asn1_write_Integer(&data, lprc->size)) {
411                 return False;
412         }
413
414         if (!asn1_write_OctetString(&data, lprc->cookie, lprc->cookie_len)) {
415                 return False;
416         }       
417
418         if (!asn1_pop_tag(&data)) {
419                 return False;
420         }
421
422         *out = data_blob_talloc(mem_ctx, data.data, data.length);
423         if (out->data == NULL) {
424                 return False;
425         }
426
427         return True;
428 }
429
430 /* seem that this controls has 2 forms one in case it is used with
431  * a Search Request and another when used ina Search Response
432  */
433 static BOOL encode_asq_control(void *mem_ctx, void *in, DATA_BLOB *out)
434 {
435         struct ldb_asq_control *lac = talloc_get_type(in, struct ldb_asq_control);
436         struct asn1_data data;
437
438         ZERO_STRUCT(data);
439
440         if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
441                 return False;
442         }
443
444         if (lac->request) {
445
446                 if (!asn1_write_OctetString(&data, lac->source_attribute, lac->src_attr_len)) {
447                         return False;
448                 }
449         } else {
450                 if (!asn1_write_enumerated(&data, lac->result)) {
451                         return False;
452                 }
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 struct control_handler ldap_known_controls[] = {
468         { "1.2.840.113556.1.4.319", decode_paged_results_request, encode_paged_results_request },
469         { "1.2.840.113556.1.4.529", decode_extended_dn_request, encode_extended_dn_request },
470         { "1.2.840.113556.1.4.473", decode_server_sort_request, encode_server_sort_request },
471         { "1.2.840.113556.1.4.474", decode_server_sort_response, encode_server_sort_response },
472         { "1.2.840.113556.1.4.1504", decode_asq_control, encode_asq_control },
473         { NULL, NULL, NULL }
474 };
475
476 BOOL ldap_decode_control(void *mem_ctx, struct asn1_data *data, struct ldap_Control *ctrl)
477 {
478         int i;
479         DATA_BLOB oid;
480         DATA_BLOB value;
481
482         if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
483                 return False;
484         }
485
486         if (!asn1_read_OctetString(data, &oid)) {
487                 return False;
488         }
489         ctrl->oid = talloc_strndup(mem_ctx, (char *)oid.data, oid.length);
490         if (!(ctrl->oid)) {
491                 return False;
492         }
493
494         if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
495                 if (!asn1_read_BOOLEAN(data, &(ctrl->critical))) {
496                         return False;
497                 }
498         } else {
499                 ctrl->critical = False;
500         }
501
502         ctrl->value = NULL;
503
504         for (i = 0; ldap_known_controls[i].oid != NULL; i++) {
505                 if (strcmp(ldap_known_controls[i].oid, ctrl->oid) == 0) {
506                         
507                         if (!asn1_read_OctetString(data, &value)) {
508                                 return False;
509                         }
510                         if (!ldap_known_controls[i].decode(mem_ctx, value, &(ctrl->value))) {
511                                 return False;
512                         }
513                         break;
514                 }
515         }
516         if (ldap_known_controls[i].oid == NULL) {
517                 return False;
518         }
519
520         if (!asn1_end_tag(data)) {
521                 return False;
522         }
523
524         return True;
525 }
526
527 BOOL ldap_encode_control(void *mem_ctx, struct asn1_data *data, struct ldap_Control *ctrl)
528 {
529         DATA_BLOB value;
530         int i;
531
532         if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
533                 return False;
534         }
535         
536         if (!asn1_write_OctetString(data, ctrl->oid, strlen(ctrl->oid))) {
537                 return False;
538         }
539         
540         if (ctrl->critical) {
541                 if (!asn1_write_BOOLEAN(data, ctrl->critical)) {
542                         return False;
543                 }
544         }
545
546         for (i = 0; ldap_known_controls[i].oid != NULL; i++) {
547                 if (strcmp(ldap_known_controls[i].oid, ctrl->oid) == 0) {
548                         if (!ldap_known_controls[i].encode(mem_ctx, ctrl->value, &value)) {
549                                 return False;
550                         }
551                         break;
552                 }
553         }
554         if (ldap_known_controls[i].oid == NULL) {
555                 return False;
556         }
557
558         if (value.length != 0) {
559                 if (!asn1_write_OctetString(data, value.data, value.length)) {
560                         return False;
561                 }
562         }
563
564         if (!asn1_pop_tag(data)) {
565                 return False;
566         }
567
568         return True;
569 }