r6028: A MAJOR update to intergrate the new credentails system fully with
[bbaumbach/samba-autobuild/.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->mem_ctx, dn);
316         res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SIMPLE;
317         res->r.BindRequest.creds.password = talloc_strdup(res->mem_ctx, 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->mem_ctx, 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->mem_ctx = result;
352         result->next_msgid = 1;
353         result->outstanding = NULL;
354         result->searchid = 0;
355         result->search_entries = NULL;
356         result->auth_dn = NULL;
357         result->simple_pw = NULL;
358         result->gensec = NULL;
359
360         return result;
361 }
362
363 struct ldap_connection *ldap_connect(TALLOC_CTX *mem_ctx, const char *url)
364 {
365         struct hostent *hp;
366         struct ipv4_addr ip;
367         struct ldap_connection *conn;
368         BOOL ret;
369
370         conn = new_ldap_connection(mem_ctx);
371         if (!conn) {
372                 return NULL;
373         }
374
375         ret = ldap_parse_basic_url(conn->mem_ctx, url, &conn->host,
376                                   &conn->port, &conn->ldaps);
377         if (!ret) {
378                 talloc_free(conn);
379                 return NULL;
380         }
381
382         hp = sys_gethostbyname(conn->host);
383         if (!hp || !hp->h_addr) {
384                 talloc_free(conn);
385                 return NULL;
386         }
387
388         memcpy((char *)&ip, (char *)hp->h_addr, 4);
389
390         conn->sock = open_socket_out(SOCK_STREAM, &ip, conn->port, LDAP_CONNECTION_TIMEOUT);
391         if (conn->sock < 0) {
392                 talloc_free(conn);
393                 return NULL;
394         }
395
396         return conn;
397 }
398
399 struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx)
400 {
401         struct ldap_message *result;
402
403         result = talloc(mem_ctx, struct ldap_message);
404
405         if (!result) {
406                 return NULL;
407         }
408
409         result->mem_ctx = result;
410
411         return result;
412 }
413
414 BOOL ldap_send_msg(struct ldap_connection *conn, struct ldap_message *msg,
415                    const struct timeval *endtime)
416 {
417         DATA_BLOB request;
418         BOOL result;
419         struct ldap_queue_entry *entry;
420
421         msg->messageid = conn->next_msgid++;
422
423         if (!ldap_encode(msg, &request))
424                 return False;
425
426         result = (write_data_until(conn->sock, request.data, request.length,
427                                    endtime) == request.length);
428
429         data_blob_free(&request);
430
431         if (!result)
432                 return result;
433
434         /* abandon and unbind don't expect results */
435
436         if ((msg->type == LDAP_TAG_AbandonRequest) ||
437             (msg->type == LDAP_TAG_UnbindRequest))
438                 return True;
439
440         entry = malloc_p(struct ldap_queue_entry);
441
442         if (entry == NULL)
443                 return False;
444
445         entry->msgid = msg->messageid;
446         entry->msg = NULL;
447         DLIST_ADD(conn->outstanding, entry);
448
449         return True;
450 }
451
452 BOOL ldap_receive_msg(struct ldap_connection *conn, struct ldap_message *msg,
453                       const struct timeval *endtime)
454 {
455         struct asn1_data data;
456         BOOL result;
457
458         if (!asn1_read_sequence_until(conn->sock, &data, endtime))
459                 return False;
460
461         result = ldap_decode(&data, msg);
462
463         asn1_free(&data);
464         return result;
465 }
466
467 static struct ldap_message *recv_from_queue(struct ldap_connection *conn,
468                                             int msgid)
469 {
470         struct ldap_queue_entry *e;
471
472         for (e = conn->outstanding; e != NULL; e = e->next) {
473
474                 if (e->msgid == msgid) {
475                         struct ldap_message *result = e->msg;
476                         DLIST_REMOVE(conn->outstanding, e);
477                         SAFE_FREE(e);
478                         return result;
479                 }
480         }
481
482         return NULL;
483 }
484
485 static void add_search_entry(struct ldap_connection *conn,
486                              struct ldap_message *msg)
487 {
488         struct ldap_queue_entry *e = malloc_p(struct ldap_queue_entry);
489
490         if (e == NULL)
491                 return;
492
493         e->msg = msg;
494         DLIST_ADD_END(conn->search_entries, e, struct ldap_queue_entry *);
495         return;
496 }
497
498 static void fill_outstanding_request(struct ldap_connection *conn,
499                                      struct ldap_message *msg)
500 {
501         struct ldap_queue_entry *e;
502
503         for (e = conn->outstanding; e != NULL; e = e->next) {
504                 if (e->msgid == msg->messageid) {
505                         e->msg = msg;
506                         return;
507                 }
508         }
509
510         /* This reply has not been expected, destroy the incoming msg */
511         talloc_free(msg);
512         return;
513 }
514
515 struct ldap_message *ldap_receive(struct ldap_connection *conn, int msgid,
516                                   const struct timeval *endtime)
517 {
518         struct ldap_message *result = recv_from_queue(conn, msgid);
519
520         if (result != NULL)
521                 return result;
522
523         while (True) {
524                 struct asn1_data data;
525                 BOOL res;
526
527                 result = new_ldap_message(conn);
528
529                 if (!asn1_read_sequence_until(conn->sock, &data, endtime))
530                         return NULL;
531
532                 res = ldap_decode(&data, result);
533                 asn1_free(&data);
534
535                 if (!res)
536                         return NULL;
537
538                 if (result->messageid == msgid)
539                         return result;
540
541                 if (result->type == LDAP_TAG_SearchResultEntry) {
542                         add_search_entry(conn, result);
543                 } else {
544                         fill_outstanding_request(conn, result);
545                 }
546         }
547
548         return NULL;
549 }
550
551 struct ldap_message *ldap_transaction(struct ldap_connection *conn,
552                                       struct ldap_message *request)
553 {
554         if (!ldap_send_msg(conn, request, NULL))
555                 return False;
556
557         return ldap_receive(conn, request->messageid, NULL);
558 }
559
560 int ldap_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password)
561 {
562         struct ldap_message *response;
563         struct ldap_message *msg;
564         const char *dn, *pw;
565         int result = LDAP_OTHER;
566
567         if (conn == NULL)
568                 return result;
569
570         if (userdn) {
571                 dn = userdn;
572         } else {
573                 if (conn->auth_dn) {
574                         dn = conn->auth_dn;
575                 } else {
576                         dn = "";
577                 }
578         }
579
580         if (password) {
581                 pw = password;
582         } else {
583                 if (conn->simple_pw) {
584                         pw = conn->simple_pw;
585                 } else {
586                         pw = "";
587                 }
588         }
589
590         msg =  new_ldap_simple_bind_msg(conn, dn, pw);
591         if (!msg)
592                 return result;
593
594         response = ldap_transaction(conn, msg);
595         if (!response) {
596                 talloc_free(msg);
597                 return result;
598         }
599                 
600         result = response->r.BindResponse.response.resultcode;
601
602         talloc_free(msg);
603         talloc_free(response);
604
605         return result;
606 }
607
608 int ldap_bind_sasl(struct ldap_connection *conn, struct cli_credentials *creds)
609 {
610         NTSTATUS status;
611         TALLOC_CTX *mem_ctx = NULL;
612         struct ldap_message *response;
613         struct ldap_message *msg;
614         DATA_BLOB input = data_blob(NULL, 0);
615         DATA_BLOB output = data_blob(NULL, 0);
616         int result = LDAP_OTHER;
617
618         if (conn == NULL)
619                 return result;
620
621         status = gensec_client_start(conn, &conn->gensec);
622         if (!NT_STATUS_IS_OK(status)) {
623                 DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
624                 return result;
625         }
626
627         gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL);
628
629         status = gensec_set_credentials(conn->gensec, creds);
630         if (!NT_STATUS_IS_OK(status)) {
631                 DEBUG(1, ("Failed to start set GENSEC creds: %s\n", 
632                           nt_errstr(status)));
633                 goto done;
634         }
635
636         status = gensec_set_target_hostname(conn->gensec, conn->host);
637         if (!NT_STATUS_IS_OK(status)) {
638                 DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n", 
639                           nt_errstr(status)));
640                 goto done;
641         }
642
643         status = gensec_set_target_service(conn->gensec, "ldap");
644         if (!NT_STATUS_IS_OK(status)) {
645                 DEBUG(1, ("Failed to start set GENSEC target service: %s\n", 
646                           nt_errstr(status)));
647                 goto done;
648         }
649
650         status = gensec_start_mech_by_sasl_name(conn->gensec, "GSS-SPNEGO");
651         if (!NT_STATUS_IS_OK(status)) {
652                 DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",
653                           nt_errstr(status)));
654                 goto done;
655         }
656
657         mem_ctx = talloc_init("ldap_bind_sasl");
658         if (!mem_ctx)
659                 goto done;
660
661         status = gensec_update(conn->gensec, mem_ctx,
662                                input,
663                                &output);
664
665         while(1) {
666                 if (NT_STATUS_IS_OK(status) && output.length == 0) {
667                         break;
668                 }
669                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
670                         break;
671                 }
672
673                 msg =  new_ldap_sasl_bind_msg(conn, "GSS-SPNEGO", &output);
674                 if (!msg)
675                         goto done;
676
677                 response = ldap_transaction(conn, msg);
678                 talloc_free(msg);
679
680                 if (!response) {
681                         goto done;
682                 }
683
684                 result = response->r.BindResponse.response.resultcode;
685
686                 if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
687                         break;
688                 }
689
690                 if (!NT_STATUS_IS_OK(status)) {
691                         status = gensec_update(conn->gensec, mem_ctx,
692                                                response->r.BindResponse.SASL.secblob,
693                                                &output);
694                 } else {
695                         output.length = 0;
696                 }
697
698                 talloc_free(response);
699         }
700
701 done:
702         if (mem_ctx)
703                 talloc_free(mem_ctx);
704
705         return result;
706 }
707
708 struct ldap_connection *ldap_setup_connection(TALLOC_CTX *mem_ctx, const char *url, 
709                                                 const char *userdn, const char *password)
710 {
711         struct ldap_connection *conn;
712         int result;
713
714         conn =ldap_connect(mem_ctx, url);
715         if (!conn) {
716                 return NULL;
717         }
718
719         result = ldap_bind_simple(conn, userdn, password);
720         if (result != LDAP_SUCCESS) {
721                 talloc_free(conn);
722                 return NULL;
723         }
724
725         return conn;
726 }
727
728 struct ldap_connection *ldap_setup_connection_with_sasl(TALLOC_CTX *mem_ctx, 
729                                                         const char *url,
730                                                         struct cli_credentials *creds)
731 {
732         struct ldap_connection *conn;
733         int result;
734
735         conn =ldap_connect(mem_ctx, url);
736         if (!conn) {
737                 return NULL;
738         }
739
740         result = ldap_bind_sasl(conn, creds);
741         if (result != LDAP_SUCCESS) {
742                 talloc_free(conn);
743                 return NULL;
744         }
745
746         return conn;
747 }
748
749 BOOL ldap_abandon_message(struct ldap_connection *conn, int msgid,
750                                  const struct timeval *endtime)
751 {
752         struct ldap_message *msg = new_ldap_message(conn);
753         BOOL result;
754
755         if (msg == NULL)
756                 return False;
757
758         msg->type = LDAP_TAG_AbandonRequest;
759         msg->r.AbandonRequest.messageid = msgid;
760
761         result = ldap_send_msg(conn, msg, endtime);
762         talloc_free(msg);
763         return result;
764 }
765
766 BOOL ldap_setsearchent(struct ldap_connection *conn, struct ldap_message *msg,
767                        const struct timeval *endtime)
768 {
769         if ((conn->searchid != 0) &&
770             (!ldap_abandon_message(conn, conn->searchid, endtime)))
771                 return False;
772
773         conn->searchid = conn->next_msgid;
774         return ldap_send_msg(conn, msg, endtime);
775 }
776
777 struct ldap_message *ldap_getsearchent(struct ldap_connection *conn,
778                                        const struct timeval *endtime)
779 {
780         struct ldap_message *result;
781
782         if (conn->search_entries != NULL) {
783                 struct ldap_queue_entry *e = conn->search_entries;
784
785                 result = e->msg;
786                 DLIST_REMOVE(conn->search_entries, e);
787                 SAFE_FREE(e);
788                 return result;
789         }
790
791         result = ldap_receive(conn, conn->searchid, endtime);
792         if (!result) {
793                 return NULL;
794         }
795
796         if (result->type == LDAP_TAG_SearchResultEntry)
797                 return result;
798
799         if (result->type == LDAP_TAG_SearchResultDone) {
800                 /* TODO: Handle Paged Results */
801                 talloc_free(result);
802                 return NULL;
803         }
804
805         /* TODO: Handle Search References here */
806         return NULL;
807 }
808
809 void ldap_endsearchent(struct ldap_connection *conn,
810                        const struct timeval *endtime)
811 {
812         struct ldap_queue_entry *e;
813
814         e = conn->search_entries;
815
816         while (e != NULL) {
817                 struct ldap_queue_entry *next = e->next;
818                 DLIST_REMOVE(conn->search_entries, e);
819                 SAFE_FREE(e);
820                 e = next;
821         }
822 }
823
824 struct ldap_message *ldap_searchone(struct ldap_connection *conn,
825                                     struct ldap_message *msg,
826                                     const struct timeval *endtime)
827 {
828         struct ldap_message *res1, *res2 = NULL;
829         if (!ldap_setsearchent(conn, msg, endtime))
830                 return NULL;
831
832         res1 = ldap_getsearchent(conn, endtime);
833
834         if (res1 != NULL)
835                 res2 = ldap_getsearchent(conn, endtime);
836
837         ldap_endsearchent(conn, endtime);
838
839         if (res1 == NULL)
840                 return NULL;
841
842         if (res2 != NULL) {
843                 /* More than one entry */
844                 talloc_free(res1);
845                 talloc_free(res2);
846                 return NULL;
847         }
848
849         return res1;
850 }
851
852 BOOL ldap_find_single_value(struct ldap_message *msg, const char *attr,
853                             DATA_BLOB *value)
854 {
855         int i;
856         struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
857
858         if (msg->type != LDAP_TAG_SearchResultEntry)
859                 return False;
860
861         for (i=0; i<r->num_attributes; i++) {
862                 if (strequal(attr, r->attributes[i].name)) {
863                         if (r->attributes[i].num_values != 1)
864                                 return False;
865
866                         *value = r->attributes[i].values[0];
867                         return True;
868                 }
869         }
870         return False;
871 }
872
873 BOOL ldap_find_single_string(struct ldap_message *msg, const char *attr,
874                              TALLOC_CTX *mem_ctx, char **value)
875 {
876         DATA_BLOB blob;
877
878         if (!ldap_find_single_value(msg, attr, &blob))
879                 return False;
880
881         *value = talloc_size(mem_ctx, blob.length+1);
882
883         if (*value == NULL)
884                 return False;
885
886         memcpy(*value, blob.data, blob.length);
887         (*value)[blob.length] = '\0';
888         return True;
889 }
890
891 BOOL ldap_find_single_int(struct ldap_message *msg, const char *attr,
892                           int *value)
893 {
894         DATA_BLOB blob;
895         char *val;
896         int errno_save;
897         BOOL res;
898
899         if (!ldap_find_single_value(msg, attr, &blob))
900                 return False;
901
902         val = malloc(blob.length+1);
903         if (val == NULL)
904                 return False;
905
906         memcpy(val, blob.data, blob.length);
907         val[blob.length] = '\0';
908
909         errno_save = errno;
910         errno = 0;
911
912         *value = strtol(val, NULL, 10);
913
914         res = (errno == 0);
915
916         free(val);
917         errno = errno_save;
918
919         return res;
920 }
921
922 int ldap_error(struct ldap_connection *conn)
923 {
924         return 0;
925 }
926
927 NTSTATUS ldap2nterror(int ldaperror)
928 {
929         return NT_STATUS_OK;
930 }