r7524: make the ldap ASN.1 filter parse code go via a struct
[Samba.git] / source / libcli / ldap / ldap.c
blob2718dd7e34031855238ce276d0b67bf452f8bc08
1 /*
2 Unix SMB/CIFS mplementation.
3 LDAP protocol helper functions for SAMBA
5 Copyright (C) Andrew Tridgell 2004
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Stefan Metzmacher 2004
8 Copyright (C) Simo Sorce 2004
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "includes.h"
27 #include "system/iconv.h"
28 #include "asn_1.h"
29 #include "libcli/ldap/ldap.h"
32 static BOOL ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree)
34 switch (tree->operation) {
35 case LDB_OP_SIMPLE: {
36 if ((tree->u.simple.value.length == 1) &&
37 (((char *)(tree->u.simple.value.data))[0] == '*')) {
38 /* Just a presence test */
39 asn1_push_tag(data, 0x87);
40 asn1_write(data, tree->u.simple.attr,
41 strlen(tree->u.simple.attr));
42 asn1_pop_tag(data);
43 return !data->has_error;
46 /* Equality is all we currently do... */
47 asn1_push_tag(data, 0xa3);
48 asn1_write_OctetString(data, tree->u.simple.attr,
49 strlen(tree->u.simple.attr));
50 asn1_write_OctetString(data, tree->u.simple.value.data,
51 tree->u.simple.value.length);
52 asn1_pop_tag(data);
53 break;
56 case LDB_OP_AND: {
57 int i;
59 asn1_push_tag(data, 0xa0);
60 for (i=0; i<tree->u.list.num_elements; i++) {
61 ldap_push_filter(data, tree->u.list.elements[i]);
63 asn1_pop_tag(data);
64 break;
67 case LDB_OP_OR: {
68 int i;
70 asn1_push_tag(data, 0xa1);
71 for (i=0; i<tree->u.list.num_elements; i++) {
72 ldap_push_filter(data, tree->u.list.elements[i]);
74 asn1_pop_tag(data);
75 break;
77 default:
78 return False;
80 return !data->has_error;
83 static void ldap_encode_response(struct asn1_data *data, struct ldap_Result *result)
85 asn1_write_enumerated(data, result->resultcode);
86 asn1_write_OctetString(data, result->dn,
87 (result->dn) ? strlen(result->dn) : 0);
88 asn1_write_OctetString(data, result->errormessage,
89 (result->errormessage) ?
90 strlen(result->errormessage) : 0);
91 if (result->referral) {
92 asn1_push_tag(data, ASN1_CONTEXT(3));
93 asn1_write_OctetString(data, result->referral,
94 strlen(result->referral));
95 asn1_pop_tag(data);
99 BOOL ldap_encode(struct ldap_message *msg, DATA_BLOB *result)
101 struct asn1_data data;
102 int i, j;
104 ZERO_STRUCT(data);
105 asn1_push_tag(&data, ASN1_SEQUENCE(0));
106 asn1_write_Integer(&data, msg->messageid);
108 switch (msg->type) {
109 case LDAP_TAG_BindRequest: {
110 struct ldap_BindRequest *r = &msg->r.BindRequest;
111 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
112 asn1_write_Integer(&data, r->version);
113 asn1_write_OctetString(&data, r->dn,
114 (r->dn != NULL) ? strlen(r->dn) : 0);
116 switch (r->mechanism) {
117 case LDAP_AUTH_MECH_SIMPLE:
118 /* context, primitive */
119 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
120 asn1_write(&data, r->creds.password,
121 strlen(r->creds.password));
122 asn1_pop_tag(&data);
123 break;
124 case LDAP_AUTH_MECH_SASL:
125 /* context, constructed */
126 asn1_push_tag(&data, ASN1_CONTEXT(3));
127 asn1_write_OctetString(&data, r->creds.SASL.mechanism,
128 strlen(r->creds.SASL.mechanism));
129 asn1_write_OctetString(&data, r->creds.SASL.secblob.data,
130 r->creds.SASL.secblob.length);
131 asn1_pop_tag(&data);
132 break;
133 default:
134 return False;
137 asn1_pop_tag(&data);
138 asn1_pop_tag(&data);
139 break;
141 case LDAP_TAG_BindResponse: {
142 struct ldap_BindResponse *r = &msg->r.BindResponse;
143 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
144 ldap_encode_response(&data, &r->response);
145 asn1_write_ContextSimple(&data, 7, &r->SASL.secblob);
146 asn1_pop_tag(&data);
147 break;
149 case LDAP_TAG_UnbindRequest: {
150 /* struct ldap_UnbindRequest *r = &msg->r.UnbindRequest; */
151 break;
153 case LDAP_TAG_SearchRequest: {
154 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
155 struct ldb_parse_tree *tree;
156 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
157 asn1_write_OctetString(&data, r->basedn, strlen(r->basedn));
158 asn1_write_enumerated(&data, r->scope);
159 asn1_write_enumerated(&data, r->deref);
160 asn1_write_Integer(&data, r->sizelimit);
161 asn1_write_Integer(&data, r->timelimit);
162 asn1_write_BOOLEAN(&data, r->attributesonly);
164 tree = ldb_parse_tree(NULL, r->filter);
166 if (tree == NULL)
167 return False;
169 ldap_push_filter(&data, tree);
171 talloc_free(tree);
173 asn1_push_tag(&data, ASN1_SEQUENCE(0));
174 for (i=0; i<r->num_attributes; i++) {
175 asn1_write_OctetString(&data, r->attributes[i],
176 strlen(r->attributes[i]));
178 asn1_pop_tag(&data);
180 asn1_pop_tag(&data);
181 break;
183 case LDAP_TAG_SearchResultEntry: {
184 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
185 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
186 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
187 asn1_push_tag(&data, ASN1_SEQUENCE(0));
188 for (i=0; i<r->num_attributes; i++) {
189 struct ldap_attribute *attr = &r->attributes[i];
190 asn1_push_tag(&data, ASN1_SEQUENCE(0));
191 asn1_write_OctetString(&data, attr->name,
192 strlen(attr->name));
193 asn1_push_tag(&data, ASN1_SEQUENCE(1));
194 for (j=0; j<attr->num_values; j++) {
195 asn1_write_OctetString(&data,
196 attr->values[j].data,
197 attr->values[j].length);
199 asn1_pop_tag(&data);
200 asn1_pop_tag(&data);
202 asn1_pop_tag(&data);
203 asn1_pop_tag(&data);
204 break;
206 case LDAP_TAG_SearchResultDone: {
207 struct ldap_Result *r = &msg->r.SearchResultDone;
208 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
209 ldap_encode_response(&data, r);
210 asn1_pop_tag(&data);
211 break;
213 case LDAP_TAG_ModifyRequest: {
214 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
215 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
216 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
217 asn1_push_tag(&data, ASN1_SEQUENCE(0));
219 for (i=0; i<r->num_mods; i++) {
220 struct ldap_attribute *attrib = &r->mods[i].attrib;
221 asn1_push_tag(&data, ASN1_SEQUENCE(0));
222 asn1_write_enumerated(&data, r->mods[i].type);
223 asn1_push_tag(&data, ASN1_SEQUENCE(0));
224 asn1_write_OctetString(&data, attrib->name,
225 strlen(attrib->name));
226 asn1_push_tag(&data, ASN1_SET);
227 for (j=0; j<attrib->num_values; j++) {
228 asn1_write_OctetString(&data,
229 attrib->values[j].data,
230 attrib->values[j].length);
233 asn1_pop_tag(&data);
234 asn1_pop_tag(&data);
235 asn1_pop_tag(&data);
238 asn1_pop_tag(&data);
239 asn1_pop_tag(&data);
240 break;
242 case LDAP_TAG_ModifyResponse: {
243 struct ldap_Result *r = &msg->r.ModifyResponse;
244 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
245 ldap_encode_response(&data, r);
246 asn1_pop_tag(&data);
247 break;
249 case LDAP_TAG_AddRequest: {
250 struct ldap_AddRequest *r = &msg->r.AddRequest;
251 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
252 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
253 asn1_push_tag(&data, ASN1_SEQUENCE(0));
255 for (i=0; i<r->num_attributes; i++) {
256 struct ldap_attribute *attrib = &r->attributes[i];
257 asn1_push_tag(&data, ASN1_SEQUENCE(0));
258 asn1_write_OctetString(&data, attrib->name,
259 strlen(attrib->name));
260 asn1_push_tag(&data, ASN1_SET);
261 for (j=0; j<r->attributes[i].num_values; j++) {
262 asn1_write_OctetString(&data,
263 attrib->values[j].data,
264 attrib->values[j].length);
266 asn1_pop_tag(&data);
267 asn1_pop_tag(&data);
269 asn1_pop_tag(&data);
270 asn1_pop_tag(&data);
271 break;
273 case LDAP_TAG_AddResponse: {
274 struct ldap_Result *r = &msg->r.AddResponse;
275 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
276 ldap_encode_response(&data, r);
277 asn1_pop_tag(&data);
278 break;
280 case LDAP_TAG_DelRequest: {
281 struct ldap_DelRequest *r = &msg->r.DelRequest;
282 asn1_push_tag(&data, ASN1_APPLICATION_SIMPLE(msg->type));
283 asn1_write(&data, r->dn, strlen(r->dn));
284 asn1_pop_tag(&data);
285 break;
287 case LDAP_TAG_DelResponse: {
288 struct ldap_Result *r = &msg->r.DelResponse;
289 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
290 ldap_encode_response(&data, r);
291 asn1_pop_tag(&data);
292 break;
294 case LDAP_TAG_ModifyDNRequest: {
295 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
296 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
297 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
298 asn1_write_OctetString(&data, r->newrdn, strlen(r->newrdn));
299 asn1_write_BOOLEAN(&data, r->deleteolddn);
300 if (r->newsuperior != NULL) {
301 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
302 asn1_write(&data, r->newsuperior,
303 strlen(r->newsuperior));
304 asn1_pop_tag(&data);
306 asn1_pop_tag(&data);
307 break;
309 case LDAP_TAG_ModifyDNResponse: {
310 struct ldap_Result *r = &msg->r.ModifyDNResponse;
311 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
312 ldap_encode_response(&data, r);
313 asn1_pop_tag(&data);
314 break;
316 case LDAP_TAG_CompareRequest: {
317 struct ldap_CompareRequest *r = &msg->r.CompareRequest;
318 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
319 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
320 asn1_push_tag(&data, ASN1_SEQUENCE(0));
321 asn1_write_OctetString(&data, r->attribute,
322 strlen(r->attribute));
323 asn1_write_OctetString(&data, r->value.data,
324 r->value.length);
325 asn1_pop_tag(&data);
326 asn1_pop_tag(&data);
327 break;
329 case LDAP_TAG_CompareResponse: {
330 struct ldap_Result *r = &msg->r.ModifyDNResponse;
331 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
332 ldap_encode_response(&data, r);
333 asn1_pop_tag(&data);
334 break;
336 case LDAP_TAG_AbandonRequest: {
337 struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
338 asn1_push_tag(&data, ASN1_APPLICATION_SIMPLE(msg->type));
339 asn1_write_implicit_Integer(&data, r->messageid);
340 asn1_pop_tag(&data);
341 break;
343 case LDAP_TAG_SearchResultReference: {
344 struct ldap_SearchResRef *r = &msg->r.SearchResultReference;
345 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
346 asn1_write_OctetString(&data, r->referral, strlen(r->referral));
347 asn1_pop_tag(&data);
348 break;
350 case LDAP_TAG_ExtendedRequest: {
351 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
352 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
353 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
354 asn1_write(&data, r->oid, strlen(r->oid));
355 asn1_pop_tag(&data);
356 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(1));
357 asn1_write(&data, r->value.data, r->value.length);
358 asn1_pop_tag(&data);
359 asn1_pop_tag(&data);
360 break;
362 case LDAP_TAG_ExtendedResponse: {
363 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
364 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
365 ldap_encode_response(&data, &r->response);
366 asn1_pop_tag(&data);
367 break;
369 default:
370 return False;
373 asn1_pop_tag(&data);
374 *result = data_blob(data.data, data.length);
375 asn1_free(&data);
376 return True;
379 static const char *blob2string_talloc(TALLOC_CTX *mem_ctx,
380 DATA_BLOB blob)
382 char *result = talloc_size(mem_ctx, blob.length+1);
383 memcpy(result, blob.data, blob.length);
384 result[blob.length] = '\0';
385 return result;
388 static BOOL asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
389 struct asn1_data *data,
390 const char **result)
392 DATA_BLOB string;
393 if (!asn1_read_OctetString(data, &string))
394 return False;
395 *result = blob2string_talloc(mem_ctx, string);
396 data_blob_free(&string);
397 return True;
400 static void ldap_decode_response(TALLOC_CTX *mem_ctx,
401 struct asn1_data *data,
402 struct ldap_Result *result)
404 asn1_read_enumerated(data, &result->resultcode);
405 asn1_read_OctetString_talloc(mem_ctx, data, &result->dn);
406 asn1_read_OctetString_talloc(mem_ctx, data, &result->errormessage);
407 if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
408 asn1_start_tag(data, ASN1_CONTEXT(3));
409 asn1_read_OctetString_talloc(mem_ctx, data, &result->referral);
410 asn1_end_tag(data);
411 } else {
412 result->referral = NULL;
416 static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
417 struct asn1_data *data)
419 uint8_t filter_tag, tag_desc;
420 struct ldb_parse_tree *ret;
422 if (!asn1_peek_uint8(data, &filter_tag)) {
423 return NULL;
426 tag_desc = filter_tag;
427 filter_tag &= 0x1f; /* strip off the asn1 stuff */
428 tag_desc &= 0xe0;
430 ret = talloc(mem_ctx, struct ldb_parse_tree);
431 if (ret == NULL) return NULL;
433 switch(filter_tag) {
434 case 0:
435 case 1:
436 /* AND or OR of one or more filters */
437 ret->operation = (filter_tag == 0)?LDB_OP_AND:LDB_OP_OR;
438 ret->u.list.num_elements = 0;
439 ret->u.list.elements = NULL;
441 if (tag_desc != 0xa0) {
442 /* context compount */
443 goto failed;
446 if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
447 goto failed;
450 while (asn1_tag_remaining(data) > 0) {
451 struct ldb_parse_tree *subtree;
452 subtree = ldap_decode_filter_tree(ret, data);
453 if (subtree == NULL) {
454 goto failed;
456 ret->u.list.elements =
457 talloc_realloc(ret, ret->u.list.elements,
458 struct ldb_parse_tree *,
459 ret->u.list.num_elements+1);
460 if (ret->u.list.elements == NULL) {
461 goto failed;
463 talloc_steal(ret->u.list.elements, subtree);
464 ret->u.list.elements[ret->u.list.num_elements] = subtree;
465 ret->u.list.num_elements++;
467 if (!asn1_end_tag(data)) {
468 goto failed;
470 break;
472 case 3: {
473 /* equalityMatch */
474 const char *attrib;
475 DATA_BLOB value;
477 ret->operation = LDB_OP_SIMPLE;
479 if (tag_desc != 0xa0) {
480 /* context compound */
481 goto failed;
484 asn1_start_tag(data, ASN1_CONTEXT(3));
485 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
486 asn1_read_OctetString(data, &value);
487 asn1_end_tag(data);
488 if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
489 goto failed;
491 ret->u.simple.attr = talloc_steal(ret, attrib);
492 ret->u.simple.value.data = talloc_steal(ret, value.data);
493 ret->u.simple.value.length = value.length;
494 break;
496 case 7: {
497 /* Normal presence, "attribute=*" */
498 int attr_len;
499 if (tag_desc != 0x80) {
500 /* context simple */
501 goto failed;
503 if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(7))) {
504 goto failed;
507 ret->operation = LDB_OP_SIMPLE;
509 attr_len = asn1_tag_remaining(data);
511 ret->u.simple.attr = talloc_size(ret, attr_len+1);
512 if (ret->u.simple.attr == NULL) {
513 goto failed;
515 if (!asn1_read(data, ret->u.simple.attr, attr_len)) {
516 goto failed;
518 ret->u.simple.attr[attr_len] = 0;
519 ret->u.simple.value.data = talloc_strdup(ret, "*");
520 if (ret->u.simple.value.data == NULL) {
521 goto failed;
523 ret->u.simple.value.length = 1;
524 if (!asn1_end_tag(data)) {
525 goto failed;
527 break;
529 default:
530 DEBUG(0,("Unsupported LDAP filter operation 0x%x\n", filter_tag));
531 goto failed;
534 return ret;
536 failed:
537 talloc_free(ret);
538 DEBUG(0,("Failed to parse ASN.1 LDAP filter\n"));
539 return NULL;
543 static BOOL ldap_decode_filter(TALLOC_CTX *mem_ctx, struct asn1_data *data,
544 const char **filterp)
546 struct ldb_parse_tree *tree;
548 tree = ldap_decode_filter_tree(mem_ctx, data);
549 if (tree == NULL) {
550 return False;
552 *filterp = ldb_filter_from_tree(mem_ctx, tree);
553 talloc_free(tree);
554 if (*filterp == NULL) {
555 return False;
557 return True;
562 static void ldap_decode_attrib(TALLOC_CTX *mem_ctx, struct asn1_data *data,
563 struct ldap_attribute *attrib)
565 asn1_start_tag(data, ASN1_SEQUENCE(0));
566 asn1_read_OctetString_talloc(mem_ctx, data, &attrib->name);
567 asn1_start_tag(data, ASN1_SET);
568 while (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
569 DATA_BLOB blob;
570 struct ldb_val value;
571 asn1_read_OctetString(data, &blob);
572 value.data = blob.data;
573 value.length = blob.length;
574 add_value_to_attrib(mem_ctx, &value, attrib);
575 data_blob_free(&blob);
577 asn1_end_tag(data);
578 asn1_end_tag(data);
582 static void ldap_decode_attribs(TALLOC_CTX *mem_ctx, struct asn1_data *data,
583 struct ldap_attribute **attributes,
584 int *num_attributes)
586 asn1_start_tag(data, ASN1_SEQUENCE(0));
587 while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
588 struct ldap_attribute attrib;
589 ZERO_STRUCT(attrib);
590 ldap_decode_attrib(mem_ctx, data, &attrib);
591 add_attrib_to_array_talloc(mem_ctx, &attrib,
592 attributes, num_attributes);
594 asn1_end_tag(data);
597 BOOL ldap_decode(struct asn1_data *data, struct ldap_message *msg)
599 uint8_t tag;
601 asn1_start_tag(data, ASN1_SEQUENCE(0));
602 asn1_read_Integer(data, &msg->messageid);
604 if (!asn1_peek_uint8(data, &tag))
605 return False;
607 switch(tag) {
609 case ASN1_APPLICATION(LDAP_TAG_BindRequest): {
610 struct ldap_BindRequest *r = &msg->r.BindRequest;
611 msg->type = LDAP_TAG_BindRequest;
612 asn1_start_tag(data, tag);
613 asn1_read_Integer(data, &r->version);
614 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
615 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(0))) {
616 int pwlen;
617 r->creds.password = "";
618 r->mechanism = LDAP_AUTH_MECH_SIMPLE;
619 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0));
620 pwlen = asn1_tag_remaining(data);
621 if (pwlen != 0) {
622 char *pw = talloc_size(msg->mem_ctx, pwlen+1);
623 asn1_read(data, pw, pwlen);
624 pw[pwlen] = '\0';
625 r->creds.password = pw;
627 asn1_end_tag(data);
628 } else if (asn1_peek_tag(data, ASN1_CONTEXT(3))){
629 asn1_start_tag(data, ASN1_CONTEXT(3));
630 r->mechanism = LDAP_AUTH_MECH_SASL;
631 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->creds.SASL.mechanism);
632 asn1_read_OctetString(data, &r->creds.SASL.secblob);
633 if (r->creds.SASL.secblob.data) {
634 talloc_steal(msg->mem_ctx, r->creds.SASL.secblob.data);
636 asn1_end_tag(data);
638 asn1_end_tag(data);
639 break;
642 case ASN1_APPLICATION(LDAP_TAG_BindResponse): {
643 struct ldap_BindResponse *r = &msg->r.BindResponse;
644 msg->type = LDAP_TAG_BindResponse;
645 asn1_start_tag(data, tag);
646 ldap_decode_response(msg->mem_ctx, data, &r->response);
647 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(7))) {
648 DATA_BLOB tmp_blob = data_blob(NULL, 0);
649 asn1_read_ContextSimple(data, 7, &tmp_blob);
650 r->SASL.secblob = data_blob_talloc(msg->mem_ctx, tmp_blob.data, tmp_blob.length);
651 data_blob_free(&tmp_blob);
652 } else {
653 r->SASL.secblob = data_blob(NULL, 0);
655 asn1_end_tag(data);
656 break;
659 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_UnbindRequest): {
660 msg->type = LDAP_TAG_UnbindRequest;
661 asn1_start_tag(data, tag);
662 asn1_end_tag(data);
663 break;
666 case ASN1_APPLICATION(LDAP_TAG_SearchRequest): {
667 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
668 msg->type = LDAP_TAG_SearchRequest;
669 asn1_start_tag(data, tag);
670 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->basedn);
671 asn1_read_enumerated(data, (int *)&(r->scope));
672 asn1_read_enumerated(data, (int *)&(r->deref));
673 asn1_read_Integer(data, &r->sizelimit);
674 asn1_read_Integer(data, &r->timelimit);
675 asn1_read_BOOLEAN(data, &r->attributesonly);
677 /* Maybe create a TALLOC_CTX for the filter? This can waste
678 * quite a bit of memory recursing down. */
679 ldap_decode_filter(msg->mem_ctx, data, &r->filter);
681 asn1_start_tag(data, ASN1_SEQUENCE(0));
683 r->num_attributes = 0;
684 r->attributes = NULL;
686 while (asn1_tag_remaining(data) > 0) {
687 const char *attr;
688 if (!asn1_read_OctetString_talloc(msg->mem_ctx, data,
689 &attr))
690 return False;
691 if (!add_string_to_array(msg->mem_ctx, attr,
692 &r->attributes,
693 &r->num_attributes))
694 return False;
697 asn1_end_tag(data);
698 asn1_end_tag(data);
699 break;
702 case ASN1_APPLICATION(LDAP_TAG_SearchResultEntry): {
703 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
704 msg->type = LDAP_TAG_SearchResultEntry;
705 r->attributes = NULL;
706 r->num_attributes = 0;
707 asn1_start_tag(data, tag);
708 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
709 ldap_decode_attribs(msg->mem_ctx, data, &r->attributes,
710 &r->num_attributes);
711 asn1_end_tag(data);
712 break;
715 case ASN1_APPLICATION(LDAP_TAG_SearchResultDone): {
716 struct ldap_Result *r = &msg->r.SearchResultDone;
717 msg->type = LDAP_TAG_SearchResultDone;
718 asn1_start_tag(data, tag);
719 ldap_decode_response(msg->mem_ctx, data, r);
720 asn1_end_tag(data);
721 break;
724 case ASN1_APPLICATION(LDAP_TAG_SearchResultReference): {
725 struct ldap_SearchResRef *r = &msg->r.SearchResultReference;
726 msg->type = LDAP_TAG_SearchResultReference;
727 asn1_start_tag(data, tag);
728 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->referral);
729 asn1_end_tag(data);
730 break;
733 case ASN1_APPLICATION(LDAP_TAG_ModifyRequest): {
734 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
735 msg->type = LDAP_TAG_ModifyRequest;
736 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_ModifyRequest));
737 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
738 asn1_start_tag(data, ASN1_SEQUENCE(0));
740 r->num_mods = 0;
741 r->mods = NULL;
743 while (asn1_tag_remaining(data) > 0) {
744 struct ldap_mod mod;
745 int v;
746 ZERO_STRUCT(mod);
747 asn1_start_tag(data, ASN1_SEQUENCE(0));
748 asn1_read_enumerated(data, &v);
749 mod.type = v;
750 ldap_decode_attrib(msg->mem_ctx, data, &mod.attrib);
751 asn1_end_tag(data);
752 if (!add_mod_to_array_talloc(msg->mem_ctx, &mod,
753 &r->mods, &r->num_mods))
754 break;
757 asn1_end_tag(data);
758 asn1_end_tag(data);
759 break;
762 case ASN1_APPLICATION(LDAP_TAG_ModifyResponse): {
763 struct ldap_Result *r = &msg->r.ModifyResponse;
764 msg->type = LDAP_TAG_ModifyResponse;
765 asn1_start_tag(data, tag);
766 ldap_decode_response(msg->mem_ctx, data, r);
767 asn1_end_tag(data);
768 break;
771 case ASN1_APPLICATION(LDAP_TAG_AddRequest): {
772 struct ldap_AddRequest *r = &msg->r.AddRequest;
773 msg->type = LDAP_TAG_AddRequest;
774 asn1_start_tag(data, tag);
775 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
777 r->attributes = NULL;
778 r->num_attributes = 0;
779 ldap_decode_attribs(msg->mem_ctx, data, &r->attributes,
780 &r->num_attributes);
782 asn1_end_tag(data);
783 break;
786 case ASN1_APPLICATION(LDAP_TAG_AddResponse): {
787 struct ldap_Result *r = &msg->r.AddResponse;
788 msg->type = LDAP_TAG_AddResponse;
789 asn1_start_tag(data, tag);
790 ldap_decode_response(msg->mem_ctx, data, r);
791 asn1_end_tag(data);
792 break;
795 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest): {
796 struct ldap_DelRequest *r = &msg->r.DelRequest;
797 int len;
798 char *dn;
799 msg->type = LDAP_TAG_DelRequest;
800 asn1_start_tag(data,
801 ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest));
802 len = asn1_tag_remaining(data);
803 dn = talloc_size(msg->mem_ctx, len+1);
804 if (dn == NULL)
805 break;
806 asn1_read(data, dn, len);
807 dn[len] = '\0';
808 r->dn = dn;
809 asn1_end_tag(data);
810 break;
813 case ASN1_APPLICATION(LDAP_TAG_DelResponse): {
814 struct ldap_Result *r = &msg->r.DelResponse;
815 msg->type = LDAP_TAG_DelResponse;
816 asn1_start_tag(data, tag);
817 ldap_decode_response(msg->mem_ctx, data, r);
818 asn1_end_tag(data);
819 break;
822 case ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest): {
823 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
824 msg->type = LDAP_TAG_ModifyDNRequest;
825 asn1_start_tag(data,
826 ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest));
827 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
828 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->newrdn);
829 asn1_read_BOOLEAN(data, &r->deleteolddn);
830 r->newsuperior = NULL;
831 if (asn1_tag_remaining(data) > 0) {
832 int len;
833 char *newsup;
834 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0));
835 len = asn1_tag_remaining(data);
836 newsup = talloc_size(msg->mem_ctx, len+1);
837 if (newsup == NULL)
838 break;
839 asn1_read(data, newsup, len);
840 newsup[len] = '\0';
841 r->newsuperior = newsup;
842 asn1_end_tag(data);
844 asn1_end_tag(data);
845 break;
848 case ASN1_APPLICATION(LDAP_TAG_ModifyDNResponse): {
849 struct ldap_Result *r = &msg->r.ModifyDNResponse;
850 msg->type = LDAP_TAG_ModifyDNResponse;
851 asn1_start_tag(data, tag);
852 ldap_decode_response(msg->mem_ctx, data, r);
853 asn1_end_tag(data);
854 break;
857 case ASN1_APPLICATION(LDAP_TAG_CompareRequest): {
858 struct ldap_CompareRequest *r = &msg->r.CompareRequest;
859 msg->type = LDAP_TAG_CompareRequest;
860 asn1_start_tag(data,
861 ASN1_APPLICATION(LDAP_TAG_CompareRequest));
862 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
863 asn1_start_tag(data, ASN1_SEQUENCE(0));
864 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->attribute);
865 asn1_read_OctetString(data, &r->value);
866 if (r->value.data) {
867 talloc_steal(msg->mem_ctx, r->value.data);
869 asn1_end_tag(data);
870 asn1_end_tag(data);
871 break;
874 case ASN1_APPLICATION(LDAP_TAG_CompareResponse): {
875 struct ldap_Result *r = &msg->r.CompareResponse;
876 msg->type = LDAP_TAG_CompareResponse;
877 asn1_start_tag(data, tag);
878 ldap_decode_response(msg->mem_ctx, data, r);
879 asn1_end_tag(data);
880 break;
883 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_AbandonRequest): {
884 struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
885 msg->type = LDAP_TAG_AbandonRequest;
886 asn1_start_tag(data, tag);
887 asn1_read_implicit_Integer(data, &r->messageid);
888 asn1_end_tag(data);
889 break;
892 case ASN1_APPLICATION(LDAP_TAG_ExtendedRequest): {
893 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
894 DATA_BLOB tmp_blob = data_blob(NULL, 0);
896 msg->type = LDAP_TAG_ExtendedRequest;
897 asn1_start_tag(data,tag);
898 if (!asn1_read_ContextSimple(data, 0, &tmp_blob)) {
899 return False;
901 r->oid = blob2string_talloc(msg->mem_ctx, tmp_blob);
902 data_blob_free(&tmp_blob);
903 if (!r->oid) {
904 return False;
907 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(1))) {
908 asn1_read_ContextSimple(data, 1, &tmp_blob);
909 r->value = data_blob_talloc(msg->mem_ctx, tmp_blob.data, tmp_blob.length);
910 data_blob_free(&tmp_blob);
911 } else {
912 r->value = data_blob(NULL, 0);
915 asn1_end_tag(data);
916 break;
919 case ASN1_APPLICATION(LDAP_TAG_ExtendedResponse): {
920 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
921 msg->type = LDAP_TAG_ExtendedResponse;
922 asn1_start_tag(data, tag);
923 ldap_decode_response(msg->mem_ctx, data, &r->response);
924 /* I have to come across an operation that actually sends
925 * something back to really see what's going on. The currently
926 * needed pwdchange does not send anything back. */
927 r->name = NULL;
928 r->value.data = NULL;
929 r->value.length = 0;
930 asn1_end_tag(data);
931 break;
933 default:
934 return False;
937 msg->num_controls = 0;
938 msg->controls = NULL;
940 if (asn1_peek_tag(data, ASN1_CONTEXT(0))) {
941 int i;
942 struct ldap_Control *ctrl = NULL;
944 asn1_start_tag(data, ASN1_CONTEXT(0));
946 for (i=0; asn1_peek_tag(data, ASN1_SEQUENCE(0)); i++) {
947 asn1_start_tag(data, ASN1_SEQUENCE(0));
949 ctrl = talloc_realloc(msg->mem_ctx, ctrl, struct ldap_Control, i+1);
950 if (!ctrl) {
951 return False;
953 ctrl[i].oid = NULL;
954 ctrl[i].critical = False;
955 ctrl[i].value = data_blob(NULL, 0);
957 asn1_read_OctetString_talloc(ctrl, data, &ctrl[i].oid);
959 if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
960 asn1_read_BOOLEAN(data, &ctrl[i].critical);
963 if (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
964 asn1_read_OctetString(data, &ctrl[i].value);
965 if (ctrl[i].value.data) {
966 talloc_steal(msg->mem_ctx, ctrl[i].value.data);
970 asn1_end_tag(data);
972 msg->num_controls = i;
973 msg->controls = ctrl;
975 asn1_end_tag(data);
978 asn1_end_tag(data);
979 return ((!data->has_error) && (data->nesting == NULL));
982 BOOL ldap_parse_basic_url(TALLOC_CTX *mem_ctx, const char *url,
983 char **host, uint16_t *port, BOOL *ldaps)
985 int tmp_port = 0;
986 char protocol[11];
987 char tmp_host[255];
988 const char *p = url;
989 int ret;
991 /* skip leading "URL:" (if any) */
992 if (strncasecmp( p, "URL:", 4) == 0) {
993 p += 4;
996 /* Paranoia check */
997 SMB_ASSERT(sizeof(protocol)>10 && sizeof(tmp_host)>254);
999 ret = sscanf(p, "%10[^:]://%254[^:/]:%d", protocol, tmp_host, &tmp_port);
1000 if (ret < 2) {
1001 return False;
1004 if (strequal(protocol, "ldap")) {
1005 *port = 389;
1006 *ldaps = False;
1007 } else if (strequal(protocol, "ldaps")) {
1008 *port = 636;
1009 *ldaps = True;
1010 } else {
1011 DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
1012 return False;
1015 if (tmp_port != 0)
1016 *port = tmp_port;
1018 *host = talloc_strdup(mem_ctx, tmp_host);
1020 return (*host != NULL);