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.
27 #include "system/network.h"
28 #include "system/iconv.h"
29 #include "auth/auth.h"
31 #include "dlinklist.h"
33 /****************************************************************************
35 * LDAP filter parser -- main routine is ldap_parse_filter
37 * Shamelessly stolen and adapted from ldb.
39 ***************************************************************************/
42 return next token element. Caller frees
44 static char *ldap_parse_lex(TALLOC_CTX *mem_ctx, const char **s,
59 if (strchr(sep, *p)) {
61 ret = talloc_strndup(mem_ctx, p, 1);
68 while (*p && (isalnum(*p) || !strchr(sep, *p))) {
76 ret = talloc_strndup(mem_ctx, *s, p - *s);
88 find a matching close brace in a string
90 static const char *match_brace(const char *s)
92 unsigned int count = 0;
93 while (*s && (count != 0 || *s != ')')) {
108 static struct ldap_parse_tree *ldap_parse_filter(TALLOC_CTX *mem_ctx,
112 <simple> ::= <attributetype> <filtertype> <attributevalue>
114 static struct ldap_parse_tree *ldap_parse_simple(TALLOC_CTX *mem_ctx,
118 struct ldap_parse_tree *ret;
120 l = ldap_parse_lex(mem_ctx, &s, LDAP_ALL_SEP);
125 if (strchr("()&|=", *l))
128 eq = ldap_parse_lex(mem_ctx, &s, LDAP_ALL_SEP);
129 if (!eq || strcmp(eq, "=") != 0)
132 val = ldap_parse_lex(mem_ctx, &s, ")");
133 if (val && strchr("()&|", *val))
136 ret = talloc(mem_ctx, sizeof(*ret));
142 ret->operation = LDAP_OP_SIMPLE;
143 ret->u.simple.attr = l;
144 ret->u.simple.value.data = val;
145 ret->u.simple.value.length = val?strlen(val):0;
153 <and> ::= '&' <filterlist>
154 <or> ::= '|' <filterlist>
155 <filterlist> ::= <filter> | <filter> <filterlist>
157 static struct ldap_parse_tree *ldap_parse_filterlist(TALLOC_CTX *mem_ctx,
158 enum ldap_parse_op op,
161 struct ldap_parse_tree *ret, *next;
163 ret = talloc(mem_ctx, sizeof(*ret));
171 ret->u.list.num_elements = 1;
172 ret->u.list.elements = talloc(mem_ctx, sizeof(*ret->u.list.elements));
173 if (!ret->u.list.elements) {
178 ret->u.list.elements[0] = ldap_parse_filter(mem_ctx, &s);
179 if (!ret->u.list.elements[0]) {
183 while (isspace(*s)) s++;
185 while (*s && (next = ldap_parse_filter(mem_ctx, &s))) {
186 struct ldap_parse_tree **e;
187 e = talloc_realloc_p(ret,
188 ret->u.list.elements,
189 struct ldap_parse_tree *,
190 ret->u.list.num_elements+1);
195 ret->u.list.elements = e;
196 ret->u.list.elements[ret->u.list.num_elements] = next;
197 ret->u.list.num_elements++;
198 while (isspace(*s)) s++;
206 <not> ::= '!' <filter>
208 static struct ldap_parse_tree *ldap_parse_not(TALLOC_CTX *mem_ctx, const char *s)
210 struct ldap_parse_tree *ret;
212 ret = talloc(mem_ctx, sizeof(*ret));
218 ret->operation = LDAP_OP_NOT;
219 ret->u.not.child = ldap_parse_filter(mem_ctx, &s);
220 if (!ret->u.not.child)
228 <filtercomp> ::= <and> | <or> | <not> | <simple>
230 static struct ldap_parse_tree *ldap_parse_filtercomp(TALLOC_CTX *mem_ctx,
233 while (isspace(*s)) s++;
237 return ldap_parse_filterlist(mem_ctx, LDAP_OP_AND, s+1);
240 return ldap_parse_filterlist(mem_ctx, LDAP_OP_OR, s+1);
243 return ldap_parse_not(mem_ctx, s+1);
250 return ldap_parse_simple(mem_ctx, s);
255 <filter> ::= '(' <filtercomp> ')'
257 static struct ldap_parse_tree *ldap_parse_filter(TALLOC_CTX *mem_ctx,
262 struct ldap_parse_tree *ret;
264 l = ldap_parse_lex(mem_ctx, s, LDAP_ALL_SEP);
269 if (strcmp(l, "(") != 0) {
279 s2 = talloc_strndup(mem_ctx, *s, p - *s);
285 ret = ldap_parse_filtercomp(mem_ctx, s2);
293 main parser entry point. Takes a search string and returns a parse tree
295 expression ::= <simple> | <filter>
297 static struct ldap_parse_tree *ldap_parse_tree(TALLOC_CTX *mem_ctx, const char *s)
299 while (isspace(*s)) s++;
302 return ldap_parse_filter(mem_ctx, &s);
305 return ldap_parse_simple(mem_ctx, s);
308 static BOOL ldap_push_filter(struct asn1_data *data, struct ldap_parse_tree *tree)
310 switch (tree->operation) {
311 case LDAP_OP_SIMPLE: {
312 if ((tree->u.simple.value.length == 1) &&
313 (((char *)(tree->u.simple.value.data))[0] == '*')) {
314 /* Just a presence test */
315 asn1_push_tag(data, 0x87);
316 asn1_write(data, tree->u.simple.attr,
317 strlen(tree->u.simple.attr));
319 return !data->has_error;
322 /* Equality is all we currently do... */
323 asn1_push_tag(data, 0xa3);
324 asn1_write_OctetString(data, tree->u.simple.attr,
325 strlen(tree->u.simple.attr));
326 asn1_write_OctetString(data, tree->u.simple.value.data,
327 tree->u.simple.value.length);
335 asn1_push_tag(data, 0xa0);
336 for (i=0; i<tree->u.list.num_elements; i++) {
337 ldap_push_filter(data, tree->u.list.elements[i]);
346 asn1_push_tag(data, 0xa1);
347 for (i=0; i<tree->u.list.num_elements; i++) {
348 ldap_push_filter(data, tree->u.list.elements[i]);
356 return !data->has_error;
359 static void ldap_encode_response(struct asn1_data *data, struct ldap_Result *result)
361 asn1_write_enumerated(data, result->resultcode);
362 asn1_write_OctetString(data, result->dn,
363 (result->dn) ? strlen(result->dn) : 0);
364 asn1_write_OctetString(data, result->errormessage,
365 (result->errormessage) ?
366 strlen(result->errormessage) : 0);
367 if (result->referral != NULL)
368 asn1_write_OctetString(data, result->referral,
369 strlen(result->referral));
372 BOOL ldap_encode(struct ldap_message *msg, DATA_BLOB *result)
374 struct asn1_data data;
378 asn1_push_tag(&data, ASN1_SEQUENCE(0));
379 asn1_write_Integer(&data, msg->messageid);
382 case LDAP_TAG_BindRequest: {
383 struct ldap_BindRequest *r = &msg->r.BindRequest;
384 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
385 asn1_write_Integer(&data, r->version);
386 asn1_write_OctetString(&data, r->dn,
387 (r->dn != NULL) ? strlen(r->dn) : 0);
389 switch (r->mechanism) {
390 case LDAP_AUTH_MECH_SIMPLE:
391 /* context, primitive */
392 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
393 asn1_write(&data, r->creds.password,
394 strlen(r->creds.password));
397 case LDAP_AUTH_MECH_SASL:
398 /* context, constructed */
399 asn1_push_tag(&data, ASN1_CONTEXT(3));
400 asn1_write_OctetString(&data, r->creds.SASL.mechanism,
401 strlen(r->creds.SASL.mechanism));
402 asn1_write_OctetString(&data, r->creds.SASL.secblob.data,
403 r->creds.SASL.secblob.length);
414 case LDAP_TAG_BindResponse: {
415 struct ldap_BindResponse *r = &msg->r.BindResponse;
416 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
417 ldap_encode_response(&data, &r->response);
418 if (r->SASL.secblob.length > 0) {
419 asn1_write_ContextSimple(&data, 7, &r->SASL.secblob);
424 case LDAP_TAG_UnbindRequest: {
425 /* struct ldap_UnbindRequest *r = &msg->r.UnbindRequest; */
428 case LDAP_TAG_SearchRequest: {
429 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
430 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
431 asn1_write_OctetString(&data, r->basedn, strlen(r->basedn));
432 asn1_write_enumerated(&data, r->scope);
433 asn1_write_enumerated(&data, r->deref);
434 asn1_write_Integer(&data, r->sizelimit);
435 asn1_write_Integer(&data, r->timelimit);
436 asn1_write_BOOLEAN(&data, r->attributesonly);
439 TALLOC_CTX *mem_ctx = talloc_init("ldap_parse_tree");
440 struct ldap_parse_tree *tree;
445 tree = ldap_parse_tree(mem_ctx, r->filter);
450 ldap_push_filter(&data, tree);
452 talloc_destroy(mem_ctx);
455 asn1_push_tag(&data, ASN1_SEQUENCE(0));
456 for (i=0; i<r->num_attributes; i++) {
457 asn1_write_OctetString(&data, r->attributes[i],
458 strlen(r->attributes[i]));
465 case LDAP_TAG_SearchResultEntry: {
466 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
467 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
468 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
469 asn1_push_tag(&data, ASN1_SEQUENCE(0));
470 for (i=0; i<r->num_attributes; i++) {
471 struct ldap_attribute *attr = &r->attributes[i];
472 asn1_push_tag(&data, ASN1_SEQUENCE(0));
473 asn1_write_OctetString(&data, attr->name,
475 asn1_push_tag(&data, ASN1_SEQUENCE(1));
476 for (j=0; j<attr->num_values; j++) {
477 asn1_write_OctetString(&data,
478 attr->values[j].data,
479 attr->values[j].length);
488 case LDAP_TAG_SearchResultDone: {
489 struct ldap_Result *r = &msg->r.SearchResultDone;
490 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
491 ldap_encode_response(&data, r);
495 case LDAP_TAG_ModifyRequest: {
496 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
497 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
498 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
499 asn1_push_tag(&data, ASN1_SEQUENCE(0));
501 for (i=0; i<r->num_mods; i++) {
502 struct ldap_attribute *attrib = &r->mods[i].attrib;
503 asn1_push_tag(&data, ASN1_SEQUENCE(0));
504 asn1_write_enumerated(&data, r->mods[i].type);
505 asn1_push_tag(&data, ASN1_SEQUENCE(0));
506 asn1_write_OctetString(&data, attrib->name,
507 strlen(attrib->name));
508 asn1_push_tag(&data, ASN1_SET);
509 for (j=0; j<attrib->num_values; j++) {
510 asn1_write_OctetString(&data,
511 attrib->values[j].data,
512 attrib->values[j].length);
524 case LDAP_TAG_ModifyResponse: {
525 struct ldap_Result *r = &msg->r.ModifyResponse;
526 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
527 ldap_encode_response(&data, r);
531 case LDAP_TAG_AddRequest: {
532 struct ldap_AddRequest *r = &msg->r.AddRequest;
533 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
534 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
535 asn1_push_tag(&data, ASN1_SEQUENCE(0));
537 for (i=0; i<r->num_attributes; i++) {
538 struct ldap_attribute *attrib = &r->attributes[i];
539 asn1_push_tag(&data, ASN1_SEQUENCE(0));
540 asn1_write_OctetString(&data, attrib->name,
541 strlen(attrib->name));
542 asn1_push_tag(&data, ASN1_SET);
543 for (j=0; j<r->attributes[i].num_values; j++) {
544 asn1_write_OctetString(&data,
545 attrib->values[j].data,
546 attrib->values[j].length);
555 case LDAP_TAG_AddResponse: {
556 struct ldap_Result *r = &msg->r.AddResponse;
557 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
558 ldap_encode_response(&data, r);
562 case LDAP_TAG_DelRequest: {
563 struct ldap_DelRequest *r = &msg->r.DelRequest;
564 asn1_push_tag(&data, ASN1_APPLICATION_SIMPLE(msg->type));
565 asn1_write(&data, r->dn, strlen(r->dn));
569 case LDAP_TAG_DelResponse: {
570 struct ldap_Result *r = &msg->r.DelResponse;
571 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
572 ldap_encode_response(&data, r);
576 case LDAP_TAG_ModifyDNRequest: {
577 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
578 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
579 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
580 asn1_write_OctetString(&data, r->newrdn, strlen(r->newrdn));
581 asn1_write_BOOLEAN(&data, r->deleteolddn);
582 if (r->newsuperior != NULL) {
583 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
584 asn1_write(&data, r->newsuperior,
585 strlen(r->newsuperior));
591 case LDAP_TAG_ModifyDNResponse: {
592 struct ldap_Result *r = &msg->r.ModifyDNResponse;
593 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
594 ldap_encode_response(&data, r);
598 case LDAP_TAG_CompareRequest: {
599 struct ldap_CompareRequest *r = &msg->r.CompareRequest;
600 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
601 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
602 asn1_push_tag(&data, ASN1_SEQUENCE(0));
603 asn1_write_OctetString(&data, r->attribute,
604 strlen(r->attribute));
605 asn1_write_OctetString(&data, r->value.data,
611 case LDAP_TAG_CompareResponse: {
612 struct ldap_Result *r = &msg->r.ModifyDNResponse;
613 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
614 ldap_encode_response(&data, r);
618 case LDAP_TAG_AbandonRequest: {
619 struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
620 asn1_push_tag(&data, ASN1_APPLICATION_SIMPLE(msg->type));
621 asn1_write_implicit_Integer(&data, r->messageid);
625 case LDAP_TAG_SearchResultReference: {
626 /* struct ldap_SearchResRef *r = &msg->r.SearchResultReference; */
629 case LDAP_TAG_ExtendedRequest: {
630 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
631 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
632 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
633 asn1_write(&data, r->oid, strlen(r->oid));
635 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(1));
636 asn1_write(&data, r->value.data, r->value.length);
641 case LDAP_TAG_ExtendedResponse: {
642 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
643 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
644 ldap_encode_response(&data, &r->response);
653 *result = data_blob(data.data, data.length);
658 static const char *blob2string_talloc(TALLOC_CTX *mem_ctx,
661 char *result = talloc(mem_ctx, blob.length+1);
662 memcpy(result, blob.data, blob.length);
663 result[blob.length] = '\0';
667 static BOOL asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
668 struct asn1_data *data,
672 if (!asn1_read_OctetString(data, &string))
674 *result = blob2string_talloc(mem_ctx, string);
675 data_blob_free(&string);
679 static void ldap_decode_response(TALLOC_CTX *mem_ctx,
680 struct asn1_data *data,
681 struct ldap_Result *result)
683 asn1_read_enumerated(data, &result->resultcode);
684 asn1_read_OctetString_talloc(mem_ctx, data, &result->dn);
685 asn1_read_OctetString_talloc(mem_ctx, data, &result->errormessage);
686 if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
687 asn1_start_tag(data, ASN1_CONTEXT(3));
688 asn1_read_OctetString_talloc(mem_ctx, data, &result->referral);
691 result->referral = NULL;
695 static BOOL ldap_decode_filter(TALLOC_CTX *mem_ctx, struct asn1_data *data,
698 uint8 filter_tag, tag_desc;
700 if (!asn1_peek_uint8(data, &filter_tag))
703 tag_desc = filter_tag;
704 filter_tag &= 0x1f; /* strip off the asn1 stuff */
709 /* AND of one or more filters */
710 if (tag_desc != 0xa0) /* context compount */
713 asn1_start_tag(data, ASN1_CONTEXT(0));
715 *filter = talloc_strdup(mem_ctx, "(&");
719 while (asn1_tag_remaining(data) > 0) {
721 if (!ldap_decode_filter(mem_ctx, data, &subfilter))
723 *filter = talloc_asprintf(mem_ctx, "%s%s", *filter,
730 *filter = talloc_asprintf(mem_ctx, "%s)", *filter);
734 /* OR of one or more filters */
735 if (tag_desc != 0xa0) /* context compount */
738 asn1_start_tag(data, ASN1_CONTEXT(1));
740 *filter = talloc_strdup(mem_ctx, "(|");
744 while (asn1_tag_remaining(data) > 0) {
746 if (!ldap_decode_filter(mem_ctx, data, &subfilter))
748 *filter = talloc_asprintf(mem_ctx, "%s%s", *filter,
756 *filter = talloc_asprintf(mem_ctx, "%s)", *filter);
761 const char *attrib, *value;
762 if (tag_desc != 0xa0) /* context compound */
764 asn1_start_tag(data, ASN1_CONTEXT(3));
765 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
766 asn1_read_OctetString_talloc(mem_ctx, data, &value);
768 if ((data->has_error) || (attrib == NULL) || (value == NULL))
770 *filter = talloc_asprintf(mem_ctx, "(%s=%s)", attrib, value);
774 /* Normal presence, "attribute=*" */
777 if (tag_desc != 0x80) /* context simple */
779 if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(7)))
781 attr_len = asn1_tag_remaining(data);
782 attr_name = malloc(attr_len+1);
783 if (attr_name == NULL)
785 asn1_read(data, attr_name, attr_len);
786 attr_name[attr_len] = '\0';
787 *filter = talloc_asprintf(mem_ctx, "(%s=*)", attr_name);
788 SAFE_FREE(attr_name);
800 static void ldap_decode_attrib(TALLOC_CTX *mem_ctx, struct asn1_data *data,
801 struct ldap_attribute *attrib)
803 asn1_start_tag(data, ASN1_SEQUENCE(0));
804 asn1_read_OctetString_talloc(mem_ctx, data, &attrib->name);
805 asn1_start_tag(data, ASN1_SET);
806 while (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
808 struct ldap_val value;
809 asn1_read_OctetString(data, &blob);
810 value.data = blob.data;
811 value.length = blob.length;
812 add_value_to_attrib(mem_ctx, &value, attrib);
813 data_blob_free(&blob);
820 static void ldap_decode_attribs(TALLOC_CTX *mem_ctx, struct asn1_data *data,
821 struct ldap_attribute **attributes,
824 asn1_start_tag(data, ASN1_SEQUENCE(0));
825 while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
826 struct ldap_attribute attrib;
828 ldap_decode_attrib(mem_ctx, data, &attrib);
829 add_attrib_to_array_talloc(mem_ctx, &attrib,
830 attributes, num_attributes);
835 BOOL ldap_decode(struct asn1_data *data, struct ldap_message *msg)
839 asn1_start_tag(data, ASN1_SEQUENCE(0));
840 asn1_read_Integer(data, &msg->messageid);
842 if (!asn1_peek_uint8(data, &tag))
847 case ASN1_APPLICATION(LDAP_TAG_BindRequest): {
848 struct ldap_BindRequest *r = &msg->r.BindRequest;
849 msg->type = LDAP_TAG_BindRequest;
850 asn1_start_tag(data, tag);
851 asn1_read_Integer(data, &r->version);
852 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
853 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(0))) {
855 r->creds.password = "";
856 r->mechanism = LDAP_AUTH_MECH_SIMPLE;
857 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0));
858 pwlen = asn1_tag_remaining(data);
860 char *pw = talloc(msg->mem_ctx, pwlen+1);
861 asn1_read(data, pw, pwlen);
863 r->creds.password = pw;
866 } else if (asn1_peek_tag(data, ASN1_CONTEXT(3))){
867 asn1_start_tag(data, ASN1_CONTEXT(3));
868 r->mechanism = LDAP_AUTH_MECH_SASL;
869 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->creds.SASL.mechanism);
870 asn1_read_OctetString(data, &r->creds.SASL.secblob);
871 if (r->creds.SASL.secblob.data) {
872 talloc_steal(msg->mem_ctx, r->creds.SASL.secblob.data);
880 case ASN1_APPLICATION(LDAP_TAG_BindResponse): {
881 struct ldap_BindResponse *r = &msg->r.BindResponse;
882 msg->type = LDAP_TAG_BindResponse;
883 asn1_start_tag(data, tag);
884 ldap_decode_response(msg->mem_ctx, data, &r->response);
885 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(7))) {
886 DATA_BLOB tmp_blob = data_blob(NULL, 0);
887 asn1_read_ContextSimple(data, 7, &tmp_blob);
888 r->SASL.secblob = data_blob_talloc(msg->mem_ctx, tmp_blob.data, tmp_blob.length);
889 data_blob_free(&tmp_blob);
891 r->SASL.secblob = data_blob(NULL, 0);
897 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_UnbindRequest): {
898 msg->type = LDAP_TAG_UnbindRequest;
899 asn1_start_tag(data, tag);
904 case ASN1_APPLICATION(LDAP_TAG_SearchRequest): {
905 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
906 msg->type = LDAP_TAG_SearchRequest;
907 asn1_start_tag(data, tag);
908 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->basedn);
909 asn1_read_enumerated(data, (int *)&(r->scope));
910 asn1_read_enumerated(data, (int *)&(r->deref));
911 asn1_read_Integer(data, &r->sizelimit);
912 asn1_read_Integer(data, &r->timelimit);
913 asn1_read_BOOLEAN(data, &r->attributesonly);
915 /* Maybe create a TALLOC_CTX for the filter? This can waste
916 * quite a bit of memory recursing down. */
917 ldap_decode_filter(msg->mem_ctx, data, &r->filter);
919 asn1_start_tag(data, ASN1_SEQUENCE(0));
921 r->num_attributes = 0;
922 r->attributes = NULL;
924 while (asn1_tag_remaining(data) > 0) {
926 if (!asn1_read_OctetString_talloc(msg->mem_ctx, data,
929 if (!add_string_to_array(msg->mem_ctx, attr,
940 case ASN1_APPLICATION(LDAP_TAG_SearchResultEntry): {
941 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
942 msg->type = LDAP_TAG_SearchResultEntry;
943 r->attributes = NULL;
944 r->num_attributes = 0;
945 asn1_start_tag(data, tag);
946 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
947 ldap_decode_attribs(msg->mem_ctx, data, &r->attributes,
953 case ASN1_APPLICATION(LDAP_TAG_SearchResultDone): {
954 struct ldap_Result *r = &msg->r.SearchResultDone;
955 msg->type = LDAP_TAG_SearchResultDone;
956 asn1_start_tag(data, tag);
957 ldap_decode_response(msg->mem_ctx, data, r);
962 case ASN1_APPLICATION(LDAP_TAG_SearchResultReference): {
963 /* struct ldap_SearchResRef *r = &msg->r.SearchResultReference; */
964 msg->type = LDAP_TAG_SearchResultReference;
968 case ASN1_APPLICATION(LDAP_TAG_ModifyRequest): {
969 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
970 msg->type = LDAP_TAG_ModifyRequest;
971 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_ModifyRequest));
972 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
973 asn1_start_tag(data, ASN1_SEQUENCE(0));
978 while (asn1_tag_remaining(data) > 0) {
981 asn1_start_tag(data, ASN1_SEQUENCE(0));
982 asn1_read_enumerated(data, &mod.type);
983 ldap_decode_attrib(msg->mem_ctx, data, &mod.attrib);
985 if (!add_mod_to_array_talloc(msg->mem_ctx, &mod,
986 &r->mods, &r->num_mods))
995 case ASN1_APPLICATION(LDAP_TAG_ModifyResponse): {
996 struct ldap_Result *r = &msg->r.ModifyResponse;
997 msg->type = LDAP_TAG_ModifyResponse;
998 asn1_start_tag(data, tag);
999 ldap_decode_response(msg->mem_ctx, data, r);
1004 case ASN1_APPLICATION(LDAP_TAG_AddRequest): {
1005 struct ldap_AddRequest *r = &msg->r.AddRequest;
1006 msg->type = LDAP_TAG_AddRequest;
1007 asn1_start_tag(data, tag);
1008 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
1010 r->attributes = NULL;
1011 r->num_attributes = 0;
1012 ldap_decode_attribs(msg->mem_ctx, data, &r->attributes,
1013 &r->num_attributes);
1019 case ASN1_APPLICATION(LDAP_TAG_AddResponse): {
1020 struct ldap_Result *r = &msg->r.AddResponse;
1021 msg->type = LDAP_TAG_AddResponse;
1022 asn1_start_tag(data, tag);
1023 ldap_decode_response(msg->mem_ctx, data, r);
1028 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest): {
1029 struct ldap_DelRequest *r = &msg->r.DelRequest;
1032 msg->type = LDAP_TAG_DelRequest;
1033 asn1_start_tag(data,
1034 ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest));
1035 len = asn1_tag_remaining(data);
1036 dn = talloc(msg->mem_ctx, len+1);
1039 asn1_read(data, dn, len);
1046 case ASN1_APPLICATION(LDAP_TAG_DelResponse): {
1047 struct ldap_Result *r = &msg->r.DelResponse;
1048 msg->type = LDAP_TAG_DelResponse;
1049 asn1_start_tag(data, tag);
1050 ldap_decode_response(msg->mem_ctx, data, r);
1055 case ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest): {
1056 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
1057 msg->type = LDAP_TAG_ModifyDNRequest;
1058 asn1_start_tag(data,
1059 ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest));
1060 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
1061 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->newrdn);
1062 asn1_read_BOOLEAN(data, &r->deleteolddn);
1063 r->newsuperior = NULL;
1064 if (asn1_tag_remaining(data) > 0) {
1067 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0));
1068 len = asn1_tag_remaining(data);
1069 newsup = talloc(msg->mem_ctx, len+1);
1072 asn1_read(data, newsup, len);
1074 r->newsuperior = newsup;
1081 case ASN1_APPLICATION(LDAP_TAG_ModifyDNResponse): {
1082 struct ldap_Result *r = &msg->r.ModifyDNResponse;
1083 msg->type = LDAP_TAG_ModifyDNResponse;
1084 asn1_start_tag(data, tag);
1085 ldap_decode_response(msg->mem_ctx, data, r);
1090 case ASN1_APPLICATION(LDAP_TAG_CompareRequest): {
1091 struct ldap_CompareRequest *r = &msg->r.CompareRequest;
1092 msg->type = LDAP_TAG_CompareRequest;
1093 asn1_start_tag(data,
1094 ASN1_APPLICATION(LDAP_TAG_CompareRequest));
1095 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
1096 asn1_start_tag(data, ASN1_SEQUENCE(0));
1097 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->attribute);
1098 asn1_read_OctetString(data, &r->value);
1099 if (r->value.data) {
1100 talloc_steal(msg->mem_ctx, r->value.data);
1107 case ASN1_APPLICATION(LDAP_TAG_CompareResponse): {
1108 struct ldap_Result *r = &msg->r.CompareResponse;
1109 msg->type = LDAP_TAG_CompareResponse;
1110 asn1_start_tag(data, tag);
1111 ldap_decode_response(msg->mem_ctx, data, r);
1116 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_AbandonRequest): {
1117 struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
1118 msg->type = LDAP_TAG_AbandonRequest;
1119 asn1_start_tag(data, tag);
1120 asn1_read_implicit_Integer(data, &r->messageid);
1125 case ASN1_APPLICATION(LDAP_TAG_ExtendedRequest): {
1126 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
1127 DATA_BLOB tmp_blob = data_blob(NULL, 0);
1129 msg->type = LDAP_TAG_ExtendedRequest;
1130 asn1_start_tag(data,tag);
1131 if (!asn1_read_ContextSimple(data, 0, &tmp_blob)) {
1134 r->oid = blob2string_talloc(msg->mem_ctx, tmp_blob);
1135 data_blob_free(&tmp_blob);
1140 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(1))) {
1141 asn1_read_ContextSimple(data, 1, &tmp_blob);
1142 r->value = data_blob_talloc(msg->mem_ctx, tmp_blob.data, tmp_blob.length);
1143 data_blob_free(&tmp_blob);
1145 r->value = data_blob(NULL, 0);
1152 case ASN1_APPLICATION(LDAP_TAG_ExtendedResponse): {
1153 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
1154 msg->type = LDAP_TAG_ExtendedResponse;
1155 asn1_start_tag(data, tag);
1156 ldap_decode_response(msg->mem_ctx, data, &r->response);
1157 /* I have to come across an operation that actually sends
1158 * something back to really see what's going on. The currently
1159 * needed pwdchange does not send anything back. */
1161 r->value.data = NULL;
1162 r->value.length = 0;
1170 msg->num_controls = 0;
1171 msg->controls = NULL;
1173 if (asn1_peek_tag(data, ASN1_CONTEXT(0))) {
1175 struct ldap_Control *ctrl = NULL;
1177 asn1_start_tag(data, ASN1_CONTEXT(0));
1179 for (i=0; asn1_peek_tag(data, ASN1_SEQUENCE(0)); i++) {
1180 asn1_start_tag(data, ASN1_SEQUENCE(0));
1182 ctrl = talloc_realloc_p(msg->mem_ctx, ctrl, struct ldap_Control, i+1);
1187 ctrl[i].critical = False;
1188 ctrl[i].value = data_blob(NULL, 0);
1190 asn1_read_OctetString_talloc(ctrl, data, &ctrl[i].oid);
1192 if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
1193 asn1_read_BOOLEAN(data, &ctrl[i].critical);
1196 if (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
1197 asn1_read_OctetString(data, &ctrl[i].value);
1198 if (ctrl[i].value.data) {
1199 talloc_steal(msg->mem_ctx, ctrl[i].value.data);
1205 msg->num_controls = i;
1206 msg->controls = ctrl;
1212 return ((!data->has_error) && (data->nesting == NULL));
1215 BOOL ldap_parse_basic_url(TALLOC_CTX *mem_ctx, const char *url,
1216 char **host, uint16 *port, BOOL *ldaps)
1221 const char *p = url;
1223 /* skip leading "URL:" (if any) */
1224 if (strncasecmp( p, "URL:", 4) == 0) {
1228 /* Paranoia check */
1229 SMB_ASSERT(sizeof(protocol)>10 && sizeof(tmp_host)>254);
1231 sscanf(p, "%10[^:]://%254[^:/]:%d", protocol, tmp_host, &tmp_port);
1233 if (strequal(protocol, "ldap")) {
1236 } else if (strequal(protocol, "ldaps")) {
1240 DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
1247 *host = talloc_strdup(mem_ctx, tmp_host);
1249 return (*host != NULL);
1252 struct ldap_connection *new_ldap_connection(void)
1254 TALLOC_CTX *mem_ctx = talloc_init("ldap_connection");
1255 struct ldap_connection *result;
1257 if (mem_ctx == NULL)
1260 result = talloc(mem_ctx, sizeof(*result));
1265 result->mem_ctx = mem_ctx;
1266 result->next_msgid = 1;
1267 result->outstanding = NULL;
1268 result->searchid = 0;
1269 result->search_entries = NULL;
1270 result->auth_dn = NULL;
1271 result->simple_pw = NULL;
1272 result->gensec = NULL;
1277 BOOL ldap_connect(struct ldap_connection *conn, const char *url)
1280 struct ipv4_addr ip;
1282 if (!ldap_parse_basic_url(conn->mem_ctx, url, &conn->host,
1283 &conn->port, &conn->ldaps))
1286 hp = sys_gethostbyname(conn->host);
1288 if ((hp == NULL) || (hp->h_addr == NULL))
1291 putip((char *)&ip, (char *)hp->h_addr);
1293 conn->sock = open_socket_out(SOCK_STREAM, &ip, conn->port, LDAP_CONNECTION_TIMEOUT);
1295 return (conn->sock >= 0);
1298 BOOL ldap_set_simple_creds(struct ldap_connection *conn,
1299 const char *dn, const char *password)
1301 conn->auth_dn = talloc_strdup(conn->mem_ctx, dn);
1302 conn->simple_pw = talloc_strdup(conn->mem_ctx, password);
1304 return ((conn->auth_dn != NULL) && (conn->simple_pw != NULL));
1307 struct ldap_message *new_ldap_message(void)
1309 TALLOC_CTX *mem_ctx = talloc_init("ldap_message");
1310 struct ldap_message *result;
1312 if (mem_ctx == NULL)
1315 result = talloc(mem_ctx, sizeof(*result));
1320 result->mem_ctx = mem_ctx;
1324 void destroy_ldap_message(struct ldap_message *msg)
1327 talloc_destroy(msg->mem_ctx);
1330 BOOL ldap_send_msg(struct ldap_connection *conn, struct ldap_message *msg,
1331 const struct timeval *endtime)
1335 struct ldap_queue_entry *entry;
1337 msg->messageid = conn->next_msgid++;
1339 if (!ldap_encode(msg, &request))
1342 result = (write_data_until(conn->sock, request.data, request.length,
1343 endtime) == request.length);
1345 data_blob_free(&request);
1350 /* abandon and unbind don't expect results */
1352 if ((msg->type == LDAP_TAG_AbandonRequest) ||
1353 (msg->type == LDAP_TAG_UnbindRequest))
1356 entry = malloc(sizeof(*entry));
1361 entry->msgid = msg->messageid;
1363 DLIST_ADD(conn->outstanding, entry);
1368 BOOL ldap_receive_msg(struct ldap_connection *conn, struct ldap_message *msg,
1369 const struct timeval *endtime)
1371 struct asn1_data data;
1374 if (!asn1_read_sequence_until(conn->sock, &data, endtime))
1377 result = ldap_decode(&data, msg);
1383 static struct ldap_message *recv_from_queue(struct ldap_connection *conn,
1386 struct ldap_queue_entry *e;
1388 for (e = conn->outstanding; e != NULL; e = e->next) {
1390 if (e->msgid == msgid) {
1391 struct ldap_message *result = e->msg;
1392 DLIST_REMOVE(conn->outstanding, e);
1401 static void add_search_entry(struct ldap_connection *conn,
1402 struct ldap_message *msg)
1404 struct ldap_queue_entry *e = malloc(sizeof *e);
1410 DLIST_ADD_END(conn->search_entries, e, struct ldap_queue_entry *);
1414 static void fill_outstanding_request(struct ldap_connection *conn,
1415 struct ldap_message *msg)
1417 struct ldap_queue_entry *e;
1419 for (e = conn->outstanding; e != NULL; e = e->next) {
1420 if (e->msgid == msg->messageid) {
1426 /* This reply has not been expected, destroy the incoming msg */
1427 destroy_ldap_message(msg);
1431 struct ldap_message *ldap_receive(struct ldap_connection *conn, int msgid,
1432 const struct timeval *endtime)
1434 struct ldap_message *result = recv_from_queue(conn, msgid);
1440 struct asn1_data data;
1443 result = new_ldap_message();
1445 if (!asn1_read_sequence_until(conn->sock, &data, endtime))
1448 res = ldap_decode(&data, result);
1454 if (result->messageid == msgid)
1457 if (result->type == LDAP_TAG_SearchResultEntry) {
1458 add_search_entry(conn, result);
1460 fill_outstanding_request(conn, result);
1467 struct ldap_message *ldap_transaction(struct ldap_connection *conn,
1468 struct ldap_message *request)
1470 if (!ldap_send_msg(conn, request, NULL))
1473 return ldap_receive(conn, request->messageid, NULL);
1476 int ldap_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password)
1478 struct ldap_message *response;
1479 struct ldap_message *msg;
1480 const char *dn, *pw;
1481 int result = LDAP_OTHER;
1489 if (conn->auth_dn) {
1499 if (conn->simple_pw) {
1500 pw = conn->simple_pw;
1506 msg = new_ldap_simple_bind_msg(dn, pw);
1510 response = ldap_transaction(conn, msg);
1512 destroy_ldap_message(msg);
1516 result = response->r.BindResponse.response.resultcode;
1518 destroy_ldap_message(msg);
1519 destroy_ldap_message(response);
1524 int ldap_bind_sasl(struct ldap_connection *conn, const char *username, const char *domain, const char *password)
1527 TALLOC_CTX *mem_ctx = NULL;
1528 struct ldap_message *response;
1529 struct ldap_message *msg;
1530 DATA_BLOB input = data_blob(NULL, 0);
1531 DATA_BLOB output = data_blob(NULL, 0);
1532 int result = LDAP_OTHER;
1537 status = gensec_client_start(conn, &conn->gensec);
1538 if (!NT_STATUS_IS_OK(status)) {
1539 DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
1543 gensec_want_feature(conn->gensec, GENSEC_WANT_SIGN | GENSEC_WANT_SEAL);
1545 status = gensec_set_domain(conn->gensec, domain);
1546 if (!NT_STATUS_IS_OK(status)) {
1547 DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n",
1548 domain, nt_errstr(status)));
1552 status = gensec_set_username(conn->gensec, username);
1553 if (!NT_STATUS_IS_OK(status)) {
1554 DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n",
1555 username, nt_errstr(status)));
1559 status = gensec_set_password(conn->gensec, password);
1560 if (!NT_STATUS_IS_OK(status)) {
1561 DEBUG(1, ("Failed to start set GENSEC client password: %s\n",
1562 nt_errstr(status)));
1566 status = gensec_set_target_hostname(conn->gensec, conn->host);
1567 if (!NT_STATUS_IS_OK(status)) {
1568 DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n",
1569 nt_errstr(status)));
1573 status = gensec_start_mech_by_sasl_name(conn->gensec, "GSS-SPNEGO");
1574 if (!NT_STATUS_IS_OK(status)) {
1575 DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",
1576 nt_errstr(status)));
1580 mem_ctx = talloc_init("ldap_bind_sasl");
1584 status = gensec_update(conn->gensec, mem_ctx,
1589 if (NT_STATUS_IS_OK(status) && output.length == 0) {
1592 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
1596 msg = new_ldap_sasl_bind_msg("GSS-SPNEGO", &output);
1600 response = ldap_transaction(conn, msg);
1601 destroy_ldap_message(msg);
1607 result = response->r.BindResponse.response.resultcode;
1609 if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
1613 status = gensec_update(conn->gensec, mem_ctx,
1614 response->r.BindResponse.SASL.secblob,
1617 destroy_ldap_message(response);
1622 talloc_destroy(mem_ctx);
1627 BOOL ldap_setup_connection(struct ldap_connection *conn,
1628 const char *url, const char *userdn, const char *password)
1632 if (!ldap_connect(conn, url)) {
1636 result = ldap_bind_simple(conn, userdn, password);
1637 if (result == LDAP_SUCCESS) {
1644 BOOL ldap_setup_connection_with_sasl(struct ldap_connection *conn, const char *url, const char *username, const char *domain, const char *password)
1648 if (!ldap_connect(conn, url)) {
1652 result = ldap_bind_sasl(conn, username, domain, password);
1653 if (result == LDAP_SUCCESS) {
1660 static BOOL ldap_abandon_message(struct ldap_connection *conn, int msgid,
1661 const struct timeval *endtime)
1663 struct ldap_message *msg = new_ldap_message();
1669 msg->type = LDAP_TAG_AbandonRequest;
1670 msg->r.AbandonRequest.messageid = msgid;
1672 result = ldap_send_msg(conn, msg, endtime);
1673 destroy_ldap_message(msg);
1677 struct ldap_message *new_ldap_search_message(const char *base,
1678 enum ldap_scope scope,
1681 const char **attributes)
1683 struct ldap_message *res = new_ldap_message();
1688 res->type = LDAP_TAG_SearchRequest;
1689 res->r.SearchRequest.basedn = base;
1690 res->r.SearchRequest.scope = scope;
1691 res->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
1692 res->r.SearchRequest.timelimit = 0;
1693 res->r.SearchRequest.sizelimit = 0;
1694 res->r.SearchRequest.attributesonly = False;
1695 res->r.SearchRequest.filter = filter;
1696 res->r.SearchRequest.num_attributes = num_attributes;
1697 res->r.SearchRequest.attributes = attributes;
1701 struct ldap_message *new_ldap_simple_bind_msg(const char *dn, const char *pw)
1703 struct ldap_message *res = new_ldap_message();
1708 res->type = LDAP_TAG_BindRequest;
1709 res->r.BindRequest.version = 3;
1710 res->r.BindRequest.dn = talloc_strdup(res->mem_ctx, dn);
1711 res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SIMPLE;
1712 res->r.BindRequest.creds.password = talloc_strdup(res->mem_ctx, pw);
1716 struct ldap_message *new_ldap_sasl_bind_msg(const char *sasl_mechanism, DATA_BLOB *secblob)
1718 struct ldap_message *res = new_ldap_message();
1723 res->type = LDAP_TAG_BindRequest;
1724 res->r.BindRequest.version = 3;
1725 res->r.BindRequest.dn = "";
1726 res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SASL;
1727 res->r.BindRequest.creds.SASL.mechanism = talloc_strdup(res->mem_ctx, sasl_mechanism);
1728 res->r.BindRequest.creds.SASL.secblob = *secblob;
1732 BOOL ldap_setsearchent(struct ldap_connection *conn, struct ldap_message *msg,
1733 const struct timeval *endtime)
1735 if ((conn->searchid != 0) &&
1736 (!ldap_abandon_message(conn, conn->searchid, endtime)))
1739 conn->searchid = conn->next_msgid;
1740 return ldap_send_msg(conn, msg, endtime);
1743 struct ldap_message *ldap_getsearchent(struct ldap_connection *conn,
1744 const struct timeval *endtime)
1746 struct ldap_message *result;
1748 if (conn->search_entries != NULL) {
1749 struct ldap_queue_entry *e = conn->search_entries;
1752 DLIST_REMOVE(conn->search_entries, e);
1757 result = ldap_receive(conn, conn->searchid, endtime);
1762 if (result->type == LDAP_TAG_SearchResultEntry)
1765 if (result->type == LDAP_TAG_SearchResultDone) {
1766 /* TODO: Handle Paged Results */
1767 destroy_ldap_message(result);
1771 /* TODO: Handle Search References here */
1775 void ldap_endsearchent(struct ldap_connection *conn,
1776 const struct timeval *endtime)
1778 struct ldap_queue_entry *e;
1780 e = conn->search_entries;
1783 struct ldap_queue_entry *next = e->next;
1784 DLIST_REMOVE(conn->search_entries, e);
1790 struct ldap_message *ldap_searchone(struct ldap_connection *conn,
1791 struct ldap_message *msg,
1792 const struct timeval *endtime)
1794 struct ldap_message *res1, *res2 = NULL;
1795 if (!ldap_setsearchent(conn, msg, endtime))
1798 res1 = ldap_getsearchent(conn, endtime);
1801 res2 = ldap_getsearchent(conn, endtime);
1803 ldap_endsearchent(conn, endtime);
1809 /* More than one entry */
1810 destroy_ldap_message(res1);
1811 destroy_ldap_message(res2);
1818 BOOL ldap_find_single_value(struct ldap_message *msg, const char *attr,
1822 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
1824 if (msg->type != LDAP_TAG_SearchResultEntry)
1827 for (i=0; i<r->num_attributes; i++) {
1828 if (strequal(attr, r->attributes[i].name)) {
1829 if (r->attributes[i].num_values != 1)
1832 *value = r->attributes[i].values[0];
1839 BOOL ldap_find_single_string(struct ldap_message *msg, const char *attr,
1840 TALLOC_CTX *mem_ctx, char **value)
1844 if (!ldap_find_single_value(msg, attr, &blob))
1847 *value = talloc(mem_ctx, blob.length+1);
1852 memcpy(*value, blob.data, blob.length);
1853 (*value)[blob.length] = '\0';
1857 BOOL ldap_find_single_int(struct ldap_message *msg, const char *attr,
1865 if (!ldap_find_single_value(msg, attr, &blob))
1868 val = malloc(blob.length+1);
1872 memcpy(val, blob.data, blob.length);
1873 val[blob.length] = '\0';
1878 *value = strtol(val, NULL, 10);
1888 int ldap_error(struct ldap_connection *conn)
1893 NTSTATUS ldap2nterror(int ldaperror)
1895 return NT_STATUS_OK;