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"
29 /****************************************************************************
31 * LDAP filter parser -- main routine is ldap_parse_filter
33 * Shamelessly stolen and adapted from ldb.
35 ***************************************************************************/
38 return next token element. Caller frees
40 static char *ldap_parse_lex(TALLOC_CTX *mem_ctx, const char **s,
55 if (strchr(sep, *p)) {
57 ret = talloc_strndup(mem_ctx, p, 1);
64 while (*p && (isalnum(*p) || !strchr(sep, *p))) {
72 ret = talloc_strndup(mem_ctx, *s, p - *s);
84 find a matching close brace in a string
86 static const char *match_brace(const char *s)
88 unsigned int count = 0;
89 while (*s && (count != 0 || *s != ')')) {
104 static struct ldap_parse_tree *ldap_parse_filter(TALLOC_CTX *mem_ctx,
108 <simple> ::= <attributetype> <filtertype> <attributevalue>
110 static struct ldap_parse_tree *ldap_parse_simple(TALLOC_CTX *mem_ctx,
114 struct ldap_parse_tree *ret;
116 l = ldap_parse_lex(mem_ctx, &s, LDAP_ALL_SEP);
121 if (strchr("()&|=", *l))
124 eq = ldap_parse_lex(mem_ctx, &s, LDAP_ALL_SEP);
125 if (!eq || strcmp(eq, "=") != 0)
128 val = ldap_parse_lex(mem_ctx, &s, ")");
129 if (val && strchr("()&|", *val))
132 ret = talloc(mem_ctx, sizeof(*ret));
138 ret->operation = LDAP_OP_SIMPLE;
139 ret->u.simple.attr = l;
140 ret->u.simple.value.data = val;
141 ret->u.simple.value.length = val?strlen(val):0;
149 <and> ::= '&' <filterlist>
150 <or> ::= '|' <filterlist>
151 <filterlist> ::= <filter> | <filter> <filterlist>
153 static struct ldap_parse_tree *ldap_parse_filterlist(TALLOC_CTX *mem_ctx,
154 enum ldap_parse_op op,
157 struct ldap_parse_tree *ret, *next;
159 ret = talloc(mem_ctx, sizeof(*ret));
167 ret->u.list.num_elements = 1;
168 ret->u.list.elements = talloc(mem_ctx, sizeof(*ret->u.list.elements));
169 if (!ret->u.list.elements) {
174 ret->u.list.elements[0] = ldap_parse_filter(mem_ctx, &s);
175 if (!ret->u.list.elements[0]) {
179 while (isspace(*s)) s++;
181 while (*s && (next = ldap_parse_filter(mem_ctx, &s))) {
182 struct ldap_parse_tree **e;
183 e = talloc_realloc_p(ret,
184 ret->u.list.elements,
185 struct ldap_parse_tree *,
186 ret->u.list.num_elements+1);
191 ret->u.list.elements = e;
192 ret->u.list.elements[ret->u.list.num_elements] = next;
193 ret->u.list.num_elements++;
194 while (isspace(*s)) s++;
202 <not> ::= '!' <filter>
204 static struct ldap_parse_tree *ldap_parse_not(TALLOC_CTX *mem_ctx, const char *s)
206 struct ldap_parse_tree *ret;
208 ret = talloc(mem_ctx, sizeof(*ret));
214 ret->operation = LDAP_OP_NOT;
215 ret->u.not.child = ldap_parse_filter(mem_ctx, &s);
216 if (!ret->u.not.child)
224 <filtercomp> ::= <and> | <or> | <not> | <simple>
226 static struct ldap_parse_tree *ldap_parse_filtercomp(TALLOC_CTX *mem_ctx,
229 while (isspace(*s)) s++;
233 return ldap_parse_filterlist(mem_ctx, LDAP_OP_AND, s+1);
236 return ldap_parse_filterlist(mem_ctx, LDAP_OP_OR, s+1);
239 return ldap_parse_not(mem_ctx, s+1);
246 return ldap_parse_simple(mem_ctx, s);
251 <filter> ::= '(' <filtercomp> ')'
253 static struct ldap_parse_tree *ldap_parse_filter(TALLOC_CTX *mem_ctx,
258 struct ldap_parse_tree *ret;
260 l = ldap_parse_lex(mem_ctx, s, LDAP_ALL_SEP);
265 if (strcmp(l, "(") != 0) {
275 s2 = talloc_strndup(mem_ctx, *s, p - *s);
281 ret = ldap_parse_filtercomp(mem_ctx, s2);
289 main parser entry point. Takes a search string and returns a parse tree
291 expression ::= <simple> | <filter>
293 static struct ldap_parse_tree *ldap_parse_tree(TALLOC_CTX *mem_ctx, const char *s)
295 while (isspace(*s)) s++;
298 return ldap_parse_filter(mem_ctx, &s);
301 return ldap_parse_simple(mem_ctx, s);
304 static BOOL ldap_push_filter(ASN1_DATA *data, struct ldap_parse_tree *tree)
306 switch (tree->operation) {
307 case LDAP_OP_SIMPLE: {
308 if ((tree->u.simple.value.length == 1) &&
309 (((char *)(tree->u.simple.value.data))[0] == '*')) {
310 /* Just a presence test */
311 asn1_push_tag(data, 0x87);
312 asn1_write(data, tree->u.simple.attr,
313 strlen(tree->u.simple.attr));
315 return !data->has_error;
318 /* Equality is all we currently do... */
319 asn1_push_tag(data, 0xa3);
320 asn1_write_OctetString(data, tree->u.simple.attr,
321 strlen(tree->u.simple.attr));
322 asn1_write_OctetString(data, tree->u.simple.value.data,
323 tree->u.simple.value.length);
331 asn1_push_tag(data, 0xa0);
332 for (i=0; i<tree->u.list.num_elements; i++) {
333 ldap_push_filter(data, tree->u.list.elements[i]);
342 asn1_push_tag(data, 0xa1);
343 for (i=0; i<tree->u.list.num_elements; i++) {
344 ldap_push_filter(data, tree->u.list.elements[i]);
352 return !data->has_error;
355 static void ldap_encode_response(ASN1_DATA *data, struct ldap_Result *result)
357 asn1_write_enumerated(data, result->resultcode);
358 asn1_write_OctetString(data, result->dn,
359 (result->dn) ? strlen(result->dn) : 0);
360 asn1_write_OctetString(data, result->errormessage,
361 (result->errormessage) ?
362 strlen(result->errormessage) : 0);
363 if (result->referral != NULL)
364 asn1_write_OctetString(data, result->referral,
365 strlen(result->referral));
368 BOOL ldap_encode(struct ldap_message *msg, DATA_BLOB *result)
374 asn1_push_tag(&data, ASN1_SEQUENCE(0));
375 asn1_write_Integer(&data, msg->messageid);
378 case LDAP_TAG_BindRequest: {
379 struct ldap_BindRequest *r = &msg->r.BindRequest;
380 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
381 asn1_write_Integer(&data, r->version);
382 asn1_write_OctetString(&data, r->dn,
383 (r->dn != NULL) ? strlen(r->dn) : 0);
385 switch (r->mechanism) {
386 case LDAP_AUTH_MECH_SIMPLE:
387 /* context, primitive */
388 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
389 asn1_write(&data, r->creds.password,
390 strlen(r->creds.password));
393 case LDAP_AUTH_MECH_SASL:
394 /* context, constructed */
395 asn1_push_tag(&data, ASN1_CONTEXT(3));
396 asn1_write_OctetString(&data, r->creds.SASL.mechanism,
397 strlen(r->creds.SASL.mechanism));
398 asn1_write_OctetString(&data, r->creds.SASL.secblob.data,
399 r->creds.SASL.secblob.length);
410 case LDAP_TAG_BindResponse: {
411 struct ldap_BindResponse *r = &msg->r.BindResponse;
412 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
413 ldap_encode_response(&data, &r->response);
414 if (r->SASL.secblob.length > 0) {
415 asn1_write_ContextSimple(&data, 7, &r->SASL.secblob);
420 case LDAP_TAG_UnbindRequest: {
421 /* struct ldap_UnbindRequest *r = &msg->r.UnbindRequest; */
424 case LDAP_TAG_SearchRequest: {
425 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
426 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
427 asn1_write_OctetString(&data, r->basedn, strlen(r->basedn));
428 asn1_write_enumerated(&data, r->scope);
429 asn1_write_enumerated(&data, r->deref);
430 asn1_write_Integer(&data, r->sizelimit);
431 asn1_write_Integer(&data, r->timelimit);
432 asn1_write_BOOLEAN(&data, r->attributesonly);
435 TALLOC_CTX *mem_ctx = talloc_init("ldap_parse_tree");
436 struct ldap_parse_tree *tree;
441 tree = ldap_parse_tree(mem_ctx, r->filter);
446 ldap_push_filter(&data, tree);
448 talloc_destroy(mem_ctx);
451 asn1_push_tag(&data, ASN1_SEQUENCE(0));
452 for (i=0; i<r->num_attributes; i++) {
453 asn1_write_OctetString(&data, r->attributes[i],
454 strlen(r->attributes[i]));
461 case LDAP_TAG_SearchResultEntry: {
462 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
463 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
464 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
465 asn1_push_tag(&data, ASN1_SEQUENCE(0));
466 for (i=0; i<r->num_attributes; i++) {
467 struct ldap_attribute *attr = &r->attributes[i];
468 asn1_push_tag(&data, ASN1_SEQUENCE(0));
469 asn1_write_OctetString(&data, attr->name,
471 asn1_push_tag(&data, ASN1_SEQUENCE(1));
472 for (j=0; j<attr->num_values; j++) {
473 asn1_write_OctetString(&data,
474 attr->values[j].data,
475 attr->values[j].length);
484 case LDAP_TAG_SearchResultDone: {
485 struct ldap_Result *r = &msg->r.SearchResultDone;
486 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
487 ldap_encode_response(&data, r);
491 case LDAP_TAG_ModifyRequest: {
492 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
493 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
494 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
495 asn1_push_tag(&data, ASN1_SEQUENCE(0));
497 for (i=0; i<r->num_mods; i++) {
498 struct ldap_attribute *attrib = &r->mods[i].attrib;
499 asn1_push_tag(&data, ASN1_SEQUENCE(0));
500 asn1_write_enumerated(&data, r->mods[i].type);
501 asn1_push_tag(&data, ASN1_SEQUENCE(0));
502 asn1_write_OctetString(&data, attrib->name,
503 strlen(attrib->name));
504 asn1_push_tag(&data, ASN1_SET);
505 for (j=0; j<attrib->num_values; j++) {
506 asn1_write_OctetString(&data,
507 attrib->values[j].data,
508 attrib->values[j].length);
520 case LDAP_TAG_ModifyResponse: {
521 struct ldap_Result *r = &msg->r.ModifyResponse;
522 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
523 ldap_encode_response(&data, r);
527 case LDAP_TAG_AddRequest: {
528 struct ldap_AddRequest *r = &msg->r.AddRequest;
529 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
530 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
531 asn1_push_tag(&data, ASN1_SEQUENCE(0));
533 for (i=0; i<r->num_attributes; i++) {
534 struct ldap_attribute *attrib = &r->attributes[i];
535 asn1_push_tag(&data, ASN1_SEQUENCE(0));
536 asn1_write_OctetString(&data, attrib->name,
537 strlen(attrib->name));
538 asn1_push_tag(&data, ASN1_SET);
539 for (j=0; j<r->attributes[i].num_values; j++) {
540 asn1_write_OctetString(&data,
541 attrib->values[j].data,
542 attrib->values[j].length);
551 case LDAP_TAG_AddResponse: {
552 struct ldap_Result *r = &msg->r.AddResponse;
553 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
554 ldap_encode_response(&data, r);
558 case LDAP_TAG_DelRequest: {
559 struct ldap_DelRequest *r = &msg->r.DelRequest;
560 asn1_push_tag(&data, ASN1_APPLICATION_SIMPLE(msg->type));
561 asn1_write(&data, r->dn, strlen(r->dn));
565 case LDAP_TAG_DelResponse: {
566 struct ldap_Result *r = &msg->r.DelResponse;
567 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
568 ldap_encode_response(&data, r);
572 case LDAP_TAG_ModifyDNRequest: {
573 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
574 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
575 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
576 asn1_write_OctetString(&data, r->newrdn, strlen(r->newrdn));
577 asn1_write_BOOLEAN(&data, r->deleteolddn);
578 if (r->newsuperior != NULL) {
579 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
580 asn1_write(&data, r->newsuperior,
581 strlen(r->newsuperior));
587 case LDAP_TAG_ModifyDNResponse: {
588 struct ldap_Result *r = &msg->r.ModifyDNResponse;
589 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
590 ldap_encode_response(&data, r);
594 case LDAP_TAG_CompareRequest: {
595 struct ldap_CompareRequest *r = &msg->r.CompareRequest;
596 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
597 asn1_write_OctetString(&data, r->dn, strlen(r->dn));
598 asn1_push_tag(&data, ASN1_SEQUENCE(0));
599 asn1_write_OctetString(&data, r->attribute,
600 strlen(r->attribute));
601 asn1_write_OctetString(&data, r->value.data,
607 case LDAP_TAG_CompareResponse: {
608 struct ldap_Result *r = &msg->r.ModifyDNResponse;
609 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
610 ldap_encode_response(&data, r);
614 case LDAP_TAG_AbandonRequest: {
615 struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
616 asn1_push_tag(&data, ASN1_APPLICATION_SIMPLE(msg->type));
617 asn1_write_implicit_Integer(&data, r->messageid);
621 case LDAP_TAG_SearchResultReference: {
622 /* struct ldap_SearchResRef *r = &msg->r.SearchResultReference; */
625 case LDAP_TAG_ExtendedRequest: {
626 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
627 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
628 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
629 asn1_write(&data, r->oid, strlen(r->oid));
631 asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(1));
632 asn1_write(&data, r->value.data, r->value.length);
637 case LDAP_TAG_ExtendedResponse: {
638 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
639 asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
640 ldap_encode_response(&data, &r->response);
649 *result = data_blob(data.data, data.length);
654 static const char *blob2string_talloc(TALLOC_CTX *mem_ctx,
657 char *result = talloc(mem_ctx, blob.length+1);
658 memcpy(result, blob.data, blob.length);
659 result[blob.length] = '\0';
663 static BOOL asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
668 if (!asn1_read_OctetString(data, &string))
670 *result = blob2string_talloc(mem_ctx, string);
671 data_blob_free(&string);
675 static void ldap_decode_response(TALLOC_CTX *mem_ctx,
677 struct ldap_Result *result)
679 asn1_read_enumerated(data, &result->resultcode);
680 asn1_read_OctetString_talloc(mem_ctx, data, &result->dn);
681 asn1_read_OctetString_talloc(mem_ctx, data, &result->errormessage);
682 if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
683 asn1_start_tag(data, ASN1_CONTEXT(3));
684 asn1_read_OctetString_talloc(mem_ctx, data, &result->referral);
687 result->referral = NULL;
691 static BOOL ldap_decode_filter(TALLOC_CTX *mem_ctx, ASN1_DATA *data,
694 uint8 filter_tag, tag_desc;
696 if (!asn1_peek_uint8(data, &filter_tag))
699 tag_desc = filter_tag;
700 filter_tag &= 0x1f; /* strip off the asn1 stuff */
705 /* AND of one or more filters */
706 if (tag_desc != 0xa0) /* context compount */
709 asn1_start_tag(data, ASN1_CONTEXT(0));
711 *filter = talloc_strdup(mem_ctx, "(&");
715 while (asn1_tag_remaining(data) > 0) {
717 if (!ldap_decode_filter(mem_ctx, data, &subfilter))
719 *filter = talloc_asprintf(mem_ctx, "%s%s", *filter,
726 *filter = talloc_asprintf(mem_ctx, "%s)", *filter);
730 /* OR of one or more filters */
731 if (tag_desc != 0xa0) /* context compount */
734 asn1_start_tag(data, ASN1_CONTEXT(1));
736 *filter = talloc_strdup(mem_ctx, "(|");
740 while (asn1_tag_remaining(data) > 0) {
742 if (!ldap_decode_filter(mem_ctx, data, &subfilter))
744 *filter = talloc_asprintf(mem_ctx, "%s%s", *filter,
752 *filter = talloc_asprintf(mem_ctx, "%s)", *filter);
757 const char *attrib, *value;
758 if (tag_desc != 0xa0) /* context compound */
760 asn1_start_tag(data, ASN1_CONTEXT(3));
761 asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
762 asn1_read_OctetString_talloc(mem_ctx, data, &value);
764 if ((data->has_error) || (attrib == NULL) || (value == NULL))
766 *filter = talloc_asprintf(mem_ctx, "(%s=%s)", attrib, value);
770 /* Normal presence, "attribute=*" */
773 if (tag_desc != 0x80) /* context simple */
775 if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(7)))
777 attr_len = asn1_tag_remaining(data);
778 attr_name = malloc(attr_len+1);
779 if (attr_name == NULL)
781 asn1_read(data, attr_name, attr_len);
782 attr_name[attr_len] = '\0';
783 *filter = talloc_asprintf(mem_ctx, "(%s=*)", attr_name);
784 SAFE_FREE(attr_name);
796 static void ldap_decode_attrib(TALLOC_CTX *mem_ctx, ASN1_DATA *data,
797 struct ldap_attribute *attrib)
799 asn1_start_tag(data, ASN1_SEQUENCE(0));
800 asn1_read_OctetString_talloc(mem_ctx, data, &attrib->name);
801 asn1_start_tag(data, ASN1_SET);
802 while (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
804 struct ldap_val value;
805 asn1_read_OctetString(data, &blob);
806 value.data = blob.data;
807 value.length = blob.length;
808 add_value_to_attrib(mem_ctx, &value, attrib);
809 data_blob_free(&blob);
816 static void ldap_decode_attribs(TALLOC_CTX *mem_ctx, ASN1_DATA *data,
817 struct ldap_attribute **attributes,
820 asn1_start_tag(data, ASN1_SEQUENCE(0));
821 while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
822 struct ldap_attribute attrib;
824 ldap_decode_attrib(mem_ctx, data, &attrib);
825 add_attrib_to_array_talloc(mem_ctx, &attrib,
826 attributes, num_attributes);
831 BOOL ldap_decode(ASN1_DATA *data, struct ldap_message *msg)
835 asn1_start_tag(data, ASN1_SEQUENCE(0));
836 asn1_read_Integer(data, &msg->messageid);
838 if (!asn1_peek_uint8(data, &tag))
843 case ASN1_APPLICATION(LDAP_TAG_BindRequest): {
844 struct ldap_BindRequest *r = &msg->r.BindRequest;
845 msg->type = LDAP_TAG_BindRequest;
846 asn1_start_tag(data, tag);
847 asn1_read_Integer(data, &r->version);
848 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
849 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(0))) {
851 r->creds.password = "";
852 r->mechanism = LDAP_AUTH_MECH_SIMPLE;
853 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0));
854 pwlen = asn1_tag_remaining(data);
856 char *pw = talloc(msg->mem_ctx, pwlen+1);
857 asn1_read(data, pw, pwlen);
859 r->creds.password = pw;
862 } else if (asn1_peek_tag(data, ASN1_CONTEXT(3))){
863 asn1_start_tag(data, ASN1_CONTEXT(3));
864 r->mechanism = LDAP_AUTH_MECH_SASL;
865 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->creds.SASL.mechanism);
866 asn1_read_OctetString(data, &r->creds.SASL.secblob);
867 if (r->creds.SASL.secblob.data) {
868 talloc_steal(msg->mem_ctx, r->creds.SASL.secblob.data);
876 case ASN1_APPLICATION(LDAP_TAG_BindResponse): {
877 struct ldap_BindResponse *r = &msg->r.BindResponse;
878 msg->type = LDAP_TAG_BindResponse;
879 asn1_start_tag(data, tag);
880 ldap_decode_response(msg->mem_ctx, data, &r->response);
881 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(7))) {
882 DATA_BLOB tmp_blob = data_blob(NULL, 0);
883 asn1_read_ContextSimple(data, 7, &tmp_blob);
884 r->SASL.secblob = data_blob_talloc(msg->mem_ctx, tmp_blob.data, tmp_blob.length);
885 data_blob_free(&tmp_blob);
887 r->SASL.secblob = data_blob(NULL, 0);
893 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_UnbindRequest): {
894 msg->type = LDAP_TAG_UnbindRequest;
895 asn1_start_tag(data, tag);
900 case ASN1_APPLICATION(LDAP_TAG_SearchRequest): {
901 struct ldap_SearchRequest *r = &msg->r.SearchRequest;
902 msg->type = LDAP_TAG_SearchRequest;
903 asn1_start_tag(data, tag);
904 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->basedn);
905 asn1_read_enumerated(data, (int *)&(r->scope));
906 asn1_read_enumerated(data, (int *)&(r->deref));
907 asn1_read_Integer(data, &r->sizelimit);
908 asn1_read_Integer(data, &r->timelimit);
909 asn1_read_BOOLEAN(data, &r->attributesonly);
911 /* Maybe create a TALLOC_CTX for the filter? This can waste
912 * quite a bit of memory recursing down. */
913 ldap_decode_filter(msg->mem_ctx, data, &r->filter);
915 asn1_start_tag(data, ASN1_SEQUENCE(0));
917 r->num_attributes = 0;
918 r->attributes = NULL;
920 while (asn1_tag_remaining(data) > 0) {
922 if (!asn1_read_OctetString_talloc(msg->mem_ctx, data,
925 if (!add_string_to_array(msg->mem_ctx, attr,
936 case ASN1_APPLICATION(LDAP_TAG_SearchResultEntry): {
937 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
938 msg->type = LDAP_TAG_SearchResultEntry;
939 r->attributes = NULL;
940 r->num_attributes = 0;
941 asn1_start_tag(data, tag);
942 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
943 ldap_decode_attribs(msg->mem_ctx, data, &r->attributes,
949 case ASN1_APPLICATION(LDAP_TAG_SearchResultDone): {
950 struct ldap_Result *r = &msg->r.SearchResultDone;
951 msg->type = LDAP_TAG_SearchResultDone;
952 asn1_start_tag(data, tag);
953 ldap_decode_response(msg->mem_ctx, data, r);
958 case ASN1_APPLICATION(LDAP_TAG_SearchResultReference): {
959 /* struct ldap_SearchResRef *r = &msg->r.SearchResultReference; */
960 msg->type = LDAP_TAG_SearchResultReference;
964 case ASN1_APPLICATION(LDAP_TAG_ModifyRequest): {
965 struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
966 msg->type = LDAP_TAG_ModifyRequest;
967 asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_ModifyRequest));
968 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
969 asn1_start_tag(data, ASN1_SEQUENCE(0));
974 while (asn1_tag_remaining(data) > 0) {
977 asn1_start_tag(data, ASN1_SEQUENCE(0));
978 asn1_read_enumerated(data, &mod.type);
979 ldap_decode_attrib(msg->mem_ctx, data, &mod.attrib);
981 if (!add_mod_to_array_talloc(msg->mem_ctx, &mod,
982 &r->mods, &r->num_mods))
991 case ASN1_APPLICATION(LDAP_TAG_ModifyResponse): {
992 struct ldap_Result *r = &msg->r.ModifyResponse;
993 msg->type = LDAP_TAG_ModifyResponse;
994 asn1_start_tag(data, tag);
995 ldap_decode_response(msg->mem_ctx, data, r);
1000 case ASN1_APPLICATION(LDAP_TAG_AddRequest): {
1001 struct ldap_AddRequest *r = &msg->r.AddRequest;
1002 msg->type = LDAP_TAG_AddRequest;
1003 asn1_start_tag(data, tag);
1004 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
1006 r->attributes = NULL;
1007 r->num_attributes = 0;
1008 ldap_decode_attribs(msg->mem_ctx, data, &r->attributes,
1009 &r->num_attributes);
1015 case ASN1_APPLICATION(LDAP_TAG_AddResponse): {
1016 struct ldap_Result *r = &msg->r.AddResponse;
1017 msg->type = LDAP_TAG_AddResponse;
1018 asn1_start_tag(data, tag);
1019 ldap_decode_response(msg->mem_ctx, data, r);
1024 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest): {
1025 struct ldap_DelRequest *r = &msg->r.DelRequest;
1028 msg->type = LDAP_TAG_DelRequest;
1029 asn1_start_tag(data,
1030 ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest));
1031 len = asn1_tag_remaining(data);
1032 dn = talloc(msg->mem_ctx, len+1);
1035 asn1_read(data, dn, len);
1042 case ASN1_APPLICATION(LDAP_TAG_DelResponse): {
1043 struct ldap_Result *r = &msg->r.DelResponse;
1044 msg->type = LDAP_TAG_DelResponse;
1045 asn1_start_tag(data, tag);
1046 ldap_decode_response(msg->mem_ctx, data, r);
1051 case ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest): {
1052 struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
1053 msg->type = LDAP_TAG_ModifyDNRequest;
1054 asn1_start_tag(data,
1055 ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest));
1056 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
1057 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->newrdn);
1058 asn1_read_BOOLEAN(data, &r->deleteolddn);
1059 r->newsuperior = NULL;
1060 if (asn1_tag_remaining(data) > 0) {
1063 asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0));
1064 len = asn1_tag_remaining(data);
1065 newsup = talloc(msg->mem_ctx, len+1);
1068 asn1_read(data, newsup, len);
1070 r->newsuperior = newsup;
1077 case ASN1_APPLICATION(LDAP_TAG_ModifyDNResponse): {
1078 struct ldap_Result *r = &msg->r.ModifyDNResponse;
1079 msg->type = LDAP_TAG_ModifyDNResponse;
1080 asn1_start_tag(data, tag);
1081 ldap_decode_response(msg->mem_ctx, data, r);
1086 case ASN1_APPLICATION(LDAP_TAG_CompareRequest): {
1087 struct ldap_CompareRequest *r = &msg->r.CompareRequest;
1088 msg->type = LDAP_TAG_CompareRequest;
1089 asn1_start_tag(data,
1090 ASN1_APPLICATION(LDAP_TAG_CompareRequest));
1091 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->dn);
1092 asn1_start_tag(data, ASN1_SEQUENCE(0));
1093 asn1_read_OctetString_talloc(msg->mem_ctx, data, &r->attribute);
1094 asn1_read_OctetString(data, &r->value);
1095 if (r->value.data) {
1096 talloc_steal(msg->mem_ctx, r->value.data);
1103 case ASN1_APPLICATION(LDAP_TAG_CompareResponse): {
1104 struct ldap_Result *r = &msg->r.CompareResponse;
1105 msg->type = LDAP_TAG_CompareResponse;
1106 asn1_start_tag(data, tag);
1107 ldap_decode_response(msg->mem_ctx, data, r);
1112 case ASN1_APPLICATION_SIMPLE(LDAP_TAG_AbandonRequest): {
1113 struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
1114 msg->type = LDAP_TAG_AbandonRequest;
1115 asn1_start_tag(data, tag);
1116 asn1_read_implicit_Integer(data, &r->messageid);
1121 case ASN1_APPLICATION(LDAP_TAG_ExtendedRequest): {
1122 struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
1123 DATA_BLOB tmp_blob = data_blob(NULL, 0);
1125 msg->type = LDAP_TAG_ExtendedRequest;
1126 asn1_start_tag(data,tag);
1127 if (!asn1_read_ContextSimple(data, 0, &tmp_blob)) {
1130 r->oid = blob2string_talloc(msg->mem_ctx, tmp_blob);
1131 data_blob_free(&tmp_blob);
1136 if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(1))) {
1137 asn1_read_ContextSimple(data, 1, &tmp_blob);
1138 r->value = data_blob_talloc(msg->mem_ctx, tmp_blob.data, tmp_blob.length);
1139 data_blob_free(&tmp_blob);
1141 r->value = data_blob(NULL, 0);
1148 case ASN1_APPLICATION(LDAP_TAG_ExtendedResponse): {
1149 struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
1150 msg->type = LDAP_TAG_ExtendedResponse;
1151 asn1_start_tag(data, tag);
1152 ldap_decode_response(msg->mem_ctx, data, &r->response);
1153 /* I have to come across an operation that actually sends
1154 * something back to really see what's going on. The currently
1155 * needed pwdchange does not send anything back. */
1157 r->value.data = NULL;
1158 r->value.length = 0;
1166 msg->num_controls = 0;
1167 msg->controls = NULL;
1169 if (asn1_peek_tag(data, ASN1_CONTEXT(0))) {
1171 struct ldap_Control *ctrl = NULL;
1173 asn1_start_tag(data, ASN1_CONTEXT(0));
1175 for (i=0; asn1_peek_tag(data, ASN1_SEQUENCE(0)); i++) {
1176 asn1_start_tag(data, ASN1_SEQUENCE(0));
1178 ctrl = talloc_realloc_p(msg->mem_ctx, ctrl, struct ldap_Control, i+1);
1183 ctrl[i].critical = False;
1184 ctrl[i].value = data_blob(NULL, 0);
1186 asn1_read_OctetString_talloc(ctrl, data, &ctrl[i].oid);
1188 if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
1189 asn1_read_BOOLEAN(data, &ctrl[i].critical);
1192 if (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
1193 asn1_read_OctetString(data, &ctrl[i].value);
1194 if (ctrl[i].value.data) {
1195 talloc_steal(msg->mem_ctx, ctrl[i].value.data);
1201 msg->num_controls = i;
1202 msg->controls = ctrl;
1208 return ((!data->has_error) && (data->nesting == NULL));
1211 BOOL ldap_parse_basic_url(TALLOC_CTX *mem_ctx, const char *url,
1212 char **host, uint16 *port, BOOL *ldaps)
1217 const char *p = url;
1219 /* skip leading "URL:" (if any) */
1220 if (strncasecmp( p, "URL:", 4) == 0) {
1224 /* Paranoia check */
1225 SMB_ASSERT(sizeof(protocol)>10 && sizeof(tmp_host)>254);
1227 sscanf(p, "%10[^:]://%254[^:/]:%d", protocol, tmp_host, &tmp_port);
1229 if (strequal(protocol, "ldap")) {
1232 } else if (strequal(protocol, "ldaps")) {
1236 DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
1243 *host = talloc_strdup(mem_ctx, tmp_host);
1245 return (*host != NULL);
1248 struct ldap_connection *new_ldap_connection(void)
1250 TALLOC_CTX *mem_ctx = talloc_init("ldap_connection");
1251 struct ldap_connection *result;
1253 if (mem_ctx == NULL)
1256 result = talloc(mem_ctx, sizeof(*result));
1261 result->mem_ctx = mem_ctx;
1262 result->next_msgid = 1;
1263 result->outstanding = NULL;
1264 result->searchid = 0;
1265 result->search_entries = NULL;
1266 result->auth_dn = NULL;
1267 result->simple_pw = NULL;
1268 result->gensec = NULL;
1273 BOOL ldap_connect(struct ldap_connection *conn, const char *url)
1276 struct ipv4_addr ip;
1278 if (!ldap_parse_basic_url(conn->mem_ctx, url, &conn->host,
1279 &conn->port, &conn->ldaps))
1282 hp = sys_gethostbyname(conn->host);
1284 if ((hp == NULL) || (hp->h_addr == NULL))
1287 putip((char *)&ip, (char *)hp->h_addr);
1289 conn->sock = open_socket_out(SOCK_STREAM, &ip, conn->port, LDAP_CONNECTION_TIMEOUT);
1291 return (conn->sock >= 0);
1294 BOOL ldap_set_simple_creds(struct ldap_connection *conn,
1295 const char *dn, const char *password)
1297 conn->auth_dn = talloc_strdup(conn->mem_ctx, dn);
1298 conn->simple_pw = talloc_strdup(conn->mem_ctx, password);
1300 return ((conn->auth_dn != NULL) && (conn->simple_pw != NULL));
1303 struct ldap_message *new_ldap_message(void)
1305 TALLOC_CTX *mem_ctx = talloc_init("ldap_message");
1306 struct ldap_message *result;
1308 if (mem_ctx == NULL)
1311 result = talloc(mem_ctx, sizeof(*result));
1316 result->mem_ctx = mem_ctx;
1320 void destroy_ldap_message(struct ldap_message *msg)
1323 talloc_destroy(msg->mem_ctx);
1326 BOOL ldap_send_msg(struct ldap_connection *conn, struct ldap_message *msg,
1327 const struct timeval *endtime)
1331 struct ldap_queue_entry *entry;
1333 msg->messageid = conn->next_msgid++;
1335 if (!ldap_encode(msg, &request))
1338 result = (write_data_until(conn->sock, request.data, request.length,
1339 endtime) == request.length);
1341 data_blob_free(&request);
1346 /* abandon and unbind don't expect results */
1348 if ((msg->type == LDAP_TAG_AbandonRequest) ||
1349 (msg->type == LDAP_TAG_UnbindRequest))
1352 entry = malloc(sizeof(*entry));
1357 entry->msgid = msg->messageid;
1359 DLIST_ADD(conn->outstanding, entry);
1364 BOOL ldap_receive_msg(struct ldap_connection *conn, struct ldap_message *msg,
1365 const struct timeval *endtime)
1367 struct asn1_data data;
1370 if (!asn1_read_sequence_until(conn->sock, &data, endtime))
1373 result = ldap_decode(&data, msg);
1379 static struct ldap_message *recv_from_queue(struct ldap_connection *conn,
1382 struct ldap_queue_entry *e;
1384 for (e = conn->outstanding; e != NULL; e = e->next) {
1386 if (e->msgid == msgid) {
1387 struct ldap_message *result = e->msg;
1388 DLIST_REMOVE(conn->outstanding, e);
1397 static void add_search_entry(struct ldap_connection *conn,
1398 struct ldap_message *msg)
1400 struct ldap_queue_entry *e = malloc(sizeof *e);
1406 DLIST_ADD_END(conn->search_entries, e, struct ldap_queue_entry *);
1410 static void fill_outstanding_request(struct ldap_connection *conn,
1411 struct ldap_message *msg)
1413 struct ldap_queue_entry *e;
1415 for (e = conn->outstanding; e != NULL; e = e->next) {
1416 if (e->msgid == msg->messageid) {
1422 /* This reply has not been expected, destroy the incoming msg */
1423 destroy_ldap_message(msg);
1427 struct ldap_message *ldap_receive(struct ldap_connection *conn, int msgid,
1428 const struct timeval *endtime)
1430 struct ldap_message *result = recv_from_queue(conn, msgid);
1436 struct asn1_data data;
1439 result = new_ldap_message();
1441 if (!asn1_read_sequence_until(conn->sock, &data, endtime))
1444 res = ldap_decode(&data, result);
1450 if (result->messageid == msgid)
1453 if (result->type == LDAP_TAG_SearchResultEntry) {
1454 add_search_entry(conn, result);
1456 fill_outstanding_request(conn, result);
1463 struct ldap_message *ldap_transaction(struct ldap_connection *conn,
1464 struct ldap_message *request)
1466 if (!ldap_send_msg(conn, request, NULL))
1469 return ldap_receive(conn, request->messageid, NULL);
1472 int ldap_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password)
1474 struct ldap_message *response;
1475 struct ldap_message *msg;
1476 const char *dn, *pw;
1477 int result = LDAP_OTHER;
1485 if (conn->auth_dn) {
1495 if (conn->simple_pw) {
1496 pw = conn->simple_pw;
1502 msg = new_ldap_simple_bind_msg(dn, pw);
1506 response = ldap_transaction(conn, msg);
1508 destroy_ldap_message(msg);
1512 result = response->r.BindResponse.response.resultcode;
1514 destroy_ldap_message(msg);
1515 destroy_ldap_message(response);
1520 int ldap_bind_sasl(struct ldap_connection *conn, const char *username, const char *domain, const char *password)
1523 TALLOC_CTX *mem_ctx = NULL;
1524 struct ldap_message *response;
1525 struct ldap_message *msg;
1526 DATA_BLOB input = data_blob(NULL, 0);
1527 DATA_BLOB output = data_blob(NULL, 0);
1528 int result = LDAP_OTHER;
1533 status = gensec_client_start(conn, &conn->gensec);
1534 if (!NT_STATUS_IS_OK(status)) {
1535 DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
1539 gensec_want_feature(conn->gensec, GENSEC_WANT_SIGN | GENSEC_WANT_SEAL);
1541 status = gensec_set_domain(conn->gensec, domain);
1542 if (!NT_STATUS_IS_OK(status)) {
1543 DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n",
1544 domain, nt_errstr(status)));
1548 status = gensec_set_username(conn->gensec, username);
1549 if (!NT_STATUS_IS_OK(status)) {
1550 DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n",
1551 username, nt_errstr(status)));
1555 status = gensec_set_password(conn->gensec, password);
1556 if (!NT_STATUS_IS_OK(status)) {
1557 DEBUG(1, ("Failed to start set GENSEC client password: %s\n",
1558 nt_errstr(status)));
1562 status = gensec_set_target_hostname(conn->gensec, conn->host);
1563 if (!NT_STATUS_IS_OK(status)) {
1564 DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n",
1565 nt_errstr(status)));
1569 status = gensec_start_mech_by_sasl_name(conn->gensec, "GSS-SPNEGO");
1570 if (!NT_STATUS_IS_OK(status)) {
1571 DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",
1572 nt_errstr(status)));
1576 mem_ctx = talloc_init("ldap_bind_sasl");
1580 status = gensec_update(conn->gensec, mem_ctx,
1585 if (NT_STATUS_IS_OK(status) && output.length == 0) {
1588 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
1592 msg = new_ldap_sasl_bind_msg("GSS-SPNEGO", &output);
1596 response = ldap_transaction(conn, msg);
1597 destroy_ldap_message(msg);
1603 result = response->r.BindResponse.response.resultcode;
1605 if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
1609 status = gensec_update(conn->gensec, mem_ctx,
1610 response->r.BindResponse.SASL.secblob,
1613 destroy_ldap_message(response);
1618 talloc_destroy(mem_ctx);
1623 BOOL ldap_setup_connection(struct ldap_connection *conn,
1624 const char *url, const char *userdn, const char *password)
1628 if (!ldap_connect(conn, url)) {
1632 result = ldap_bind_simple(conn, userdn, password);
1633 if (result == LDAP_SUCCESS) {
1640 BOOL ldap_setup_connection_with_sasl(struct ldap_connection *conn, const char *url, const char *username, const char *domain, const char *password)
1644 if (!ldap_connect(conn, url)) {
1648 result = ldap_bind_sasl(conn, username, domain, password);
1649 if (result == LDAP_SUCCESS) {
1656 static BOOL ldap_abandon_message(struct ldap_connection *conn, int msgid,
1657 const struct timeval *endtime)
1659 struct ldap_message *msg = new_ldap_message();
1665 msg->type = LDAP_TAG_AbandonRequest;
1666 msg->r.AbandonRequest.messageid = msgid;
1668 result = ldap_send_msg(conn, msg, endtime);
1669 destroy_ldap_message(msg);
1673 struct ldap_message *new_ldap_search_message(const char *base,
1674 enum ldap_scope scope,
1677 const char **attributes)
1679 struct ldap_message *res = new_ldap_message();
1684 res->type = LDAP_TAG_SearchRequest;
1685 res->r.SearchRequest.basedn = base;
1686 res->r.SearchRequest.scope = scope;
1687 res->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
1688 res->r.SearchRequest.timelimit = 0;
1689 res->r.SearchRequest.sizelimit = 0;
1690 res->r.SearchRequest.attributesonly = False;
1691 res->r.SearchRequest.filter = filter;
1692 res->r.SearchRequest.num_attributes = num_attributes;
1693 res->r.SearchRequest.attributes = attributes;
1697 struct ldap_message *new_ldap_simple_bind_msg(const char *dn, const char *pw)
1699 struct ldap_message *res = new_ldap_message();
1704 res->type = LDAP_TAG_BindRequest;
1705 res->r.BindRequest.version = 3;
1706 res->r.BindRequest.dn = talloc_strdup(res->mem_ctx, dn);
1707 res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SIMPLE;
1708 res->r.BindRequest.creds.password = talloc_strdup(res->mem_ctx, pw);
1712 struct ldap_message *new_ldap_sasl_bind_msg(const char *sasl_mechanism, DATA_BLOB *secblob)
1714 struct ldap_message *res = new_ldap_message();
1719 res->type = LDAP_TAG_BindRequest;
1720 res->r.BindRequest.version = 3;
1721 res->r.BindRequest.dn = "";
1722 res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SASL;
1723 res->r.BindRequest.creds.SASL.mechanism = talloc_strdup(res->mem_ctx, sasl_mechanism);
1724 res->r.BindRequest.creds.SASL.secblob = *secblob;
1728 BOOL ldap_setsearchent(struct ldap_connection *conn, struct ldap_message *msg,
1729 const struct timeval *endtime)
1731 if ((conn->searchid != 0) &&
1732 (!ldap_abandon_message(conn, conn->searchid, endtime)))
1735 conn->searchid = conn->next_msgid;
1736 return ldap_send_msg(conn, msg, endtime);
1739 struct ldap_message *ldap_getsearchent(struct ldap_connection *conn,
1740 const struct timeval *endtime)
1742 struct ldap_message *result;
1744 if (conn->search_entries != NULL) {
1745 struct ldap_queue_entry *e = conn->search_entries;
1748 DLIST_REMOVE(conn->search_entries, e);
1753 result = ldap_receive(conn, conn->searchid, endtime);
1758 if (result->type == LDAP_TAG_SearchResultEntry)
1761 if (result->type == LDAP_TAG_SearchResultDone) {
1762 /* TODO: Handle Paged Results */
1763 destroy_ldap_message(result);
1767 /* TODO: Handle Search References here */
1771 void ldap_endsearchent(struct ldap_connection *conn,
1772 const struct timeval *endtime)
1774 struct ldap_queue_entry *e;
1776 e = conn->search_entries;
1779 struct ldap_queue_entry *next = e->next;
1780 DLIST_REMOVE(conn->search_entries, e);
1786 struct ldap_message *ldap_searchone(struct ldap_connection *conn,
1787 struct ldap_message *msg,
1788 const struct timeval *endtime)
1790 struct ldap_message *res1, *res2 = NULL;
1791 if (!ldap_setsearchent(conn, msg, endtime))
1794 res1 = ldap_getsearchent(conn, endtime);
1797 res2 = ldap_getsearchent(conn, endtime);
1799 ldap_endsearchent(conn, endtime);
1805 /* More than one entry */
1806 destroy_ldap_message(res1);
1807 destroy_ldap_message(res2);
1814 BOOL ldap_find_single_value(struct ldap_message *msg, const char *attr,
1818 struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
1820 if (msg->type != LDAP_TAG_SearchResultEntry)
1823 for (i=0; i<r->num_attributes; i++) {
1824 if (strequal(attr, r->attributes[i].name)) {
1825 if (r->attributes[i].num_values != 1)
1828 *value = r->attributes[i].values[0];
1835 BOOL ldap_find_single_string(struct ldap_message *msg, const char *attr,
1836 TALLOC_CTX *mem_ctx, char **value)
1840 if (!ldap_find_single_value(msg, attr, &blob))
1843 *value = talloc(mem_ctx, blob.length+1);
1848 memcpy(*value, blob.data, blob.length);
1849 (*value)[blob.length] = '\0';
1853 BOOL ldap_find_single_int(struct ldap_message *msg, const char *attr,
1861 if (!ldap_find_single_value(msg, attr, &blob))
1864 val = malloc(blob.length+1);
1868 memcpy(val, blob.data, blob.length);
1869 val[blob.length] = '\0';
1874 *value = strtol(val, NULL, 10);
1884 int ldap_error(struct ldap_connection *conn)
1889 NTSTATUS ldap2nterror(int ldaperror)
1891 return NT_STATUS_OK;