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(ret->u.list.elements,
183 sizeof(struct ldap_parse_tree) *
184 (ret->u.list.num_elements+1));
189 ret->u.list.elements = e;
190 ret->u.list.elements[ret->u.list.num_elements] = next;
191 ret->u.list.num_elements++;
192 while (isspace(*s)) s++;
200 <not> ::= '!' <filter>
202 static struct ldap_parse_tree *ldap_parse_not(TALLOC_CTX *mem_ctx, const char *s)
204 struct ldap_parse_tree *ret;
206 ret = talloc(mem_ctx, sizeof(*ret));
212 ret->operation = LDAP_OP_NOT;
213 ret->u.not.child = ldap_parse_filter(mem_ctx, &s);
214 if (!ret->u.not.child)
222 <filtercomp> ::= <and> | <or> | <not> | <simple>
224 static struct ldap_parse_tree *ldap_parse_filtercomp(TALLOC_CTX *mem_ctx,
227 while (isspace(*s)) s++;
231 return ldap_parse_filterlist(mem_ctx, LDAP_OP_AND, s+1);
234 return ldap_parse_filterlist(mem_ctx, LDAP_OP_OR, s+1);
237 return ldap_parse_not(mem_ctx, s+1);
244 return ldap_parse_simple(mem_ctx, s);
249 <filter> ::= '(' <filtercomp> ')'
251 static struct ldap_parse_tree *ldap_parse_filter(TALLOC_CTX *mem_ctx,
256 struct ldap_parse_tree *ret;
258 l = ldap_parse_lex(mem_ctx, s, LDAP_ALL_SEP);
263 if (strcmp(l, "(") != 0) {
273 s2 = talloc_strndup(mem_ctx, *s, p - *s);
279 ret = ldap_parse_filtercomp(mem_ctx, s2);
287 main parser entry point. Takes a search string and returns a parse tree
289 expression ::= <simple> | <filter>
291 static struct ldap_parse_tree *ldap_parse_tree(TALLOC_CTX *mem_ctx, const char *s)
293 while (isspace(*s)) s++;
296 return ldap_parse_filter(mem_ctx, &s);
299 return ldap_parse_simple(mem_ctx, s);
302 static BOOL ldap_push_filter(ASN1_DATA *data, struct ldap_parse_tree *tree)
304 switch (tree->operation) {
305 case LDAP_OP_SIMPLE: {
306 if ((tree->u.simple.value.length == 1) &&
307 (((char *)(tree->u.simple.value.data))[0] == '*')) {
308 /* Just a presence test */
309 asn1_push_tag(data, 0x87);
310 asn1_write(data, tree->u.simple.attr,
311 strlen(tree->u.simple.attr));
313 return !data->has_error;
316 /* Equality is all we currently do... */
317 asn1_push_tag(data, 0xa3);
318 asn1_write_OctetString(data, tree->u.simple.attr,
319 strlen(tree->u.simple.attr));
320 asn1_write_OctetString(data, tree->u.simple.value.data,
321 tree->u.simple.value.length);
329 asn1_push_tag(data, 0xa0);
330 for (i=0; i<tree->u.list.num_elements; i++) {
331 ldap_push_filter(data, tree->u.list.elements[i]);
340 asn1_push_tag(data, 0xa1);
341 for (i=0; i<tree->u.list.num_elements; i++) {
342 ldap_push_filter(data, tree->u.list.elements[i]);
350 return !data->has_error;
353 static void ldap_encode_response(enum ldap_request_tag tag,
354 struct ldap_Result *result,
357 asn1_push_tag(data, ASN1_APPLICATION(tag));
358 asn1_write_enumerated(data, result->resultcode);
359 asn1_write_OctetString(data, result->dn,
360 (result->dn) ? strlen(result->dn) : 0);
361 asn1_write_OctetString(data, result->errormessage,
362 (result->errormessage) ?
363 strlen(result->errormessage) : 0);
364 if (result->referral != NULL)
365 asn1_write_OctetString(data, result->referral,
366 strlen(result->referral));
370 BOOL ldap_encode(struct ldap_message *msg, DATA_BLOB *result)
376 asn1_push_tag(&data, ASN1_SEQUENCE(0));
377 asn1_write_Integer(&data, msg->messageid);
380 case LDAP_TAG_BindRequest: {
381 struct ldap_BindRequest *r = &msg->r.BindRequest;
382 asn1_push_tag(&data, ASN1_APPLICATION(LDAP_TAG_BindRequest));
383 asn1_write_Integer(&data, r->version);
384 asn1_write_OctetString(&data, r->dn,
385 (r->dn != NULL) ? strlen(r->dn) : 0);
387 switch (r->mechanism) {
388 case LDAP_AUTH_MECH_SIMPLE:
389 /* context, primitive */
390 asn1_push_tag(&data, r->mechanism | 0x80);
391 asn1_write(&data, r->creds.password,
392 strlen(r->creds.password));
395 case LDAP_AUTH_MECH_SASL:
396 /* context, constructed */
397 asn1_push_tag(&data, r->mechanism | 0xa0);
398 asn1_write_OctetString(&data, r->creds.SASL.mechanism,
399 strlen(r->creds.SASL.mechanism));
400 asn1_write_OctetString(&data, r->creds.SASL.secblob.data,
401 r->creds.SASL.secblob.length);
412 case LDAP_TAG_BindResponse: {
413 struct ldap_BindResponse *r = &msg->r.BindResponse;
414 ldap_encode_response(msg->type, &r->response, &data);
417 case LDAP_TAG_UnbindRequest: {
418 /* struct ldap_UnbindRequest *r = &msg->r.UnbindRequest; */
421 case LDAP_TAG_SearchRequest: {
422 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
423 asn1_push_tag(&data, ASN1_APPLICATION(LDAP_TAG_SearchRequest));
424 asn1_write_OctetString(&data, r->basedn, strlen(r->basedn));
425 asn1_write_enumerated(&data, r->scope);
426 asn1_write_enumerated(&data, r->deref);
427 asn1_write_Integer(&data, r->sizelimit);
428 asn1_write_Integer(&data, r->timelimit);
429 asn1_write_BOOLEAN(&data, r->attributesonly);
432 TALLOC_CTX *mem_ctx = talloc_init("ldap_parse_tree");
433 struct ldap_parse_tree *tree;
438 tree = ldap_parse_tree(mem_ctx, r->filter);
443 ldap_push_filter(&data, tree);
445 talloc_destroy(mem_ctx);
448 asn1_push_tag(&data, ASN1_SEQUENCE(0));
449 for (i=0; i<r->num_attributes; i++) {
450 asn1_write_OctetString(&data, r->attributes[i],
451 strlen(r->attributes[i]));
458 case LDAP_TAG_SearchResultEntry: {
459 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
460 asn1_push_tag(&data, ASN1_APPLICATION(LDAP_TAG_SearchResultEntry));
461 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
462 asn1_push_tag(&data, ASN1_SEQUENCE(0));
463 for (i=0; i<r->num_attributes; i++) {
464 struct ldap_attribute *attr = &r->attributes[i];
465 asn1_push_tag(&data, ASN1_SEQUENCE(0));
466 asn1_write_OctetString(&data, attr->name,
468 asn1_push_tag(&data, ASN1_SEQUENCE(1));
469 for (j=0; j<attr->num_values; j++) {
470 asn1_write_OctetString(&data,
471 attr->values[j].data,
472 attr->values[j].length);
481 case LDAP_TAG_SearchResultDone: {
482 struct ldap_Result *r = &msg->r.SearchResultDone;
483 ldap_encode_response(msg->type, r, &data);
486 case LDAP_TAG_ModifyRequest: {
487 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
488 asn1_push_tag(&data, ASN1_APPLICATION(LDAP_TAG_ModifyRequest));
489 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
490 asn1_push_tag(&data, ASN1_SEQUENCE(0));
492 for (i=0; i<r->num_mods; i++) {
493 struct ldap_attribute *attrib = &r->mods[i].attrib;
494 asn1_push_tag(&data, ASN1_SEQUENCE(0));
495 asn1_write_enumerated(&data, r->mods[i].type);
496 asn1_push_tag(&data, ASN1_SEQUENCE(0));
497 asn1_write_OctetString(&data, attrib->name,
498 strlen(attrib->name));
499 asn1_push_tag(&data, ASN1_SET);
500 for (j=0; j<attrib->num_values; j++) {
501 asn1_write_OctetString(&data,
502 attrib->values[j].data,
503 attrib->values[j].length);
515 case LDAP_TAG_ModifyResponse: {
516 struct ldap_Result *r = &msg->r.ModifyResponse;
517 ldap_encode_response(msg->type, r, &data);
520 case LDAP_TAG_AddRequest: {
521 struct ldap_AddRequest *r = &msg->r.AddRequest;
522 asn1_push_tag(&data, ASN1_APPLICATION(LDAP_TAG_AddRequest));
523 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
524 asn1_push_tag(&data, ASN1_SEQUENCE(0));
526 for (i=0; i<r->num_attributes; i++) {
527 struct ldap_attribute *attrib = &r->attributes[i];
528 asn1_push_tag(&data, ASN1_SEQUENCE(0));
529 asn1_write_OctetString(&data, attrib->name,
530 strlen(attrib->name));
531 asn1_push_tag(&data, ASN1_SET);
532 for (j=0; j<r->attributes[i].num_values; j++) {
533 asn1_write_OctetString(&data,
534 attrib->values[j].data,
535 attrib->values[j].length);
544 case LDAP_TAG_AddResponse: {
545 struct ldap_Result *r = &msg->r.AddResponse;
546 ldap_encode_response(msg->type, r, &data);
549 case LDAP_TAG_DelRequest: {
550 struct ldap_DelRequest *r = &msg->r.DelRequest;
552 ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest));
553 asn1_write(&data, r->dn, strlen(r->dn));
557 case LDAP_TAG_DelResponse: {
558 struct ldap_Result *r = &msg->r.DelResponse;
559 ldap_encode_response(msg->type, r, &data);
562 case LDAP_TAG_ModifyDNRequest: {
563 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
565 ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest));
566 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
567 asn1_write_OctetString(&data, r->newrdn, strlen(r->newrdn));
568 asn1_write_BOOLEAN(&data, r->deleteolddn);
569 if (r->newsuperior != NULL) {
570 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
571 asn1_write(&data, r->newsuperior,
572 strlen(r->newsuperior));
578 case LDAP_TAG_ModifyDNResponse: {
579 struct ldap_Result *r = &msg->r.ModifyDNResponse;
580 ldap_encode_response(msg->type, r, &data);
583 case LDAP_TAG_CompareRequest: {
584 struct ldap_CompareRequest *r = &msg->r.CompareRequest;
586 ASN1_APPLICATION(LDAP_TAG_CompareRequest));
587 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
588 asn1_push_tag(&data, ASN1_SEQUENCE(0));
589 asn1_write_OctetString(&data, r->attribute,
590 strlen(r->attribute));
591 asn1_write_OctetString(&data, r->value,
597 case LDAP_TAG_CompareResponse: {
598 /* struct ldap_Result *r = &msg->r.CompareResponse; */
601 case LDAP_TAG_AbandonRequest: {
602 struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
604 ASN1_APPLICATION_SIMPLE(LDAP_TAG_AbandonRequest));
605 asn1_write_implicit_Integer(&data, r->messageid);
609 case LDAP_TAG_SearchResultReference: {
610 /* struct ldap_SearchResRef *r = &msg->r.SearchResultReference; */
613 case LDAP_TAG_ExtendedRequest: {
614 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
615 asn1_push_tag(&data, ASN1_APPLICATION(LDAP_TAG_ExtendedRequest));
616 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
617 asn1_write(&data, r->oid, strlen(r->oid));
619 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(1));
620 asn1_write(&data, r->value.data, r->value.length);
625 case LDAP_TAG_ExtendedResponse: {
626 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
627 ldap_encode_response(msg->type, &r->response, &data);
635 *result = data_blob(data.data, data.length);
640 static const char *blob2string_talloc(TALLOC_CTX *mem_ctx,
643 char *result = talloc(mem_ctx, blob.length+1);
644 memcpy(result, blob.data, blob.length);
645 result[blob.length] = '\0';
649 static BOOL asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
654 if (!asn1_read_OctetString(data, &string))
656 *result = blob2string_talloc(mem_ctx, string);
657 data_blob_free(&string);
661 static void ldap_decode_response(TALLOC_CTX *mem_ctx,
663 enum ldap_request_tag tag,
664 struct ldap_Result *result)
666 asn1_start_tag(data, ASN1_APPLICATION(tag));
667 asn1_read_enumerated(data, &result->resultcode);
668 asn1_read_OctetString_talloc(mem_ctx, data, &result->dn);
669 asn1_read_OctetString_talloc(mem_ctx, data, &result->errormessage);
670 if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
671 asn1_start_tag(data, ASN1_CONTEXT(3));
672 asn1_read_OctetString_talloc(mem_ctx, data, &result->referral);
675 result->referral = NULL;
680 static BOOL ldap_decode_filter(TALLOC_CTX *mem_ctx, ASN1_DATA *data,
683 uint8 filter_tag, tag_desc;
685 if (!asn1_peek_uint8(data, &filter_tag))
688 tag_desc = filter_tag;
689 filter_tag &= 0x1f; /* strip off the asn1 stuff */
694 /* AND of one or more filters */
695 if (tag_desc != 0xa0) /* context compount */
698 asn1_start_tag(data, ASN1_CONTEXT(0));
700 *filter = talloc_strdup(mem_ctx, "(&");
704 while (asn1_tag_remaining(data) > 0) {
706 if (!ldap_decode_filter(mem_ctx, data, &subfilter))
708 *filter = talloc_asprintf(mem_ctx, "%s%s", *filter,
715 *filter = talloc_asprintf(mem_ctx, "%s)", *filter);
719 /* OR of one or more filters */
720 if (tag_desc != 0xa0) /* context compount */
723 asn1_start_tag(data, ASN1_CONTEXT(1));
725 *filter = talloc_strdup(mem_ctx, "(|");
729 while (asn1_tag_remaining(data) > 0) {
731 if (!ldap_decode_filter(mem_ctx, data, &subfilter))
733 *filter = talloc_asprintf(mem_ctx, "%s%s", *filter,
741 *filter = talloc_asprintf(mem_ctx, "%s)", *filter);
746 const char *attrib, *value;
747 if (tag_desc != 0xa0) /* context compound */
749 asn1_start_tag(data, ASN1_CONTEXT(3));
750 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
751 asn1_read_OctetString_talloc(mem_ctx, data, &value);
753 if ((data->has_error) || (attrib == NULL) || (value == NULL))
755 *filter = talloc_asprintf(mem_ctx, "(%s=%s)", attrib, value);
759 /* Normal presence, "attribute=*" */
762 if (tag_desc != 0x80) /* context simple */
764 if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(7)))
766 attr_len = asn1_tag_remaining(data);
767 attr_name = malloc(attr_len+1);
768 if (attr_name == NULL)
770 asn1_read(data, attr_name, attr_len);
771 attr_name[attr_len] = '\0';
772 *filter = talloc_asprintf(mem_ctx, "(%s=*)", attr_name);
773 SAFE_FREE(attr_name);
785 static void ldap_decode_attrib(TALLOC_CTX *mem_ctx, ASN1_DATA *data,
786 struct ldap_attribute *attrib)
788 asn1_start_tag(data, ASN1_SEQUENCE(0));
789 asn1_read_OctetString_talloc(mem_ctx, data, &attrib->name);
790 asn1_start_tag(data, ASN1_SET);
791 while (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
793 struct ldap_val value;
794 asn1_read_OctetString(data, &blob);
795 value.data = blob.data;
796 value.length = blob.length;
797 add_value_to_attrib(mem_ctx, &value, attrib);
798 data_blob_free(&blob);
805 static void ldap_decode_attribs(TALLOC_CTX *mem_ctx, ASN1_DATA *data,
806 struct ldap_attribute **attributes,
809 asn1_start_tag(data, ASN1_SEQUENCE(0));
810 while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
811 struct ldap_attribute attrib;
813 ldap_decode_attrib(mem_ctx, data, &attrib);
814 add_attrib_to_array_talloc(mem_ctx, &attrib,
815 attributes, num_attributes);
820 BOOL ldap_decode(ASN1_DATA *data, struct ldap_message *msg)
824 asn1_start_tag(data, ASN1_SEQUENCE(0));
825 asn1_read_Integer(data, &msg->messageid);
827 if (!asn1_peek_uint8(data, &tag))
832 case ASN1_APPLICATION(LDAP_TAG_BindRequest): {
833 struct ldap_BindRequest *r = &msg->r.BindRequest;
834 msg->type = LDAP_TAG_BindRequest;
835 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_BindRequest));
836 asn1_read_Integer(data, &r->version);
837 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
838 if (asn1_peek_tag(data, 0x80)) {
840 r->creds.password = "";
841 /* Mechanism 0 (SIMPLE) */
842 asn1_start_tag(data, 0x80);
843 pwlen = asn1_tag_remaining(data);
845 char *pw = talloc(msg->mem_ctx, pwlen+1);
846 asn1_read(data, pw, pwlen);
848 r->creds.password = pw;
856 case ASN1_APPLICATION(LDAP_TAG_BindResponse): {
857 struct ldap_BindResponse *r = &msg->r.BindResponse;
858 msg->type = LDAP_TAG_BindResponse;
859 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_BindResponse));
860 asn1_read_enumerated(data, &r->response.resultcode);
861 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->response.dn);
862 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->response.errormessage);
863 if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
864 asn1_start_tag(data, ASN1_CONTEXT(3));
865 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->response.referral);
868 r->response.referral = NULL;
870 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(7))) {
871 DATA_BLOB tmp_blob = data_blob(NULL, 0);
872 asn1_read_ContextSimple(data, 7, &tmp_blob);
873 r->SASL.secblob = data_blob_talloc(msg->mem_ctx, tmp_blob.data, tmp_blob.length);
874 data_blob_free(&tmp_blob);
876 r->SASL.secblob = data_blob(NULL, 0);
882 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_UnbindRequest): {
883 msg->type = LDAP_TAG_UnbindRequest;
884 asn1_start_tag(data, ASN1_APPLICATION_SIMPLE(LDAP_TAG_UnbindRequest));
889 case ASN1_APPLICATION(LDAP_TAG_SearchRequest): {
890 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
891 msg->type = LDAP_TAG_SearchRequest;
892 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_SearchRequest));
893 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->basedn);
894 asn1_read_enumerated(data, (int *)&(r->scope));
895 asn1_read_enumerated(data, (int *)&(r->deref));
896 asn1_read_Integer(data, &r->sizelimit);
897 asn1_read_Integer(data, &r->timelimit);
898 asn1_read_BOOLEAN(data, &r->attributesonly);
900 /* Maybe create a TALLOC_CTX for the filter? This can waste
901 * quite a bit of memory recursing down. */
902 ldap_decode_filter(msg->mem_ctx, data, &r->filter);
904 asn1_start_tag(data, ASN1_SEQUENCE(0));
906 r->num_attributes = 0;
907 r->attributes = NULL;
909 while (asn1_tag_remaining(data) > 0) {
911 if (!asn1_read_OctetString_talloc(msg->mem_ctx, data,
914 if (!add_string_to_array(msg->mem_ctx, attr,
925 case ASN1_APPLICATION(LDAP_TAG_SearchResultEntry): {
926 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
927 msg->type = LDAP_TAG_SearchResultEntry;
928 r->attributes = NULL;
929 r->num_attributes = 0;
931 ASN1_APPLICATION(LDAP_TAG_SearchResultEntry));
932 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
933 ldap_decode_attribs(msg->mem_ctx, data, &r->attributes,
939 case ASN1_APPLICATION(LDAP_TAG_SearchResultDone): {
940 struct ldap_Result *r = &msg->r.SearchResultDone;
941 msg->type = LDAP_TAG_SearchResultDone;
942 ldap_decode_response(msg->mem_ctx, data,
943 LDAP_TAG_SearchResultDone, r);
947 case ASN1_APPLICATION(LDAP_TAG_SearchResultReference): {
948 /* struct ldap_SearchResRef *r = &msg->r.SearchResultReference; */
949 msg->type = LDAP_TAG_SearchResultReference;
953 case ASN1_APPLICATION(LDAP_TAG_ModifyRequest): {
954 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
955 msg->type = LDAP_TAG_ModifyRequest;
956 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_ModifyRequest));
957 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
958 asn1_start_tag(data, ASN1_SEQUENCE(0));
963 while (asn1_tag_remaining(data) > 0) {
966 asn1_start_tag(data, ASN1_SEQUENCE(0));
967 asn1_read_enumerated(data, &mod.type);
968 ldap_decode_attrib(msg->mem_ctx, data, &mod.attrib);
970 if (!add_mod_to_array_talloc(msg->mem_ctx, &mod,
971 &r->mods, &r->num_mods))
980 case ASN1_APPLICATION(LDAP_TAG_ModifyResponse): {
981 struct ldap_Result *r = &msg->r.ModifyResponse;
982 msg->type = LDAP_TAG_ModifyResponse;
983 ldap_decode_response(msg->mem_ctx, data,
984 LDAP_TAG_ModifyResponse, r);
988 case ASN1_APPLICATION(LDAP_TAG_AddRequest): {
989 struct ldap_AddRequest *r = &msg->r.AddRequest;
990 msg->type = LDAP_TAG_AddRequest;
991 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_AddRequest));
992 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
994 r->attributes = NULL;
995 r->num_attributes = 0;
996 ldap_decode_attribs(msg->mem_ctx, data, &r->attributes,
1003 case ASN1_APPLICATION(LDAP_TAG_AddResponse): {
1004 struct ldap_Result *r = &msg->r.AddResponse;
1005 msg->type = LDAP_TAG_AddResponse;
1006 ldap_decode_response(msg->mem_ctx, data,
1007 LDAP_TAG_AddResponse, r);
1011 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest): {
1012 struct ldap_DelRequest *r = &msg->r.DelRequest;
1015 msg->type = LDAP_TAG_DelRequest;
1016 asn1_start_tag(data,
1017 ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest));
1018 len = asn1_tag_remaining(data);
1019 dn = talloc(msg->mem_ctx, len+1);
1022 asn1_read(data, dn, len);
1029 case ASN1_APPLICATION(LDAP_TAG_DelResponse): {
1030 struct ldap_Result *r = &msg->r.DelResponse;
1031 msg->type = LDAP_TAG_DelResponse;
1032 ldap_decode_response(msg->mem_ctx, data,
1033 LDAP_TAG_DelResponse, r);
1037 case ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest): {
1038 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
1039 msg->type = LDAP_TAG_ModifyDNRequest;
1040 asn1_start_tag(data,
1041 ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest));
1042 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
1043 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->newrdn);
1044 asn1_read_BOOLEAN(data, &r->deleteolddn);
1045 r->newsuperior = NULL;
1046 if (asn1_tag_remaining(data) > 0) {
1049 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0));
1050 len = asn1_tag_remaining(data);
1051 newsup = talloc(msg->mem_ctx, len+1);
1054 asn1_read(data, newsup, len);
1056 r->newsuperior = newsup;
1063 case ASN1_APPLICATION(LDAP_TAG_ModifyDNResponse): {
1064 struct ldap_Result *r = &msg->r.ModifyDNResponse;
1065 msg->type = LDAP_TAG_ModifyDNResponse;
1066 ldap_decode_response(msg->mem_ctx, data,
1067 LDAP_TAG_ModifyDNResponse, r);
1071 case ASN1_APPLICATION(LDAP_TAG_CompareRequest): {
1072 /* struct ldap_CompareRequest *r = &msg->r.CompareRequest; */
1073 msg->type = LDAP_TAG_CompareRequest;
1077 case ASN1_APPLICATION(LDAP_TAG_CompareResponse): {
1078 struct ldap_Result *r = &msg->r.CompareResponse;
1079 msg->type = LDAP_TAG_CompareResponse;
1080 ldap_decode_response(msg->mem_ctx, data,
1081 LDAP_TAG_CompareResponse, r);
1085 case ASN1_APPLICATION(LDAP_TAG_AbandonRequest): {
1086 /* struct ldap_AbandonRequest *r = &msg->r.AbandonRequest; */
1087 msg->type = LDAP_TAG_AbandonRequest;
1091 case ASN1_APPLICATION(LDAP_TAG_ExtendedRequest): {
1092 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
1093 DATA_BLOB tmp_blob = data_blob(NULL, 0);
1095 msg->type = LDAP_TAG_ExtendedRequest;
1096 asn1_start_tag(data,ASN1_APPLICATION(LDAP_TAG_ExtendedRequest));
1097 if (!asn1_read_ContextSimple(data, 0, &tmp_blob)) {
1100 r->oid = blob2string_talloc(msg->mem_ctx, tmp_blob);
1101 data_blob_free(&tmp_blob);
1106 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(1))) {
1107 asn1_read_ContextSimple(data, 1, &tmp_blob);
1108 r->value = data_blob_talloc(msg->mem_ctx, tmp_blob.data, tmp_blob.length);
1109 data_blob_free(&tmp_blob);
1111 r->value = data_blob(NULL, 0);
1118 case ASN1_APPLICATION(LDAP_TAG_ExtendedResponse): {
1119 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
1120 msg->type = LDAP_TAG_ExtendedResponse;
1121 ldap_decode_response(msg->mem_ctx, data,
1122 LDAP_TAG_ExtendedResponse, &r->response);
1123 /* I have to come across an operation that actually sends
1124 * something back to really see what's going on. The currently
1125 * needed pwdchange does not send anything back. */
1127 r->value.data = NULL;
1128 r->value.length = 0;
1136 return ((!data->has_error) && (data->nesting == NULL));
1139 BOOL ldap_parse_basic_url(TALLOC_CTX *mem_ctx, const char *url,
1140 char **host, uint16 *port, BOOL *ldaps)
1145 const char *p = url;
1147 /* skip leading "URL:" (if any) */
1148 if (strncasecmp( p, "URL:", 4) == 0) {
1152 /* Paranoia check */
1153 SMB_ASSERT(sizeof(protocol)>10 && sizeof(tmp_host)>254);
1155 sscanf(p, "%10[^:]://%254[^:/]:%d", protocol, tmp_host, &tmp_port);
1157 if (strequal(protocol, "ldap")) {
1160 } else if (strequal(protocol, "ldaps")) {
1164 DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
1171 *host = talloc_strdup(mem_ctx, tmp_host);
1173 return (*host != NULL);
1176 struct ldap_connection *new_ldap_connection(void)
1178 TALLOC_CTX *mem_ctx = talloc_init("ldap_connection");
1179 struct ldap_connection *result;
1181 if (mem_ctx == NULL)
1184 result = talloc(mem_ctx, sizeof(*result));
1189 result->mem_ctx = mem_ctx;
1190 result->next_msgid = 1;
1191 result->outstanding = NULL;
1192 result->searchid = 0;
1193 result->search_entries = NULL;
1194 result->auth_dn = NULL;
1195 result->simple_pw = NULL;
1196 result->gensec = NULL;
1201 BOOL ldap_connect(struct ldap_connection *conn, const char *url)
1206 if (!ldap_parse_basic_url(conn->mem_ctx, url, &conn->host,
1207 &conn->port, &conn->ldaps))
1210 hp = sys_gethostbyname(conn->host);
1212 if ((hp == NULL) || (hp->h_addr == NULL))
1215 putip((char *)&ip, (char *)hp->h_addr);
1217 conn->sock = open_socket_out(SOCK_STREAM, &ip, conn->port, LDAP_CONNECTION_TIMEOUT);
1219 return (conn->sock >= 0);
1222 BOOL ldap_set_simple_creds(struct ldap_connection *conn,
1223 const char *dn, const char *password)
1225 conn->auth_dn = talloc_strdup(conn->mem_ctx, dn);
1226 conn->simple_pw = talloc_strdup(conn->mem_ctx, password);
1228 return ((conn->auth_dn != NULL) && (conn->simple_pw != NULL));
1231 struct ldap_message *new_ldap_message(void)
1233 TALLOC_CTX *mem_ctx = talloc_init("ldap_message");
1234 struct ldap_message *result;
1236 if (mem_ctx == NULL)
1239 result = talloc(mem_ctx, sizeof(*result));
1244 result->mem_ctx = mem_ctx;
1248 void destroy_ldap_message(struct ldap_message *msg)
1251 talloc_destroy(msg->mem_ctx);
1254 BOOL ldap_send_msg(struct ldap_connection *conn, struct ldap_message *msg,
1255 const struct timeval *endtime)
1259 struct ldap_queue_entry *entry;
1261 msg->messageid = conn->next_msgid++;
1263 if (!ldap_encode(msg, &request))
1266 result = (write_data_until(conn->sock, request.data, request.length,
1267 endtime) == request.length);
1269 data_blob_free(&request);
1274 /* abandon and unbind don't expect results */
1276 if ((msg->type == LDAP_TAG_AbandonRequest) ||
1277 (msg->type == LDAP_TAG_UnbindRequest))
1280 entry = malloc(sizeof(*entry));
1285 entry->msgid = msg->messageid;
1287 DLIST_ADD(conn->outstanding, entry);
1292 BOOL ldap_receive_msg(struct ldap_connection *conn, struct ldap_message *msg,
1293 const struct timeval *endtime)
1295 struct asn1_data data;
1298 if (!asn1_read_sequence_until(conn->sock, &data, endtime))
1301 result = ldap_decode(&data, msg);
1307 static struct ldap_message *recv_from_queue(struct ldap_connection *conn,
1310 struct ldap_queue_entry *e;
1312 for (e = conn->outstanding; e != NULL; e = e->next) {
1314 if (e->msgid == msgid) {
1315 struct ldap_message *result = e->msg;
1316 DLIST_REMOVE(conn->outstanding, e);
1325 static void add_search_entry(struct ldap_connection *conn,
1326 struct ldap_message *msg)
1328 struct ldap_queue_entry *e = malloc(sizeof *e);
1334 DLIST_ADD_END(conn->search_entries, e, struct ldap_queue_entry *);
1338 static void fill_outstanding_request(struct ldap_connection *conn,
1339 struct ldap_message *msg)
1341 struct ldap_queue_entry *e;
1343 for (e = conn->outstanding; e != NULL; e = e->next) {
1344 if (e->msgid == msg->messageid) {
1350 /* This reply has not been expected, destroy the incoming msg */
1351 destroy_ldap_message(msg);
1355 struct ldap_message *ldap_receive(struct ldap_connection *conn, int msgid,
1356 const struct timeval *endtime)
1358 struct ldap_message *result = recv_from_queue(conn, msgid);
1364 struct asn1_data data;
1367 result = new_ldap_message();
1369 if (!asn1_read_sequence_until(conn->sock, &data, endtime))
1372 res = ldap_decode(&data, result);
1378 if (result->messageid == msgid)
1381 if (result->type == LDAP_TAG_SearchResultEntry) {
1382 add_search_entry(conn, result);
1384 fill_outstanding_request(conn, result);
1391 struct ldap_message *ldap_transaction(struct ldap_connection *conn,
1392 struct ldap_message *request)
1394 if (!ldap_send_msg(conn, request, NULL))
1397 return ldap_receive(conn, request->messageid, NULL);
1400 int ldap_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password)
1402 struct ldap_message *response;
1403 struct ldap_message *msg;
1404 const char *dn, *pw;
1405 int result = LDAP_OTHER;
1413 if (conn->auth_dn) {
1423 if (conn->simple_pw) {
1424 pw = conn->simple_pw;
1430 msg = new_ldap_simple_bind_msg(dn, pw);
1434 response = ldap_transaction(conn, msg);
1436 destroy_ldap_message(msg);
1440 result = response->r.BindResponse.response.resultcode;
1442 destroy_ldap_message(msg);
1443 destroy_ldap_message(response);
1448 int ldap_bind_sasl(struct ldap_connection *conn, const char *username, const char *domain, const char *password)
1451 TALLOC_CTX *mem_ctx = NULL;
1452 struct ldap_message *response;
1453 struct ldap_message *msg;
1454 DATA_BLOB input = data_blob(NULL, 0);
1455 DATA_BLOB output = data_blob(NULL, 0);
1456 int result = LDAP_OTHER;
1461 status = gensec_client_start(conn, &conn->gensec);
1462 if (!NT_STATUS_IS_OK(status)) {
1463 DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
1467 status = gensec_set_domain(conn->gensec, domain);
1468 if (!NT_STATUS_IS_OK(status)) {
1469 DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n",
1470 domain, nt_errstr(status)));
1474 status = gensec_set_username(conn->gensec, username);
1475 if (!NT_STATUS_IS_OK(status)) {
1476 DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n",
1477 username, nt_errstr(status)));
1481 status = gensec_set_password(conn->gensec, password);
1482 if (!NT_STATUS_IS_OK(status)) {
1483 DEBUG(1, ("Failed to start set GENSEC client password: %s\n",
1484 nt_errstr(status)));
1488 status = gensec_set_target_hostname(conn->gensec, conn->host);
1489 if (!NT_STATUS_IS_OK(status)) {
1490 DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n",
1491 nt_errstr(status)));
1495 status = gensec_start_mech_by_sasl_name(conn->gensec, "GSS-SPNEGO");
1496 if (!NT_STATUS_IS_OK(status)) {
1497 DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",
1498 nt_errstr(status)));
1502 mem_ctx = talloc_init("ldap_bind_sasl");
1506 status = gensec_update(conn->gensec, mem_ctx,
1511 if (NT_STATUS_IS_OK(status) && output.length == 0) {
1514 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
1518 msg = new_ldap_sasl_bind_msg("GSS-SPNEGO", &output);
1522 response = ldap_transaction(conn, msg);
1523 destroy_ldap_message(msg);
1529 result = response->r.BindResponse.response.resultcode;
1531 if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
1535 status = gensec_update(conn->gensec, mem_ctx,
1536 response->r.BindResponse.SASL.secblob,
1539 destroy_ldap_message(response);
1544 gensec_end(&conn->gensec);
1546 talloc_destroy(mem_ctx);
1551 BOOL ldap_setup_connection(struct ldap_connection *conn,
1552 const char *url, const char *userdn, const char *password)
1556 if (!ldap_connect(conn, url)) {
1560 result = ldap_bind_simple(conn, userdn, password);
1561 if (result == LDAP_SUCCESS) {
1568 BOOL ldap_setup_connection_with_sasl(struct ldap_connection *conn, const char *url, const char *username, const char *domain, const char *password)
1572 if (!ldap_connect(conn, url)) {
1576 result = ldap_bind_sasl(conn, username, domain, password);
1577 if (result == LDAP_SUCCESS) {
1584 static BOOL ldap_abandon_message(struct ldap_connection *conn, int msgid,
1585 const struct timeval *endtime)
1587 struct ldap_message *msg = new_ldap_message();
1593 msg->type = LDAP_TAG_AbandonRequest;
1594 msg->r.AbandonRequest.messageid = msgid;
1596 result = ldap_send_msg(conn, msg, endtime);
1597 destroy_ldap_message(msg);
1601 struct ldap_message *new_ldap_search_message(const char *base,
1602 enum ldap_scope scope,
1605 const char **attributes)
1607 struct ldap_message *res = new_ldap_message();
1612 res->type = LDAP_TAG_SearchRequest;
1613 res->r.SearchRequest.basedn = base;
1614 res->r.SearchRequest.scope = scope;
1615 res->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
1616 res->r.SearchRequest.timelimit = 0;
1617 res->r.SearchRequest.sizelimit = 0;
1618 res->r.SearchRequest.attributesonly = False;
1619 res->r.SearchRequest.filter = filter;
1620 res->r.SearchRequest.num_attributes = num_attributes;
1621 res->r.SearchRequest.attributes = attributes;
1625 struct ldap_message *new_ldap_simple_bind_msg(const char *dn, const char *pw)
1627 struct ldap_message *res = new_ldap_message();
1632 res->type = LDAP_TAG_BindRequest;
1633 res->r.BindRequest.version = 3;
1634 res->r.BindRequest.dn = talloc_strdup(res->mem_ctx, dn);
1635 res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SIMPLE;
1636 res->r.BindRequest.creds.password = talloc_strdup(res->mem_ctx, pw);
1640 struct ldap_message *new_ldap_sasl_bind_msg(const char *sasl_mechanism, DATA_BLOB *secblob)
1642 struct ldap_message *res = new_ldap_message();
1647 res->type = LDAP_TAG_BindRequest;
1648 res->r.BindRequest.version = 3;
1649 res->r.BindRequest.dn = "";
1650 res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SASL;
1651 res->r.BindRequest.creds.SASL.mechanism = talloc_strdup(res->mem_ctx, sasl_mechanism);
1652 res->r.BindRequest.creds.SASL.secblob = *secblob;
1656 BOOL ldap_setsearchent(struct ldap_connection *conn, struct ldap_message *msg,
1657 const struct timeval *endtime)
1659 if ((conn->searchid != 0) &&
1660 (!ldap_abandon_message(conn, conn->searchid, endtime)))
1663 conn->searchid = conn->next_msgid;
1664 return ldap_send_msg(conn, msg, endtime);
1667 struct ldap_message *ldap_getsearchent(struct ldap_connection *conn,
1668 const struct timeval *endtime)
1670 struct ldap_message *result;
1672 if (conn->search_entries != NULL) {
1673 struct ldap_queue_entry *e = conn->search_entries;
1676 DLIST_REMOVE(conn->search_entries, e);
1681 result = ldap_receive(conn, conn->searchid, endtime);
1683 if (result->type == LDAP_TAG_SearchResultEntry)
1686 if (result->type == LDAP_TAG_SearchResultDone) {
1687 /* TODO: Handle Paged Results */
1688 destroy_ldap_message(result);
1692 /* TODO: Handle Search References here */
1696 void ldap_endsearchent(struct ldap_connection *conn,
1697 const struct timeval *endtime)
1699 struct ldap_queue_entry *e;
1701 e = conn->search_entries;
1704 struct ldap_queue_entry *next = e->next;
1705 DLIST_REMOVE(conn->search_entries, e);
1711 struct ldap_message *ldap_searchone(struct ldap_connection *conn,
1712 struct ldap_message *msg,
1713 const struct timeval *endtime)
1715 struct ldap_message *res1, *res2 = NULL;
1716 if (!ldap_setsearchent(conn, msg, endtime))
1719 res1 = ldap_getsearchent(conn, endtime);
1722 res2 = ldap_getsearchent(conn, endtime);
1724 ldap_endsearchent(conn, endtime);
1730 /* More than one entry */
1731 destroy_ldap_message(res1);
1732 destroy_ldap_message(res2);
1739 BOOL ldap_find_single_value(struct ldap_message *msg, const char *attr,
1743 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
1745 if (msg->type != LDAP_TAG_SearchResultEntry)
1748 for (i=0; i<r->num_attributes; i++) {
1749 if (strequal(attr, r->attributes[i].name)) {
1750 if (r->attributes[i].num_values != 1)
1753 *value = r->attributes[i].values[0];
1760 BOOL ldap_find_single_string(struct ldap_message *msg, const char *attr,
1761 TALLOC_CTX *mem_ctx, char **value)
1765 if (!ldap_find_single_value(msg, attr, &blob))
1768 *value = talloc(mem_ctx, blob.length+1);
1773 memcpy(*value, blob.data, blob.length);
1774 (*value)[blob.length] = '\0';
1778 BOOL ldap_find_single_int(struct ldap_message *msg, const char *attr,
1786 if (!ldap_find_single_value(msg, attr, &blob))
1789 val = malloc(blob.length+1);
1793 memcpy(val, blob.data, blob.length);
1794 val[blob.length] = '\0';
1799 *value = strtol(val, NULL, 10);
1809 int ldap_error(struct ldap_connection *conn)
1814 NTSTATUS ldap2nterror(int ldaperror)
1816 return NT_STATUS_OK;