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.
28 /****************************************************************************
30 * LDAP filter parser -- main routine is ldap_parse_filter
32 * Shamelessly stolen and adapted from ldb.
34 ***************************************************************************/
37 return next token element. Caller frees
39 static char *ldap_parse_lex(TALLOC_CTX *mem_ctx, const char **s,
54 if (strchr(sep, *p)) {
56 ret = talloc_strndup(mem_ctx, p, 1);
63 while (*p && (isalnum(*p) || !strchr(sep, *p))) {
71 ret = talloc_strndup(mem_ctx, *s, p - *s);
83 find a matching close brace in a string
85 static const char *match_brace(const char *s)
87 unsigned int count = 0;
88 while (*s && (count != 0 || *s != ')')) {
103 static struct ldap_parse_tree *ldap_parse_filter(TALLOC_CTX *mem_ctx,
107 <simple> ::= <attributetype> <filtertype> <attributevalue>
109 static struct ldap_parse_tree *ldap_parse_simple(TALLOC_CTX *mem_ctx,
113 struct ldap_parse_tree *ret;
115 l = ldap_parse_lex(mem_ctx, &s, LDAP_ALL_SEP);
120 if (strchr("()&|=", *l))
123 eq = ldap_parse_lex(mem_ctx, &s, LDAP_ALL_SEP);
124 if (!eq || strcmp(eq, "=") != 0)
127 val = ldap_parse_lex(mem_ctx, &s, ")");
128 if (val && strchr("()&|", *val))
131 ret = talloc(mem_ctx, sizeof(*ret));
137 ret->operation = LDAP_OP_SIMPLE;
138 ret->u.simple.attr = l;
139 ret->u.simple.value.data = val;
140 ret->u.simple.value.length = val?strlen(val):0;
148 <and> ::= '&' <filterlist>
149 <or> ::= '|' <filterlist>
150 <filterlist> ::= <filter> | <filter> <filterlist>
152 static struct ldap_parse_tree *ldap_parse_filterlist(TALLOC_CTX *mem_ctx,
153 enum ldap_parse_op op,
156 struct ldap_parse_tree *ret, *next;
158 ret = talloc(mem_ctx, sizeof(*ret));
166 ret->u.list.num_elements = 1;
167 ret->u.list.elements = talloc(mem_ctx, sizeof(*ret->u.list.elements));
168 if (!ret->u.list.elements) {
173 ret->u.list.elements[0] = ldap_parse_filter(mem_ctx, &s);
174 if (!ret->u.list.elements[0]) {
178 while (isspace(*s)) s++;
180 while (*s && (next = ldap_parse_filter(mem_ctx, &s))) {
181 struct ldap_parse_tree **e;
182 e = talloc_realloc_p(ret,
183 ret->u.list.elements,
184 struct ldap_parse_tree *,
185 ret->u.list.num_elements+1);
190 ret->u.list.elements = e;
191 ret->u.list.elements[ret->u.list.num_elements] = next;
192 ret->u.list.num_elements++;
193 while (isspace(*s)) s++;
201 <not> ::= '!' <filter>
203 static struct ldap_parse_tree *ldap_parse_not(TALLOC_CTX *mem_ctx, const char *s)
205 struct ldap_parse_tree *ret;
207 ret = talloc(mem_ctx, sizeof(*ret));
213 ret->operation = LDAP_OP_NOT;
214 ret->u.not.child = ldap_parse_filter(mem_ctx, &s);
215 if (!ret->u.not.child)
223 <filtercomp> ::= <and> | <or> | <not> | <simple>
225 static struct ldap_parse_tree *ldap_parse_filtercomp(TALLOC_CTX *mem_ctx,
228 while (isspace(*s)) s++;
232 return ldap_parse_filterlist(mem_ctx, LDAP_OP_AND, s+1);
235 return ldap_parse_filterlist(mem_ctx, LDAP_OP_OR, s+1);
238 return ldap_parse_not(mem_ctx, s+1);
245 return ldap_parse_simple(mem_ctx, s);
250 <filter> ::= '(' <filtercomp> ')'
252 static struct ldap_parse_tree *ldap_parse_filter(TALLOC_CTX *mem_ctx,
257 struct ldap_parse_tree *ret;
259 l = ldap_parse_lex(mem_ctx, s, LDAP_ALL_SEP);
264 if (strcmp(l, "(") != 0) {
274 s2 = talloc_strndup(mem_ctx, *s, p - *s);
280 ret = ldap_parse_filtercomp(mem_ctx, s2);
288 main parser entry point. Takes a search string and returns a parse tree
290 expression ::= <simple> | <filter>
292 static struct ldap_parse_tree *ldap_parse_tree(TALLOC_CTX *mem_ctx, const char *s)
294 while (isspace(*s)) s++;
297 return ldap_parse_filter(mem_ctx, &s);
300 return ldap_parse_simple(mem_ctx, s);
303 static BOOL ldap_push_filter(ASN1_DATA *data, struct ldap_parse_tree *tree)
305 switch (tree->operation) {
306 case LDAP_OP_SIMPLE: {
307 if ((tree->u.simple.value.length == 1) &&
308 (((char *)(tree->u.simple.value.data))[0] == '*')) {
309 /* Just a presence test */
310 asn1_push_tag(data, 0x87);
311 asn1_write(data, tree->u.simple.attr,
312 strlen(tree->u.simple.attr));
314 return !data->has_error;
317 /* Equality is all we currently do... */
318 asn1_push_tag(data, 0xa3);
319 asn1_write_OctetString(data, tree->u.simple.attr,
320 strlen(tree->u.simple.attr));
321 asn1_write_OctetString(data, tree->u.simple.value.data,
322 tree->u.simple.value.length);
330 asn1_push_tag(data, 0xa0);
331 for (i=0; i<tree->u.list.num_elements; i++) {
332 ldap_push_filter(data, tree->u.list.elements[i]);
341 asn1_push_tag(data, 0xa1);
342 for (i=0; i<tree->u.list.num_elements; i++) {
343 ldap_push_filter(data, tree->u.list.elements[i]);
351 return !data->has_error;
354 static void ldap_encode_response(enum ldap_request_tag tag,
355 struct ldap_Result *result,
358 asn1_push_tag(data, ASN1_APPLICATION(tag));
359 asn1_write_enumerated(data, result->resultcode);
360 asn1_write_OctetString(data, result->dn,
361 (result->dn) ? strlen(result->dn) : 0);
362 asn1_write_OctetString(data, result->errormessage,
363 (result->errormessage) ?
364 strlen(result->errormessage) : 0);
365 if (result->referral != NULL)
366 asn1_write_OctetString(data, result->referral,
367 strlen(result->referral));
371 BOOL ldap_encode(struct ldap_message *msg, DATA_BLOB *result)
377 asn1_push_tag(&data, ASN1_SEQUENCE(0));
378 asn1_write_Integer(&data, msg->messageid);
381 case LDAP_TAG_BindRequest: {
382 struct ldap_BindRequest *r = &msg->r.BindRequest;
383 asn1_push_tag(&data, ASN1_APPLICATION(LDAP_TAG_BindRequest));
384 asn1_write_Integer(&data, r->version);
385 asn1_write_OctetString(&data, r->dn,
386 (r->dn != NULL) ? strlen(r->dn) : 0);
388 switch (r->mechanism) {
389 case LDAP_AUTH_MECH_SIMPLE:
390 /* context, primitive */
391 asn1_push_tag(&data, r->mechanism | 0x80);
392 asn1_write(&data, r->creds.password,
393 strlen(r->creds.password));
396 case LDAP_AUTH_MECH_SASL:
397 /* context, constructed */
398 asn1_push_tag(&data, r->mechanism | 0xa0);
399 asn1_write_OctetString(&data, r->creds.SASL.mechanism,
400 strlen(r->creds.SASL.mechanism));
401 asn1_write_OctetString(&data, r->creds.SASL.secblob.data,
402 r->creds.SASL.secblob.length);
413 case LDAP_TAG_BindResponse: {
414 struct ldap_BindResponse *r = &msg->r.BindResponse;
415 ldap_encode_response(msg->type, &r->response, &data);
418 case LDAP_TAG_UnbindRequest: {
419 /* struct ldap_UnbindRequest *r = &msg->r.UnbindRequest; */
422 case LDAP_TAG_SearchRequest: {
423 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
424 asn1_push_tag(&data, ASN1_APPLICATION(LDAP_TAG_SearchRequest));
425 asn1_write_OctetString(&data, r->basedn, strlen(r->basedn));
426 asn1_write_enumerated(&data, r->scope);
427 asn1_write_enumerated(&data, r->deref);
428 asn1_write_Integer(&data, r->sizelimit);
429 asn1_write_Integer(&data, r->timelimit);
430 asn1_write_BOOLEAN(&data, r->attributesonly);
433 TALLOC_CTX *mem_ctx = talloc_init("ldap_parse_tree");
434 struct ldap_parse_tree *tree;
439 tree = ldap_parse_tree(mem_ctx, r->filter);
444 ldap_push_filter(&data, tree);
446 talloc_destroy(mem_ctx);
449 asn1_push_tag(&data, ASN1_SEQUENCE(0));
450 for (i=0; i<r->num_attributes; i++) {
451 asn1_write_OctetString(&data, r->attributes[i],
452 strlen(r->attributes[i]));
459 case LDAP_TAG_SearchResultEntry: {
460 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
461 asn1_push_tag(&data, ASN1_APPLICATION(LDAP_TAG_SearchResultEntry));
462 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
463 asn1_push_tag(&data, ASN1_SEQUENCE(0));
464 for (i=0; i<r->num_attributes; i++) {
465 struct ldap_attribute *attr = &r->attributes[i];
466 asn1_push_tag(&data, ASN1_SEQUENCE(0));
467 asn1_write_OctetString(&data, attr->name,
469 asn1_push_tag(&data, ASN1_SEQUENCE(1));
470 for (j=0; j<attr->num_values; j++) {
471 asn1_write_OctetString(&data,
472 attr->values[j].data,
473 attr->values[j].length);
482 case LDAP_TAG_SearchResultDone: {
483 struct ldap_Result *r = &msg->r.SearchResultDone;
484 ldap_encode_response(msg->type, r, &data);
487 case LDAP_TAG_ModifyRequest: {
488 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
489 asn1_push_tag(&data, ASN1_APPLICATION(LDAP_TAG_ModifyRequest));
490 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
491 asn1_push_tag(&data, ASN1_SEQUENCE(0));
493 for (i=0; i<r->num_mods; i++) {
494 struct ldap_attribute *attrib = &r->mods[i].attrib;
495 asn1_push_tag(&data, ASN1_SEQUENCE(0));
496 asn1_write_enumerated(&data, r->mods[i].type);
497 asn1_push_tag(&data, ASN1_SEQUENCE(0));
498 asn1_write_OctetString(&data, attrib->name,
499 strlen(attrib->name));
500 asn1_push_tag(&data, ASN1_SET);
501 for (j=0; j<attrib->num_values; j++) {
502 asn1_write_OctetString(&data,
503 attrib->values[j].data,
504 attrib->values[j].length);
516 case LDAP_TAG_ModifyResponse: {
517 struct ldap_Result *r = &msg->r.ModifyResponse;
518 ldap_encode_response(msg->type, r, &data);
521 case LDAP_TAG_AddRequest: {
522 struct ldap_AddRequest *r = &msg->r.AddRequest;
523 asn1_push_tag(&data, ASN1_APPLICATION(LDAP_TAG_AddRequest));
524 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
525 asn1_push_tag(&data, ASN1_SEQUENCE(0));
527 for (i=0; i<r->num_attributes; i++) {
528 struct ldap_attribute *attrib = &r->attributes[i];
529 asn1_push_tag(&data, ASN1_SEQUENCE(0));
530 asn1_write_OctetString(&data, attrib->name,
531 strlen(attrib->name));
532 asn1_push_tag(&data, ASN1_SET);
533 for (j=0; j<r->attributes[i].num_values; j++) {
534 asn1_write_OctetString(&data,
535 attrib->values[j].data,
536 attrib->values[j].length);
545 case LDAP_TAG_AddResponse: {
546 struct ldap_Result *r = &msg->r.AddResponse;
547 ldap_encode_response(msg->type, r, &data);
550 case LDAP_TAG_DelRequest: {
551 struct ldap_DelRequest *r = &msg->r.DelRequest;
553 ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest));
554 asn1_write(&data, r->dn, strlen(r->dn));
558 case LDAP_TAG_DelResponse: {
559 struct ldap_Result *r = &msg->r.DelResponse;
560 ldap_encode_response(msg->type, r, &data);
563 case LDAP_TAG_ModifyDNRequest: {
564 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
566 ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest));
567 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
568 asn1_write_OctetString(&data, r->newrdn, strlen(r->newrdn));
569 asn1_write_BOOLEAN(&data, r->deleteolddn);
570 if (r->newsuperior != NULL) {
571 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
572 asn1_write(&data, r->newsuperior,
573 strlen(r->newsuperior));
579 case LDAP_TAG_ModifyDNResponse: {
580 struct ldap_Result *r = &msg->r.ModifyDNResponse;
581 ldap_encode_response(msg->type, r, &data);
584 case LDAP_TAG_CompareRequest: {
585 struct ldap_CompareRequest *r = &msg->r.CompareRequest;
587 ASN1_APPLICATION(LDAP_TAG_CompareRequest));
588 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
589 asn1_push_tag(&data, ASN1_SEQUENCE(0));
590 asn1_write_OctetString(&data, r->attribute,
591 strlen(r->attribute));
592 asn1_write_OctetString(&data, r->value,
598 case LDAP_TAG_CompareResponse: {
599 /* struct ldap_Result *r = &msg->r.CompareResponse; */
602 case LDAP_TAG_AbandonRequest: {
603 struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
605 ASN1_APPLICATION_SIMPLE(LDAP_TAG_AbandonRequest));
606 asn1_write_implicit_Integer(&data, r->messageid);
610 case LDAP_TAG_SearchResultReference: {
611 /* struct ldap_SearchResRef *r = &msg->r.SearchResultReference; */
614 case LDAP_TAG_ExtendedRequest: {
615 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
616 asn1_push_tag(&data, ASN1_APPLICATION(LDAP_TAG_ExtendedRequest));
617 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
618 asn1_write(&data, r->oid, strlen(r->oid));
620 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(1));
621 asn1_write(&data, r->value.data, r->value.length);
626 case LDAP_TAG_ExtendedResponse: {
627 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
628 ldap_encode_response(msg->type, &r->response, &data);
636 *result = data_blob(data.data, data.length);
641 static const char *blob2string_talloc(TALLOC_CTX *mem_ctx,
644 char *result = talloc(mem_ctx, blob.length+1);
645 memcpy(result, blob.data, blob.length);
646 result[blob.length] = '\0';
650 static BOOL asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
655 if (!asn1_read_OctetString(data, &string))
657 *result = blob2string_talloc(mem_ctx, string);
658 data_blob_free(&string);
662 static void ldap_decode_response(TALLOC_CTX *mem_ctx,
664 enum ldap_request_tag tag,
665 struct ldap_Result *result)
667 asn1_start_tag(data, ASN1_APPLICATION(tag));
668 asn1_read_enumerated(data, &result->resultcode);
669 asn1_read_OctetString_talloc(mem_ctx, data, &result->dn);
670 asn1_read_OctetString_talloc(mem_ctx, data, &result->errormessage);
671 if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
672 asn1_start_tag(data, ASN1_CONTEXT(3));
673 asn1_read_OctetString_talloc(mem_ctx, data, &result->referral);
676 result->referral = NULL;
681 static BOOL ldap_decode_filter(TALLOC_CTX *mem_ctx, ASN1_DATA *data,
684 uint8 filter_tag, tag_desc;
686 if (!asn1_peek_uint8(data, &filter_tag))
689 tag_desc = filter_tag;
690 filter_tag &= 0x1f; /* strip off the asn1 stuff */
695 /* AND of one or more filters */
696 if (tag_desc != 0xa0) /* context compount */
699 asn1_start_tag(data, ASN1_CONTEXT(0));
701 *filter = talloc_strdup(mem_ctx, "(&");
705 while (asn1_tag_remaining(data) > 0) {
707 if (!ldap_decode_filter(mem_ctx, data, &subfilter))
709 *filter = talloc_asprintf(mem_ctx, "%s%s", *filter,
716 *filter = talloc_asprintf(mem_ctx, "%s)", *filter);
720 /* OR of one or more filters */
721 if (tag_desc != 0xa0) /* context compount */
724 asn1_start_tag(data, ASN1_CONTEXT(1));
726 *filter = talloc_strdup(mem_ctx, "(|");
730 while (asn1_tag_remaining(data) > 0) {
732 if (!ldap_decode_filter(mem_ctx, data, &subfilter))
734 *filter = talloc_asprintf(mem_ctx, "%s%s", *filter,
742 *filter = talloc_asprintf(mem_ctx, "%s)", *filter);
747 const char *attrib, *value;
748 if (tag_desc != 0xa0) /* context compound */
750 asn1_start_tag(data, ASN1_CONTEXT(3));
751 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
752 asn1_read_OctetString_talloc(mem_ctx, data, &value);
754 if ((data->has_error) || (attrib == NULL) || (value == NULL))
756 *filter = talloc_asprintf(mem_ctx, "(%s=%s)", attrib, value);
760 /* Normal presence, "attribute=*" */
763 if (tag_desc != 0x80) /* context simple */
765 if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(7)))
767 attr_len = asn1_tag_remaining(data);
768 attr_name = malloc(attr_len+1);
769 if (attr_name == NULL)
771 asn1_read(data, attr_name, attr_len);
772 attr_name[attr_len] = '\0';
773 *filter = talloc_asprintf(mem_ctx, "(%s=*)", attr_name);
774 SAFE_FREE(attr_name);
786 static void ldap_decode_attrib(TALLOC_CTX *mem_ctx, ASN1_DATA *data,
787 struct ldap_attribute *attrib)
789 asn1_start_tag(data, ASN1_SEQUENCE(0));
790 asn1_read_OctetString_talloc(mem_ctx, data, &attrib->name);
791 asn1_start_tag(data, ASN1_SET);
792 while (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
794 struct ldap_val value;
795 asn1_read_OctetString(data, &blob);
796 value.data = blob.data;
797 value.length = blob.length;
798 add_value_to_attrib(mem_ctx, &value, attrib);
799 data_blob_free(&blob);
806 static void ldap_decode_attribs(TALLOC_CTX *mem_ctx, ASN1_DATA *data,
807 struct ldap_attribute **attributes,
810 asn1_start_tag(data, ASN1_SEQUENCE(0));
811 while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
812 struct ldap_attribute attrib;
814 ldap_decode_attrib(mem_ctx, data, &attrib);
815 add_attrib_to_array_talloc(mem_ctx, &attrib,
816 attributes, num_attributes);
821 BOOL ldap_decode(ASN1_DATA *data, struct ldap_message *msg)
825 asn1_start_tag(data, ASN1_SEQUENCE(0));
826 asn1_read_Integer(data, &msg->messageid);
828 if (!asn1_peek_uint8(data, &tag))
833 case ASN1_APPLICATION(LDAP_TAG_BindRequest): {
834 struct ldap_BindRequest *r = &msg->r.BindRequest;
835 msg->type = LDAP_TAG_BindRequest;
836 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_BindRequest));
837 asn1_read_Integer(data, &r->version);
838 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
839 if (asn1_peek_tag(data, 0x80)) {
841 r->creds.password = "";
842 /* Mechanism 0 (SIMPLE) */
843 asn1_start_tag(data, 0x80);
844 pwlen = asn1_tag_remaining(data);
846 char *pw = talloc(msg->mem_ctx, pwlen+1);
847 asn1_read(data, pw, pwlen);
849 r->creds.password = pw;
857 case ASN1_APPLICATION(LDAP_TAG_BindResponse): {
858 struct ldap_BindResponse *r = &msg->r.BindResponse;
859 msg->type = LDAP_TAG_BindResponse;
860 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_BindResponse));
861 asn1_read_enumerated(data, &r->response.resultcode);
862 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->response.dn);
863 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->response.errormessage);
864 if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
865 asn1_start_tag(data, ASN1_CONTEXT(3));
866 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->response.referral);
869 r->response.referral = NULL;
871 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(7))) {
872 DATA_BLOB tmp_blob = data_blob(NULL, 0);
873 asn1_read_ContextSimple(data, 7, &tmp_blob);
874 r->SASL.secblob = data_blob_talloc(msg->mem_ctx, tmp_blob.data, tmp_blob.length);
875 data_blob_free(&tmp_blob);
877 r->SASL.secblob = data_blob(NULL, 0);
883 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_UnbindRequest): {
884 msg->type = LDAP_TAG_UnbindRequest;
885 asn1_start_tag(data, ASN1_APPLICATION_SIMPLE(LDAP_TAG_UnbindRequest));
890 case ASN1_APPLICATION(LDAP_TAG_SearchRequest): {
891 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
892 msg->type = LDAP_TAG_SearchRequest;
893 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_SearchRequest));
894 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->basedn);
895 asn1_read_enumerated(data, (int *)&(r->scope));
896 asn1_read_enumerated(data, (int *)&(r->deref));
897 asn1_read_Integer(data, &r->sizelimit);
898 asn1_read_Integer(data, &r->timelimit);
899 asn1_read_BOOLEAN(data, &r->attributesonly);
901 /* Maybe create a TALLOC_CTX for the filter? This can waste
902 * quite a bit of memory recursing down. */
903 ldap_decode_filter(msg->mem_ctx, data, &r->filter);
905 asn1_start_tag(data, ASN1_SEQUENCE(0));
907 r->num_attributes = 0;
908 r->attributes = NULL;
910 while (asn1_tag_remaining(data) > 0) {
912 if (!asn1_read_OctetString_talloc(msg->mem_ctx, data,
915 if (!add_string_to_array(msg->mem_ctx, attr,
926 case ASN1_APPLICATION(LDAP_TAG_SearchResultEntry): {
927 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
928 msg->type = LDAP_TAG_SearchResultEntry;
929 r->attributes = NULL;
930 r->num_attributes = 0;
932 ASN1_APPLICATION(LDAP_TAG_SearchResultEntry));
933 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
934 ldap_decode_attribs(msg->mem_ctx, data, &r->attributes,
940 case ASN1_APPLICATION(LDAP_TAG_SearchResultDone): {
941 struct ldap_Result *r = &msg->r.SearchResultDone;
942 msg->type = LDAP_TAG_SearchResultDone;
943 ldap_decode_response(msg->mem_ctx, data,
944 LDAP_TAG_SearchResultDone, r);
948 case ASN1_APPLICATION(LDAP_TAG_SearchResultReference): {
949 /* struct ldap_SearchResRef *r = &msg->r.SearchResultReference; */
950 msg->type = LDAP_TAG_SearchResultReference;
954 case ASN1_APPLICATION(LDAP_TAG_ModifyRequest): {
955 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
956 msg->type = LDAP_TAG_ModifyRequest;
957 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_ModifyRequest));
958 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
959 asn1_start_tag(data, ASN1_SEQUENCE(0));
964 while (asn1_tag_remaining(data) > 0) {
967 asn1_start_tag(data, ASN1_SEQUENCE(0));
968 asn1_read_enumerated(data, &mod.type);
969 ldap_decode_attrib(msg->mem_ctx, data, &mod.attrib);
971 if (!add_mod_to_array_talloc(msg->mem_ctx, &mod,
972 &r->mods, &r->num_mods))
981 case ASN1_APPLICATION(LDAP_TAG_ModifyResponse): {
982 struct ldap_Result *r = &msg->r.ModifyResponse;
983 msg->type = LDAP_TAG_ModifyResponse;
984 ldap_decode_response(msg->mem_ctx, data,
985 LDAP_TAG_ModifyResponse, r);
989 case ASN1_APPLICATION(LDAP_TAG_AddRequest): {
990 struct ldap_AddRequest *r = &msg->r.AddRequest;
991 msg->type = LDAP_TAG_AddRequest;
992 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_AddRequest));
993 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
995 r->attributes = NULL;
996 r->num_attributes = 0;
997 ldap_decode_attribs(msg->mem_ctx, data, &r->attributes,
1004 case ASN1_APPLICATION(LDAP_TAG_AddResponse): {
1005 struct ldap_Result *r = &msg->r.AddResponse;
1006 msg->type = LDAP_TAG_AddResponse;
1007 ldap_decode_response(msg->mem_ctx, data,
1008 LDAP_TAG_AddResponse, r);
1012 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest): {
1013 struct ldap_DelRequest *r = &msg->r.DelRequest;
1016 msg->type = LDAP_TAG_DelRequest;
1017 asn1_start_tag(data,
1018 ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest));
1019 len = asn1_tag_remaining(data);
1020 dn = talloc(msg->mem_ctx, len+1);
1023 asn1_read(data, dn, len);
1030 case ASN1_APPLICATION(LDAP_TAG_DelResponse): {
1031 struct ldap_Result *r = &msg->r.DelResponse;
1032 msg->type = LDAP_TAG_DelResponse;
1033 ldap_decode_response(msg->mem_ctx, data,
1034 LDAP_TAG_DelResponse, r);
1038 case ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest): {
1039 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
1040 msg->type = LDAP_TAG_ModifyDNRequest;
1041 asn1_start_tag(data,
1042 ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest));
1043 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
1044 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->newrdn);
1045 asn1_read_BOOLEAN(data, &r->deleteolddn);
1046 r->newsuperior = NULL;
1047 if (asn1_tag_remaining(data) > 0) {
1050 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0));
1051 len = asn1_tag_remaining(data);
1052 newsup = talloc(msg->mem_ctx, len+1);
1055 asn1_read(data, newsup, len);
1057 r->newsuperior = newsup;
1064 case ASN1_APPLICATION(LDAP_TAG_ModifyDNResponse): {
1065 struct ldap_Result *r = &msg->r.ModifyDNResponse;
1066 msg->type = LDAP_TAG_ModifyDNResponse;
1067 ldap_decode_response(msg->mem_ctx, data,
1068 LDAP_TAG_ModifyDNResponse, r);
1072 case ASN1_APPLICATION(LDAP_TAG_CompareRequest): {
1073 /* struct ldap_CompareRequest *r = &msg->r.CompareRequest; */
1074 msg->type = LDAP_TAG_CompareRequest;
1078 case ASN1_APPLICATION(LDAP_TAG_CompareResponse): {
1079 struct ldap_Result *r = &msg->r.CompareResponse;
1080 msg->type = LDAP_TAG_CompareResponse;
1081 ldap_decode_response(msg->mem_ctx, data,
1082 LDAP_TAG_CompareResponse, r);
1086 case ASN1_APPLICATION(LDAP_TAG_AbandonRequest): {
1087 /* struct ldap_AbandonRequest *r = &msg->r.AbandonRequest; */
1088 msg->type = LDAP_TAG_AbandonRequest;
1092 case ASN1_APPLICATION(LDAP_TAG_ExtendedRequest): {
1093 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
1094 DATA_BLOB tmp_blob = data_blob(NULL, 0);
1096 msg->type = LDAP_TAG_ExtendedRequest;
1097 asn1_start_tag(data,ASN1_APPLICATION(LDAP_TAG_ExtendedRequest));
1098 if (!asn1_read_ContextSimple(data, 0, &tmp_blob)) {
1101 r->oid = blob2string_talloc(msg->mem_ctx, tmp_blob);
1102 data_blob_free(&tmp_blob);
1107 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(1))) {
1108 asn1_read_ContextSimple(data, 1, &tmp_blob);
1109 r->value = data_blob_talloc(msg->mem_ctx, tmp_blob.data, tmp_blob.length);
1110 data_blob_free(&tmp_blob);
1112 r->value = data_blob(NULL, 0);
1119 case ASN1_APPLICATION(LDAP_TAG_ExtendedResponse): {
1120 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
1121 msg->type = LDAP_TAG_ExtendedResponse;
1122 ldap_decode_response(msg->mem_ctx, data,
1123 LDAP_TAG_ExtendedResponse, &r->response);
1124 /* I have to come across an operation that actually sends
1125 * something back to really see what's going on. The currently
1126 * needed pwdchange does not send anything back. */
1128 r->value.data = NULL;
1129 r->value.length = 0;
1137 return ((!data->has_error) && (data->nesting == NULL));
1140 BOOL ldap_parse_basic_url(TALLOC_CTX *mem_ctx, const char *url,
1141 char **host, uint16 *port, BOOL *ldaps)
1146 const char *p = url;
1148 /* skip leading "URL:" (if any) */
1149 if (strncasecmp( p, "URL:", 4) == 0) {
1153 /* Paranoia check */
1154 SMB_ASSERT(sizeof(protocol)>10 && sizeof(tmp_host)>254);
1156 sscanf(p, "%10[^:]://%254[^:/]:%d", protocol, tmp_host, &tmp_port);
1158 if (strequal(protocol, "ldap")) {
1161 } else if (strequal(protocol, "ldaps")) {
1165 DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
1172 *host = talloc_strdup(mem_ctx, tmp_host);
1174 return (*host != NULL);
1177 struct ldap_connection *new_ldap_connection(void)
1179 TALLOC_CTX *mem_ctx = talloc_init("ldap_connection");
1180 struct ldap_connection *result;
1182 if (mem_ctx == NULL)
1185 result = talloc(mem_ctx, sizeof(*result));
1190 result->mem_ctx = mem_ctx;
1191 result->next_msgid = 1;
1192 result->outstanding = NULL;
1193 result->searchid = 0;
1194 result->search_entries = NULL;
1195 result->auth_dn = NULL;
1196 result->simple_pw = NULL;
1197 result->gensec = NULL;
1202 BOOL ldap_connect(struct ldap_connection *conn, const char *url)
1207 if (!ldap_parse_basic_url(conn->mem_ctx, url, &conn->host,
1208 &conn->port, &conn->ldaps))
1211 hp = sys_gethostbyname(conn->host);
1213 if ((hp == NULL) || (hp->h_addr == NULL))
1216 putip((char *)&ip, (char *)hp->h_addr);
1218 conn->sock = open_socket_out(SOCK_STREAM, &ip, conn->port, LDAP_CONNECTION_TIMEOUT);
1220 return (conn->sock >= 0);
1223 BOOL ldap_set_simple_creds(struct ldap_connection *conn,
1224 const char *dn, const char *password)
1226 conn->auth_dn = talloc_strdup(conn->mem_ctx, dn);
1227 conn->simple_pw = talloc_strdup(conn->mem_ctx, password);
1229 return ((conn->auth_dn != NULL) && (conn->simple_pw != NULL));
1232 struct ldap_message *new_ldap_message(void)
1234 TALLOC_CTX *mem_ctx = talloc_init("ldap_message");
1235 struct ldap_message *result;
1237 if (mem_ctx == NULL)
1240 result = talloc(mem_ctx, sizeof(*result));
1245 result->mem_ctx = mem_ctx;
1249 void destroy_ldap_message(struct ldap_message *msg)
1252 talloc_destroy(msg->mem_ctx);
1255 BOOL ldap_send_msg(struct ldap_connection *conn, struct ldap_message *msg,
1256 const struct timeval *endtime)
1260 struct ldap_queue_entry *entry;
1262 msg->messageid = conn->next_msgid++;
1264 if (!ldap_encode(msg, &request))
1267 result = (write_data_until(conn->sock, request.data, request.length,
1268 endtime) == request.length);
1270 data_blob_free(&request);
1275 /* abandon and unbind don't expect results */
1277 if ((msg->type == LDAP_TAG_AbandonRequest) ||
1278 (msg->type == LDAP_TAG_UnbindRequest))
1281 entry = malloc(sizeof(*entry));
1286 entry->msgid = msg->messageid;
1288 DLIST_ADD(conn->outstanding, entry);
1293 BOOL ldap_receive_msg(struct ldap_connection *conn, struct ldap_message *msg,
1294 const struct timeval *endtime)
1296 struct asn1_data data;
1299 if (!asn1_read_sequence_until(conn->sock, &data, endtime))
1302 result = ldap_decode(&data, msg);
1308 static struct ldap_message *recv_from_queue(struct ldap_connection *conn,
1311 struct ldap_queue_entry *e;
1313 for (e = conn->outstanding; e != NULL; e = e->next) {
1315 if (e->msgid == msgid) {
1316 struct ldap_message *result = e->msg;
1317 DLIST_REMOVE(conn->outstanding, e);
1326 static void add_search_entry(struct ldap_connection *conn,
1327 struct ldap_message *msg)
1329 struct ldap_queue_entry *e = malloc(sizeof *e);
1335 DLIST_ADD_END(conn->search_entries, e, struct ldap_queue_entry *);
1339 static void fill_outstanding_request(struct ldap_connection *conn,
1340 struct ldap_message *msg)
1342 struct ldap_queue_entry *e;
1344 for (e = conn->outstanding; e != NULL; e = e->next) {
1345 if (e->msgid == msg->messageid) {
1351 /* This reply has not been expected, destroy the incoming msg */
1352 destroy_ldap_message(msg);
1356 struct ldap_message *ldap_receive(struct ldap_connection *conn, int msgid,
1357 const struct timeval *endtime)
1359 struct ldap_message *result = recv_from_queue(conn, msgid);
1365 struct asn1_data data;
1368 result = new_ldap_message();
1370 if (!asn1_read_sequence_until(conn->sock, &data, endtime))
1373 res = ldap_decode(&data, result);
1379 if (result->messageid == msgid)
1382 if (result->type == LDAP_TAG_SearchResultEntry) {
1383 add_search_entry(conn, result);
1385 fill_outstanding_request(conn, result);
1392 struct ldap_message *ldap_transaction(struct ldap_connection *conn,
1393 struct ldap_message *request)
1395 if (!ldap_send_msg(conn, request, NULL))
1398 return ldap_receive(conn, request->messageid, NULL);
1401 int ldap_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password)
1403 struct ldap_message *response;
1404 struct ldap_message *msg;
1405 const char *dn, *pw;
1406 int result = LDAP_OTHER;
1414 if (conn->auth_dn) {
1424 if (conn->simple_pw) {
1425 pw = conn->simple_pw;
1431 msg = new_ldap_simple_bind_msg(dn, pw);
1435 response = ldap_transaction(conn, msg);
1437 destroy_ldap_message(msg);
1441 result = response->r.BindResponse.response.resultcode;
1443 destroy_ldap_message(msg);
1444 destroy_ldap_message(response);
1449 int ldap_bind_sasl(struct ldap_connection *conn, const char *username, const char *domain, const char *password)
1452 TALLOC_CTX *mem_ctx = NULL;
1453 struct ldap_message *response;
1454 struct ldap_message *msg;
1455 DATA_BLOB input = data_blob(NULL, 0);
1456 DATA_BLOB output = data_blob(NULL, 0);
1457 int result = LDAP_OTHER;
1462 status = gensec_client_start(conn, &conn->gensec);
1463 if (!NT_STATUS_IS_OK(status)) {
1464 DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
1468 status = gensec_set_domain(conn->gensec, domain);
1469 if (!NT_STATUS_IS_OK(status)) {
1470 DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n",
1471 domain, nt_errstr(status)));
1475 status = gensec_set_username(conn->gensec, username);
1476 if (!NT_STATUS_IS_OK(status)) {
1477 DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n",
1478 username, nt_errstr(status)));
1482 status = gensec_set_password(conn->gensec, password);
1483 if (!NT_STATUS_IS_OK(status)) {
1484 DEBUG(1, ("Failed to start set GENSEC client password: %s\n",
1485 nt_errstr(status)));
1489 status = gensec_set_target_hostname(conn->gensec, conn->host);
1490 if (!NT_STATUS_IS_OK(status)) {
1491 DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n",
1492 nt_errstr(status)));
1496 status = gensec_start_mech_by_sasl_name(conn->gensec, "GSS-SPNEGO");
1497 if (!NT_STATUS_IS_OK(status)) {
1498 DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",
1499 nt_errstr(status)));
1503 mem_ctx = talloc_init("ldap_bind_sasl");
1507 status = gensec_update(conn->gensec, mem_ctx,
1512 if (NT_STATUS_IS_OK(status) && output.length == 0) {
1515 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
1519 msg = new_ldap_sasl_bind_msg("GSS-SPNEGO", &output);
1523 response = ldap_transaction(conn, msg);
1524 destroy_ldap_message(msg);
1530 result = response->r.BindResponse.response.resultcode;
1532 if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
1536 status = gensec_update(conn->gensec, mem_ctx,
1537 response->r.BindResponse.SASL.secblob,
1540 destroy_ldap_message(response);
1545 gensec_end(&conn->gensec);
1547 talloc_destroy(mem_ctx);
1552 BOOL ldap_setup_connection(struct ldap_connection *conn,
1553 const char *url, const char *userdn, const char *password)
1557 if (!ldap_connect(conn, url)) {
1561 result = ldap_bind_simple(conn, userdn, password);
1562 if (result == LDAP_SUCCESS) {
1569 BOOL ldap_setup_connection_with_sasl(struct ldap_connection *conn, const char *url, const char *username, const char *domain, const char *password)
1573 if (!ldap_connect(conn, url)) {
1577 result = ldap_bind_sasl(conn, username, domain, password);
1578 if (result == LDAP_SUCCESS) {
1585 static BOOL ldap_abandon_message(struct ldap_connection *conn, int msgid,
1586 const struct timeval *endtime)
1588 struct ldap_message *msg = new_ldap_message();
1594 msg->type = LDAP_TAG_AbandonRequest;
1595 msg->r.AbandonRequest.messageid = msgid;
1597 result = ldap_send_msg(conn, msg, endtime);
1598 destroy_ldap_message(msg);
1602 struct ldap_message *new_ldap_search_message(const char *base,
1603 enum ldap_scope scope,
1606 const char **attributes)
1608 struct ldap_message *res = new_ldap_message();
1613 res->type = LDAP_TAG_SearchRequest;
1614 res->r.SearchRequest.basedn = base;
1615 res->r.SearchRequest.scope = scope;
1616 res->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
1617 res->r.SearchRequest.timelimit = 0;
1618 res->r.SearchRequest.sizelimit = 0;
1619 res->r.SearchRequest.attributesonly = False;
1620 res->r.SearchRequest.filter = filter;
1621 res->r.SearchRequest.num_attributes = num_attributes;
1622 res->r.SearchRequest.attributes = attributes;
1626 struct ldap_message *new_ldap_simple_bind_msg(const char *dn, const char *pw)
1628 struct ldap_message *res = new_ldap_message();
1633 res->type = LDAP_TAG_BindRequest;
1634 res->r.BindRequest.version = 3;
1635 res->r.BindRequest.dn = talloc_strdup(res->mem_ctx, dn);
1636 res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SIMPLE;
1637 res->r.BindRequest.creds.password = talloc_strdup(res->mem_ctx, pw);
1641 struct ldap_message *new_ldap_sasl_bind_msg(const char *sasl_mechanism, DATA_BLOB *secblob)
1643 struct ldap_message *res = new_ldap_message();
1648 res->type = LDAP_TAG_BindRequest;
1649 res->r.BindRequest.version = 3;
1650 res->r.BindRequest.dn = "";
1651 res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SASL;
1652 res->r.BindRequest.creds.SASL.mechanism = talloc_strdup(res->mem_ctx, sasl_mechanism);
1653 res->r.BindRequest.creds.SASL.secblob = *secblob;
1657 BOOL ldap_setsearchent(struct ldap_connection *conn, struct ldap_message *msg,
1658 const struct timeval *endtime)
1660 if ((conn->searchid != 0) &&
1661 (!ldap_abandon_message(conn, conn->searchid, endtime)))
1664 conn->searchid = conn->next_msgid;
1665 return ldap_send_msg(conn, msg, endtime);
1668 struct ldap_message *ldap_getsearchent(struct ldap_connection *conn,
1669 const struct timeval *endtime)
1671 struct ldap_message *result;
1673 if (conn->search_entries != NULL) {
1674 struct ldap_queue_entry *e = conn->search_entries;
1677 DLIST_REMOVE(conn->search_entries, e);
1682 result = ldap_receive(conn, conn->searchid, endtime);
1684 if (result->type == LDAP_TAG_SearchResultEntry)
1687 if (result->type == LDAP_TAG_SearchResultDone) {
1688 /* TODO: Handle Paged Results */
1689 destroy_ldap_message(result);
1693 /* TODO: Handle Search References here */
1697 void ldap_endsearchent(struct ldap_connection *conn,
1698 const struct timeval *endtime)
1700 struct ldap_queue_entry *e;
1702 e = conn->search_entries;
1705 struct ldap_queue_entry *next = e->next;
1706 DLIST_REMOVE(conn->search_entries, e);
1712 struct ldap_message *ldap_searchone(struct ldap_connection *conn,
1713 struct ldap_message *msg,
1714 const struct timeval *endtime)
1716 struct ldap_message *res1, *res2 = NULL;
1717 if (!ldap_setsearchent(conn, msg, endtime))
1720 res1 = ldap_getsearchent(conn, endtime);
1723 res2 = ldap_getsearchent(conn, endtime);
1725 ldap_endsearchent(conn, endtime);
1731 /* More than one entry */
1732 destroy_ldap_message(res1);
1733 destroy_ldap_message(res2);
1740 BOOL ldap_find_single_value(struct ldap_message *msg, const char *attr,
1744 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
1746 if (msg->type != LDAP_TAG_SearchResultEntry)
1749 for (i=0; i<r->num_attributes; i++) {
1750 if (strequal(attr, r->attributes[i].name)) {
1751 if (r->attributes[i].num_values != 1)
1754 *value = r->attributes[i].values[0];
1761 BOOL ldap_find_single_string(struct ldap_message *msg, const char *attr,
1762 TALLOC_CTX *mem_ctx, char **value)
1766 if (!ldap_find_single_value(msg, attr, &blob))
1769 *value = talloc(mem_ctx, blob.length+1);
1774 memcpy(*value, blob.data, blob.length);
1775 (*value)[blob.length] = '\0';
1779 BOOL ldap_find_single_int(struct ldap_message *msg, const char *attr,
1787 if (!ldap_find_single_value(msg, attr, &blob))
1790 val = malloc(blob.length+1);
1794 memcpy(val, blob.data, blob.length);
1795 val[blob.length] = '\0';
1800 *value = strtol(val, NULL, 10);
1810 int ldap_error(struct ldap_connection *conn)
1815 NTSTATUS ldap2nterror(int ldaperror)
1817 return NT_STATUS_OK;