73099ec1be454cc4bae55d01e6ee9ee765d60ed6
[kai/samba.git] / source4 / libcli / ldap / ldap_client.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    LDAP protocol helper functions for SAMBA
4    
5    Copyright (C) Andrew Tridgell  2004
6    Copyright (C) Volker Lendecke 2004
7    Copyright (C) Stefan Metzmacher 2004
8    Copyright (C) Simo Sorce 2004
9     
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.
14    
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.
19    
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.
23    
24 */
25
26 #include "includes.h"
27 #include "system/network.h"
28 #include "auth/auth.h"
29 #include "asn_1.h"
30 #include "dlinklist.h"
31
32
33
34 /****************************************************************************
35  Check the timeout. 
36 ****************************************************************************/
37 static BOOL timeout_until(struct timeval *timeout,
38                           const struct timeval *endtime)
39 {
40         struct timeval now;
41
42         GetTimeOfDay(&now);
43
44         if ((now.tv_sec > endtime->tv_sec) ||
45             ((now.tv_sec == endtime->tv_sec) &&
46              (now.tv_usec > endtime->tv_usec)))
47                 return False;
48
49         timeout->tv_sec = endtime->tv_sec - now.tv_sec;
50         timeout->tv_usec = endtime->tv_usec - now.tv_usec;
51         return True;
52 }
53
54
55 /****************************************************************************
56  Read data from the client, reading exactly N bytes, with timeout. 
57 ****************************************************************************/
58 static ssize_t read_data_until(int fd,char *buffer,size_t N,
59                                const struct timeval *endtime)
60 {
61         ssize_t ret;
62         size_t total=0;  
63  
64         while (total < N) {
65
66                 if (endtime != NULL) {
67                         fd_set r_fds;
68                         struct timeval timeout;
69                         int res;
70
71                         FD_ZERO(&r_fds);
72                         FD_SET(fd, &r_fds);
73
74                         if (!timeout_until(&timeout, endtime))
75                                 return -1;
76
77                         res = sys_select(fd+1, &r_fds, NULL, NULL, &timeout);
78                         if (res <= 0)
79                                 return -1;
80                 }
81
82                 ret = sys_read(fd,buffer + total,N - total);
83
84                 if (ret == 0) {
85                         DEBUG(10,("read_data: read of %d returned 0. Error = %s\n", (int)(N - total), strerror(errno) ));
86                         return 0;
87                 }
88
89                 if (ret == -1) {
90                         DEBUG(0,("read_data: read failure for %d. Error = %s\n", (int)(N - total), strerror(errno) ));
91                         return -1;
92                 }
93                 total += ret;
94         }
95         return (ssize_t)total;
96 }
97
98
99 /****************************************************************************
100  Write data to a fd with timeout.
101 ****************************************************************************/
102 static ssize_t write_data_until(int fd,char *buffer,size_t N,
103                                 const struct timeval *endtime)
104 {
105         size_t total=0;
106         ssize_t ret;
107
108         while (total < N) {
109
110                 if (endtime != NULL) {
111                         fd_set w_fds;
112                         struct timeval timeout;
113                         int res;
114
115                         FD_ZERO(&w_fds);
116                         FD_SET(fd, &w_fds);
117
118                         if (!timeout_until(&timeout, endtime))
119                                 return -1;
120
121                         res = sys_select(fd+1, NULL, &w_fds, NULL, &timeout);
122                         if (res <= 0)
123                                 return -1;
124                 }
125
126                 ret = sys_write(fd,buffer + total,N - total);
127
128                 if (ret == -1) {
129                         DEBUG(0,("write_data: write failure. Error = %s\n", strerror(errno) ));
130                         return -1;
131                 }
132                 if (ret == 0)
133                         return total;
134
135                 total += ret;
136         }
137         return (ssize_t)total;
138 }
139
140
141
142 static BOOL read_one_uint8(int sock, uint8_t *result, struct asn1_data *data,
143                            const struct timeval *endtime)
144 {
145         if (read_data_until(sock, result, 1, endtime) != 1)
146                 return False;
147
148         return asn1_write(data, result, 1);
149 }
150
151 /* Read a complete ASN sequence (ie LDAP result) from a socket */
152 static BOOL asn1_read_sequence_until(int sock, struct asn1_data *data,
153                                      const struct timeval *endtime)
154 {
155         uint8_t b;
156         size_t len;
157         char *buf;
158
159         ZERO_STRUCTP(data);
160
161         if (!read_one_uint8(sock, &b, data, endtime))
162                 return False;
163
164         if (b != 0x30) {
165                 data->has_error = True;
166                 return False;
167         }
168
169         if (!read_one_uint8(sock, &b, data, endtime))
170                 return False;
171
172         if (b & 0x80) {
173                 int n = b & 0x7f;
174                 if (!read_one_uint8(sock, &b, data, endtime))
175                         return False;
176                 len = b;
177                 while (n > 1) {
178                         if (!read_one_uint8(sock, &b, data, endtime))
179                                 return False;
180                         len = (len<<8) | b;
181                         n--;
182                 }
183         } else {
184                 len = b;
185         }
186
187         buf = talloc_size(NULL, len);
188         if (buf == NULL)
189                 return False;
190
191         if (read_data_until(sock, buf, len, endtime) != len)
192                 return False;
193
194         if (!asn1_write(data, buf, len))
195                 return False;
196
197         talloc_free(buf);
198
199         data->ofs = 0;
200         
201         return True;
202 }
203
204
205
206 /****************************************************************************
207   create an outgoing socket. timeout is in milliseconds.
208   **************************************************************************/
209 static int open_socket_out(int type, struct ipv4_addr *addr, int port, int timeout)
210 {
211         struct sockaddr_in sock_out;
212         int res,ret;
213         int connect_loop = 250; /* 250 milliseconds */
214         int loops = (timeout) / connect_loop;
215
216         /* create a socket to write to */
217         res = socket(PF_INET, type, 0);
218         if (res == -1) 
219         { DEBUG(0,("socket error\n")); return -1; }
220         
221         if (type != SOCK_STREAM) return(res);
222         
223         memset((char *)&sock_out,'\0',sizeof(sock_out));
224         putip((char *)&sock_out.sin_addr,(char *)addr);
225         
226         sock_out.sin_port = htons( port );
227         sock_out.sin_family = PF_INET;
228         
229         /* set it non-blocking */
230         set_blocking(res,False);
231         
232         DEBUG(3,("Connecting to %s at port %d\n", sys_inet_ntoa(*addr),port));
233         
234         /* and connect it to the destination */
235 connect_again:
236         ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out));
237         
238         /* Some systems return EAGAIN when they mean EINPROGRESS */
239         if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
240                         errno == EAGAIN) && loops--) {
241                 msleep(connect_loop);
242                 goto connect_again;
243         }
244         
245         if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
246                         errno == EAGAIN)) {
247                 DEBUG(1,("timeout connecting to %s:%d\n", sys_inet_ntoa(*addr),port));
248                 close(res);
249                 return -1;
250         }
251         
252 #ifdef EISCONN
253         if (ret < 0 && errno == EISCONN) {
254                 errno = 0;
255                 ret = 0;
256         }
257 #endif
258         
259         if (ret < 0) {
260                 DEBUG(2,("error connecting to %s:%d (%s)\n",
261                          sys_inet_ntoa(*addr),port,strerror(errno)));
262                 close(res);
263                 return -1;
264         }
265         
266         /* set it blocking again */
267         set_blocking(res,True);
268         
269         return res;
270 }
271
272 #if 0
273 static struct ldap_message *new_ldap_search_message(struct ldap_connection *conn,
274                                              const char *base,
275                                              enum ldap_scope scope,
276                                              char *filter,
277                                              int num_attributes,
278                                              const char **attributes)
279 {
280         struct ldap_message *res;
281
282         res = new_ldap_message(conn);
283         if (!res) {
284                 return NULL;
285         }
286
287         res->type = LDAP_TAG_SearchRequest;
288         res->r.SearchRequest.basedn = base;
289         res->r.SearchRequest.scope = scope;
290         res->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
291         res->r.SearchRequest.timelimit = 0;
292         res->r.SearchRequest.sizelimit = 0;
293         res->r.SearchRequest.attributesonly = False;
294         res->r.SearchRequest.filter = filter;
295         res->r.SearchRequest.num_attributes = num_attributes;
296         res->r.SearchRequest.attributes = attributes;
297
298         return res;
299 }
300 #endif
301
302 static struct ldap_message *new_ldap_simple_bind_msg(struct ldap_connection *conn, const char *dn, const char *pw)
303 {
304         struct ldap_message *res;
305
306         res = new_ldap_message(conn);
307         if (!res) {
308                 return NULL;
309         }
310
311         res->type = LDAP_TAG_BindRequest;
312         res->r.BindRequest.version = 3;
313         res->r.BindRequest.dn = talloc_strdup(res->mem_ctx, dn);
314         res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SIMPLE;
315         res->r.BindRequest.creds.password = talloc_strdup(res->mem_ctx, pw);
316
317         return res;
318 }
319
320 static struct ldap_message *new_ldap_sasl_bind_msg(struct ldap_connection *conn, const char *sasl_mechanism, DATA_BLOB *secblob)
321 {
322         struct ldap_message *res;
323
324         res = new_ldap_message(conn);
325         if (!res) {
326                 return NULL;
327         }
328
329         res->type = LDAP_TAG_BindRequest;
330         res->r.BindRequest.version = 3;
331         res->r.BindRequest.dn = "";
332         res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SASL;
333         res->r.BindRequest.creds.SASL.mechanism = talloc_strdup(res->mem_ctx, sasl_mechanism);
334         res->r.BindRequest.creds.SASL.secblob = *secblob;
335
336         return res;
337 }
338
339 static struct ldap_connection *new_ldap_connection(TALLOC_CTX *mem_ctx)
340 {
341         struct ldap_connection *result;
342
343         result = talloc(mem_ctx, struct ldap_connection);
344
345         if (!result) {
346                 return NULL;
347         }
348
349         result->mem_ctx = result;
350         result->next_msgid = 1;
351         result->outstanding = NULL;
352         result->searchid = 0;
353         result->search_entries = NULL;
354         result->auth_dn = NULL;
355         result->simple_pw = NULL;
356         result->gensec = NULL;
357
358         return result;
359 }
360
361 struct ldap_connection *ldap_connect(TALLOC_CTX *mem_ctx, const char *url)
362 {
363         struct hostent *hp;
364         struct ipv4_addr ip;
365         struct ldap_connection *conn;
366         BOOL ret;
367
368         conn = new_ldap_connection(mem_ctx);
369         if (!conn) {
370                 return NULL;
371         }
372
373         ret = ldap_parse_basic_url(conn->mem_ctx, url, &conn->host,
374                                   &conn->port, &conn->ldaps);
375         if (!ret) {
376                 talloc_free(conn);
377                 return NULL;
378         }
379
380         hp = sys_gethostbyname(conn->host);
381         if (!hp || !hp->h_addr) {
382                 talloc_free(conn);
383                 return NULL;
384         }
385
386         putip((char *)&ip, (char *)hp->h_addr);
387
388         conn->sock = open_socket_out(SOCK_STREAM, &ip, conn->port, LDAP_CONNECTION_TIMEOUT);
389         if (conn->sock < 0) {
390                 talloc_free(conn);
391                 return NULL;
392         }
393
394         return conn;
395 }
396
397 struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx)
398 {
399         struct ldap_message *result;
400
401         result = talloc(mem_ctx, struct ldap_message);
402
403         if (!result) {
404                 return NULL;
405         }
406
407         result->mem_ctx = result;
408
409         return result;
410 }
411
412 BOOL ldap_send_msg(struct ldap_connection *conn, struct ldap_message *msg,
413                    const struct timeval *endtime)
414 {
415         DATA_BLOB request;
416         BOOL result;
417         struct ldap_queue_entry *entry;
418
419         msg->messageid = conn->next_msgid++;
420
421         if (!ldap_encode(msg, &request))
422                 return False;
423
424         result = (write_data_until(conn->sock, request.data, request.length,
425                                    endtime) == request.length);
426
427         data_blob_free(&request);
428
429         if (!result)
430                 return result;
431
432         /* abandon and unbind don't expect results */
433
434         if ((msg->type == LDAP_TAG_AbandonRequest) ||
435             (msg->type == LDAP_TAG_UnbindRequest))
436                 return True;
437
438         entry = malloc_p(struct ldap_queue_entry);
439
440         if (entry == NULL)
441                 return False;
442
443         entry->msgid = msg->messageid;
444         entry->msg = NULL;
445         DLIST_ADD(conn->outstanding, entry);
446
447         return True;
448 }
449
450 BOOL ldap_receive_msg(struct ldap_connection *conn, struct ldap_message *msg,
451                       const struct timeval *endtime)
452 {
453         struct asn1_data data;
454         BOOL result;
455
456         if (!asn1_read_sequence_until(conn->sock, &data, endtime))
457                 return False;
458
459         result = ldap_decode(&data, msg);
460
461         asn1_free(&data);
462         return result;
463 }
464
465 static struct ldap_message *recv_from_queue(struct ldap_connection *conn,
466                                             int msgid)
467 {
468         struct ldap_queue_entry *e;
469
470         for (e = conn->outstanding; e != NULL; e = e->next) {
471
472                 if (e->msgid == msgid) {
473                         struct ldap_message *result = e->msg;
474                         DLIST_REMOVE(conn->outstanding, e);
475                         SAFE_FREE(e);
476                         return result;
477                 }
478         }
479
480         return NULL;
481 }
482
483 static void add_search_entry(struct ldap_connection *conn,
484                              struct ldap_message *msg)
485 {
486         struct ldap_queue_entry *e = malloc_p(struct ldap_queue_entry);
487
488         if (e == NULL)
489                 return;
490
491         e->msg = msg;
492         DLIST_ADD_END(conn->search_entries, e, struct ldap_queue_entry *);
493         return;
494 }
495
496 static void fill_outstanding_request(struct ldap_connection *conn,
497                                      struct ldap_message *msg)
498 {
499         struct ldap_queue_entry *e;
500
501         for (e = conn->outstanding; e != NULL; e = e->next) {
502                 if (e->msgid == msg->messageid) {
503                         e->msg = msg;
504                         return;
505                 }
506         }
507
508         /* This reply has not been expected, destroy the incoming msg */
509         talloc_free(msg);
510         return;
511 }
512
513 struct ldap_message *ldap_receive(struct ldap_connection *conn, int msgid,
514                                   const struct timeval *endtime)
515 {
516         struct ldap_message *result = recv_from_queue(conn, msgid);
517
518         if (result != NULL)
519                 return result;
520
521         while (True) {
522                 struct asn1_data data;
523                 BOOL res;
524
525                 result = new_ldap_message(conn);
526
527                 if (!asn1_read_sequence_until(conn->sock, &data, endtime))
528                         return NULL;
529
530                 res = ldap_decode(&data, result);
531                 asn1_free(&data);
532
533                 if (!res)
534                         return NULL;
535
536                 if (result->messageid == msgid)
537                         return result;
538
539                 if (result->type == LDAP_TAG_SearchResultEntry) {
540                         add_search_entry(conn, result);
541                 } else {
542                         fill_outstanding_request(conn, result);
543                 }
544         }
545
546         return NULL;
547 }
548
549 struct ldap_message *ldap_transaction(struct ldap_connection *conn,
550                                       struct ldap_message *request)
551 {
552         if (!ldap_send_msg(conn, request, NULL))
553                 return False;
554
555         return ldap_receive(conn, request->messageid, NULL);
556 }
557
558 int ldap_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password)
559 {
560         struct ldap_message *response;
561         struct ldap_message *msg;
562         const char *dn, *pw;
563         int result = LDAP_OTHER;
564
565         if (conn == NULL)
566                 return result;
567
568         if (userdn) {
569                 dn = userdn;
570         } else {
571                 if (conn->auth_dn) {
572                         dn = conn->auth_dn;
573                 } else {
574                         dn = "";
575                 }
576         }
577
578         if (password) {
579                 pw = password;
580         } else {
581                 if (conn->simple_pw) {
582                         pw = conn->simple_pw;
583                 } else {
584                         pw = "";
585                 }
586         }
587
588         msg =  new_ldap_simple_bind_msg(conn, dn, pw);
589         if (!msg)
590                 return result;
591
592         response = ldap_transaction(conn, msg);
593         if (!response) {
594                 talloc_free(msg);
595                 return result;
596         }
597                 
598         result = response->r.BindResponse.response.resultcode;
599
600         talloc_free(msg);
601         talloc_free(response);
602
603         return result;
604 }
605
606 int ldap_bind_sasl(struct ldap_connection *conn, const char *username, const char *domain, const char *password)
607 {
608         NTSTATUS status;
609         TALLOC_CTX *mem_ctx = NULL;
610         struct ldap_message *response;
611         struct ldap_message *msg;
612         DATA_BLOB input = data_blob(NULL, 0);
613         DATA_BLOB output = data_blob(NULL, 0);
614         int result = LDAP_OTHER;
615
616         if (conn == NULL)
617                 return result;
618
619         status = gensec_client_start(conn, &conn->gensec);
620         if (!NT_STATUS_IS_OK(status)) {
621                 DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
622                 return result;
623         }
624
625         gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL);
626
627         status = gensec_set_domain(conn->gensec, domain);
628         if (!NT_STATUS_IS_OK(status)) {
629                 DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n", 
630                           domain, nt_errstr(status)));
631                 goto done;
632         }
633
634         status = gensec_set_username(conn->gensec, username);
635         if (!NT_STATUS_IS_OK(status)) {
636                 DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n", 
637                           username, nt_errstr(status)));
638                 goto done;
639         }
640
641         status = gensec_set_password(conn->gensec, password);
642         if (!NT_STATUS_IS_OK(status)) {
643                 DEBUG(1, ("Failed to start set GENSEC client password: %s\n", 
644                           nt_errstr(status)));
645                 goto done;
646         }
647
648         status = gensec_set_target_hostname(conn->gensec, conn->host);
649         if (!NT_STATUS_IS_OK(status)) {
650                 DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n", 
651                           nt_errstr(status)));
652                 goto done;
653         }
654
655         status = gensec_set_target_service(conn->gensec, "ldap");
656         if (!NT_STATUS_IS_OK(status)) {
657                 DEBUG(1, ("Failed to start set GENSEC target service: %s\n", 
658                           nt_errstr(status)));
659                 goto done;
660         }
661
662         status = gensec_start_mech_by_sasl_name(conn->gensec, "GSS-SPNEGO");
663         if (!NT_STATUS_IS_OK(status)) {
664                 DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",
665                           nt_errstr(status)));
666                 goto done;
667         }
668
669         mem_ctx = talloc_init("ldap_bind_sasl");
670         if (!mem_ctx)
671                 goto done;
672
673         status = gensec_update(conn->gensec, mem_ctx,
674                                input,
675                                &output);
676
677         while(1) {
678                 if (NT_STATUS_IS_OK(status) && output.length == 0) {
679                         break;
680                 }
681                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
682                         break;
683                 }
684
685                 msg =  new_ldap_sasl_bind_msg(conn, "GSS-SPNEGO", &output);
686                 if (!msg)
687                         goto done;
688
689                 response = ldap_transaction(conn, msg);
690                 talloc_free(msg);
691
692                 if (!response) {
693                         goto done;
694                 }
695
696                 result = response->r.BindResponse.response.resultcode;
697
698                 if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
699                         break;
700                 }
701
702                 if (!NT_STATUS_IS_OK(status)) {
703                         status = gensec_update(conn->gensec, mem_ctx,
704                                                response->r.BindResponse.SASL.secblob,
705                                                &output);
706                 } else {
707                         output.length = 0;
708                 }
709
710                 talloc_free(response);
711         }
712
713 done:
714         if (mem_ctx)
715                 talloc_free(mem_ctx);
716
717         return result;
718 }
719
720 struct ldap_connection *ldap_setup_connection(TALLOC_CTX *mem_ctx, const char *url, 
721                                                 const char *userdn, const char *password)
722 {
723         struct ldap_connection *conn;
724         int result;
725
726         conn =ldap_connect(mem_ctx, url);
727         if (!conn) {
728                 return NULL;
729         }
730
731         result = ldap_bind_simple(conn, userdn, password);
732         if (result != LDAP_SUCCESS) {
733                 talloc_free(conn);
734                 return NULL;
735         }
736
737         return conn;
738 }
739
740 struct ldap_connection *ldap_setup_connection_with_sasl(TALLOC_CTX *mem_ctx, const char *url,
741                                                         const char *username, const char *domain, const char *password)
742 {
743         struct ldap_connection *conn;
744         int result;
745
746         conn =ldap_connect(mem_ctx, url);
747         if (!conn) {
748                 return NULL;
749         }
750
751         result = ldap_bind_sasl(conn, username, domain, password);
752         if (result != LDAP_SUCCESS) {
753                 talloc_free(conn);
754                 return NULL;
755         }
756
757         return conn;
758 }
759
760 BOOL ldap_abandon_message(struct ldap_connection *conn, int msgid,
761                                  const struct timeval *endtime)
762 {
763         struct ldap_message *msg = new_ldap_message(conn);
764         BOOL result;
765
766         if (msg == NULL)
767                 return False;
768
769         msg->type = LDAP_TAG_AbandonRequest;
770         msg->r.AbandonRequest.messageid = msgid;
771
772         result = ldap_send_msg(conn, msg, endtime);
773         talloc_free(msg);
774         return result;
775 }
776
777 BOOL ldap_setsearchent(struct ldap_connection *conn, struct ldap_message *msg,
778                        const struct timeval *endtime)
779 {
780         if ((conn->searchid != 0) &&
781             (!ldap_abandon_message(conn, conn->searchid, endtime)))
782                 return False;
783
784         conn->searchid = conn->next_msgid;
785         return ldap_send_msg(conn, msg, endtime);
786 }
787
788 struct ldap_message *ldap_getsearchent(struct ldap_connection *conn,
789                                        const struct timeval *endtime)
790 {
791         struct ldap_message *result;
792
793         if (conn->search_entries != NULL) {
794                 struct ldap_queue_entry *e = conn->search_entries;
795
796                 result = e->msg;
797                 DLIST_REMOVE(conn->search_entries, e);
798                 SAFE_FREE(e);
799                 return result;
800         }
801
802         result = ldap_receive(conn, conn->searchid, endtime);
803         if (!result) {
804                 return NULL;
805         }
806
807         if (result->type == LDAP_TAG_SearchResultEntry)
808                 return result;
809
810         if (result->type == LDAP_TAG_SearchResultDone) {
811                 /* TODO: Handle Paged Results */
812                 talloc_free(result);
813                 return NULL;
814         }
815
816         /* TODO: Handle Search References here */
817         return NULL;
818 }
819
820 void ldap_endsearchent(struct ldap_connection *conn,
821                        const struct timeval *endtime)
822 {
823         struct ldap_queue_entry *e;
824
825         e = conn->search_entries;
826
827         while (e != NULL) {
828                 struct ldap_queue_entry *next = e->next;
829                 DLIST_REMOVE(conn->search_entries, e);
830                 SAFE_FREE(e);
831                 e = next;
832         }
833 }
834
835 struct ldap_message *ldap_searchone(struct ldap_connection *conn,
836                                     struct ldap_message *msg,
837                                     const struct timeval *endtime)
838 {
839         struct ldap_message *res1, *res2 = NULL;
840         if (!ldap_setsearchent(conn, msg, endtime))
841                 return NULL;
842
843         res1 = ldap_getsearchent(conn, endtime);
844
845         if (res1 != NULL)
846                 res2 = ldap_getsearchent(conn, endtime);
847
848         ldap_endsearchent(conn, endtime);
849
850         if (res1 == NULL)
851                 return NULL;
852
853         if (res2 != NULL) {
854                 /* More than one entry */
855                 talloc_free(res1);
856                 talloc_free(res2);
857                 return NULL;
858         }
859
860         return res1;
861 }
862
863 BOOL ldap_find_single_value(struct ldap_message *msg, const char *attr,
864                             DATA_BLOB *value)
865 {
866         int i;
867         struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
868
869         if (msg->type != LDAP_TAG_SearchResultEntry)
870                 return False;
871
872         for (i=0; i<r->num_attributes; i++) {
873                 if (strequal(attr, r->attributes[i].name)) {
874                         if (r->attributes[i].num_values != 1)
875                                 return False;
876
877                         *value = r->attributes[i].values[0];
878                         return True;
879                 }
880         }
881         return False;
882 }
883
884 BOOL ldap_find_single_string(struct ldap_message *msg, const char *attr,
885                              TALLOC_CTX *mem_ctx, char **value)
886 {
887         DATA_BLOB blob;
888
889         if (!ldap_find_single_value(msg, attr, &blob))
890                 return False;
891
892         *value = talloc_size(mem_ctx, blob.length+1);
893
894         if (*value == NULL)
895                 return False;
896
897         memcpy(*value, blob.data, blob.length);
898         (*value)[blob.length] = '\0';
899         return True;
900 }
901
902 BOOL ldap_find_single_int(struct ldap_message *msg, const char *attr,
903                           int *value)
904 {
905         DATA_BLOB blob;
906         char *val;
907         int errno_save;
908         BOOL res;
909
910         if (!ldap_find_single_value(msg, attr, &blob))
911                 return False;
912
913         val = malloc(blob.length+1);
914         if (val == NULL)
915                 return False;
916
917         memcpy(val, blob.data, blob.length);
918         val[blob.length] = '\0';
919
920         errno_save = errno;
921         errno = 0;
922
923         *value = strtol(val, NULL, 10);
924
925         res = (errno == 0);
926
927         free(val);
928         errno = errno_save;
929
930         return res;
931 }
932
933 int ldap_error(struct ldap_connection *conn)
934 {
935         return 0;
936 }
937
938 NTSTATUS ldap2nterror(int ldaperror)
939 {
940         return NT_STATUS_OK;
941 }