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