r7665: - added a ildap_*() interface to our internal ldap library. This
[kai/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 "asn_1.h"
28 #include "dlinklist.h"
29 #include "lib/events/events.h"
30 #include "lib/socket/socket.h"
31 #include "libcli/ldap/ldap.h"
32 #include "libcli/ldap/ldap_client.h"
33
34
35 /*
36   create a new ldap_connection stucture. The event context is optional
37 */
38 struct ldap_connection *ldap_new_connection(TALLOC_CTX *mem_ctx, 
39                                             struct event_context *ev)
40 {
41         struct ldap_connection *conn;
42
43         conn = talloc_zero(mem_ctx, struct ldap_connection);
44         if (conn == NULL) {
45                 return NULL;
46         }
47
48         if (ev == NULL) {
49                 ev = event_context_init(conn);
50                 if (ev == NULL) {
51                         talloc_free(conn);
52                         return NULL;
53                 }
54         }
55
56         conn->next_messageid  = 1;
57         conn->event.event_ctx = ev;
58
59         /* set a reasonable request timeout */
60         conn->timeout = 60;
61
62         return conn;
63 }
64
65
66 /*
67   the connection is dead
68 */
69 static void ldap_connection_dead(struct ldap_connection *conn)
70 {
71         struct ldap_request *req;
72
73         while (conn->pending) {
74                 req = conn->pending;
75                 DLIST_REMOVE(req->conn->pending, req);
76                 req->state = LDAP_REQUEST_DONE;
77                 req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
78                 if (req->async.fn) {
79                         req->async.fn(req);
80                 }
81         }       
82
83         while (conn->send_queue) {
84                 req = conn->send_queue;
85                 DLIST_REMOVE(req->conn->send_queue, req);
86                 req->state = LDAP_REQUEST_DONE;
87                 req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
88                 if (req->async.fn) {
89                         req->async.fn(req);
90                 }
91         }
92
93         talloc_free(conn->sock);
94         conn->sock = NULL;
95 }
96
97
98 /*
99   match up with a pending message, adding to the replies list
100 */
101 static void ldap_match_message(struct ldap_connection *conn, struct ldap_message *msg)
102 {
103         struct ldap_request *req;
104
105         for (req=conn->pending; req; req=req->next) {
106                 if (req->messageid == msg->messageid) break;
107         }
108         if (req == NULL) {
109                 DEBUG(0,("ldap: no matching message id for %u\n",
110                          msg->messageid));
111                 talloc_free(msg);
112                 return;
113         }
114
115         /* add to the list of replies received */
116         talloc_steal(req, msg);
117         req->replies = talloc_realloc(req, req->replies, 
118                                       struct ldap_message *, req->num_replies+1);
119         if (req->replies == NULL) {
120                 req->status = NT_STATUS_NO_MEMORY;
121                 req->state = LDAP_REQUEST_DONE;
122                 DLIST_REMOVE(conn->pending, req);
123                 if (req->async.fn) {
124                         req->async.fn(req);
125                 }
126                 return;
127         }
128
129         req->replies[req->num_replies] = talloc_steal(req->replies, msg);
130         req->num_replies++;
131
132         if (msg->type != LDAP_TAG_SearchResultEntry) {
133                 /* currently only search results expect multiple
134                    replies */
135                 req->state = LDAP_REQUEST_DONE;
136                 DLIST_REMOVE(conn->pending, req);
137         }
138
139         if (req->async.fn) {
140                 req->async.fn(req);
141         }
142 }
143
144 /*
145   try and decode/process plain data
146 */
147 static void ldap_try_decode_plain(struct ldap_connection *conn)
148 {
149         struct asn1_data asn1;
150
151         if (!asn1_load(&asn1, conn->partial)) {
152                 ldap_connection_dead(conn);
153                 return;
154         }
155
156         /* try and decode - this will fail if we don't have a full packet yet */
157         while (asn1.ofs < asn1.length) {
158                 struct ldap_message *msg = talloc(conn, struct ldap_message);
159                 if (msg == NULL) {
160                         ldap_connection_dead(conn);
161                         return;
162                 }
163
164                 if (ldap_decode(&asn1, msg)) {
165                         ldap_match_message(conn, msg);
166                 } else {
167                         talloc_free(msg);
168                         break;
169                 }
170         }
171
172         /* keep any remaining data in conn->partial */
173         data_blob_free(&conn->partial);
174         if (asn1.ofs != conn->partial.length) {
175                 conn->partial = data_blob_talloc(conn, 
176                                                  asn1.data + asn1.ofs, 
177                                                  asn1.length - asn1.ofs);
178         }
179         asn1_free(&asn1);
180 }
181
182 /*
183   try and decode/process wrapped data
184 */
185 static void ldap_try_decode_wrapped(struct ldap_connection *conn)
186 {
187         uint32_t len;
188
189         /* keep decoding while we have a full wrapped packet */
190         while (conn->partial.length >= 4 &&
191                (len=RIVAL(conn->partial.data, 0)) <= conn->partial.length-4) {
192                 DATA_BLOB wrapped, unwrapped;
193                 struct asn1_data asn1;
194                 struct ldap_message *msg = talloc(conn, struct ldap_message);
195                 NTSTATUS status;
196
197                 if (msg == NULL) {
198                         ldap_connection_dead(conn);
199                         return;
200                 }
201
202                 wrapped.data   = conn->partial.data+4;
203                 wrapped.length = len;
204
205                 status = gensec_unwrap(conn->gensec, msg, &wrapped, &unwrapped);
206                 if (!NT_STATUS_IS_OK(status)) {
207                         ldap_connection_dead(conn);
208                         return;
209                 }
210
211                 if (!asn1_load(&asn1, unwrapped)) {
212                         ldap_connection_dead(conn);
213                         return;
214                 }
215
216                 if (ldap_decode(&asn1, msg)) {
217                         ldap_match_message(conn, msg);
218                 } else {
219                         talloc_free(msg);
220                 }
221                 
222                 asn1_free(&asn1);
223
224                 if (conn->partial.length == len + 4) {
225                         data_blob_free(&conn->partial);
226                 } else {
227                         memmove(conn->partial.data, conn->partial.data+len+4,
228                                 conn->partial.length - (len+4));
229                         conn->partial.length -= len + 4;
230                 }
231         }
232 }
233
234
235 /*
236   handle ldap recv events
237 */
238 static void ldap_recv_handler(struct ldap_connection *conn)
239 {
240         NTSTATUS status;
241         size_t npending=0, nread;
242
243         /* work out how much data is pending */
244         status = socket_pending(conn->sock, &npending);
245         if (!NT_STATUS_IS_OK(status) || npending == 0) {
246                 DEBUG(0,("ldap_recv_handler - pending=%d - %s\n", 
247                          (int)npending, nt_errstr(status)));
248                 return;
249         }
250
251         conn->partial.data = talloc_realloc_size(conn, conn->partial.data, 
252                                                  conn->partial.length + npending);
253         if (conn->partial.data == NULL) {
254                 ldap_connection_dead(conn);
255                 return;
256         }
257
258         /* receive the pending data */
259         status = socket_recv(conn->sock, conn->partial.data + conn->partial.length,
260                              npending, &nread, 0);
261         if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
262                 return;
263         }
264         if (!NT_STATUS_IS_OK(status)) {
265                 ldap_connection_dead(conn);
266                 return;
267         }
268         conn->partial.length += nread;
269
270         /* see if we can decode what we have */
271         if (conn->enable_wrap) {
272                 ldap_try_decode_wrapped(conn);
273         } else {
274                 ldap_try_decode_plain(conn);
275         }
276 }
277
278
279 /*
280   handle ldap send events
281 */
282 static void ldap_send_handler(struct ldap_connection *conn)
283 {
284         while (conn->send_queue) {
285                 struct ldap_request *req = conn->send_queue;
286                 size_t nsent;
287                 NTSTATUS status;
288
289                 status = socket_send(conn->sock, &req->data, &nsent, 0);
290                 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
291                         break;
292                 }
293                 if (!NT_STATUS_IS_OK(status)) {
294                         ldap_connection_dead(conn);
295                         return;
296                 }
297
298                 req->data.data += nsent;
299                 req->data.length -= nsent;
300                 if (req->data.length == 0) {
301                         req->state = LDAP_REQUEST_PENDING;
302                         DLIST_REMOVE(conn->send_queue, req);
303
304                         /* some types of requests don't expect a reply */
305                         if (req->type == LDAP_TAG_AbandonRequest ||
306                             req->type == LDAP_TAG_UnbindRequest) {
307                                 req->status = NT_STATUS_OK;
308                                 req->state = LDAP_REQUEST_DONE;
309                                 if (req->async.fn) {
310                                         req->async.fn(req);
311                                 }
312                         } else {
313                                 DLIST_ADD(conn->pending, req);
314                         }
315                 }
316         }
317         if (conn->send_queue == NULL) {
318                 EVENT_FD_NOT_WRITEABLE(conn->event.fde);
319         }
320 }
321
322
323 /*
324   handle ldap socket events
325 */
326 static void ldap_io_handler(struct event_context *ev, struct fd_event *fde, 
327                             uint16_t flags, void *private)
328 {
329         struct ldap_connection *conn = talloc_get_type(private, struct ldap_connection);
330         if (flags & EVENT_FD_WRITE) {
331                 ldap_send_handler(conn);
332                 if (conn->sock == NULL) return;
333         }
334         if (flags & EVENT_FD_READ) {
335                 ldap_recv_handler(conn);
336         }
337 }
338
339 /*
340   parse a ldap URL
341 */
342 static NTSTATUS ldap_parse_basic_url(TALLOC_CTX *mem_ctx, const char *url,
343                                      char **host, uint16_t *port, BOOL *ldaps)
344 {
345         int tmp_port = 0;
346         char protocol[11];
347         char tmp_host[255];
348         const char *p = url;
349         int ret;
350
351         /* skip leading "URL:" (if any) */
352         if (strncasecmp(p, "URL:", 4) == 0) {
353                 p += 4;
354         }
355
356         /* Paranoia check */
357         SMB_ASSERT(sizeof(protocol)>10 && sizeof(tmp_host)>254);
358                 
359         ret = sscanf(p, "%10[^:]://%254[^:/]:%d", protocol, tmp_host, &tmp_port);
360         if (ret < 2) {
361                 return NT_STATUS_INVALID_PARAMETER;
362         }
363
364         if (strequal(protocol, "ldap")) {
365                 *port = 389;
366                 *ldaps = False;
367         } else if (strequal(protocol, "ldaps")) {
368                 *port = 636;
369                 *ldaps = True;
370         } else {
371                 DEBUG(0, ("unrecognised ldap protocol (%s)!\n", protocol));
372                 return NT_STATUS_PROTOCOL_UNREACHABLE;
373         }
374
375         if (tmp_port != 0)
376                 *port = tmp_port;
377
378         *host = talloc_strdup(mem_ctx, tmp_host);
379         NT_STATUS_HAVE_NO_MEMORY(*host);
380
381         return NT_STATUS_OK;
382 }
383
384 /*
385   connect to a ldap server
386 */
387 NTSTATUS ldap_connect(struct ldap_connection *conn, const char *url)
388 {
389         NTSTATUS status;
390
391         status = ldap_parse_basic_url(conn, url, &conn->host,
392                                       &conn->port, &conn->ldaps);
393         NT_STATUS_NOT_OK_RETURN(status);
394
395         status = socket_create("ipv4", SOCKET_TYPE_STREAM, &conn->sock, 0);
396         NT_STATUS_NOT_OK_RETURN(status);
397
398         talloc_steal(conn, conn->sock);
399
400         /* connect in a event friendly way */
401         status = socket_connect_ev(conn->sock, NULL, 0, conn->host, conn->port, 0, 
402                                    conn->event.event_ctx);
403         if (!NT_STATUS_IS_OK(status)) {
404                 talloc_free(conn->sock);
405                 return status;
406         }
407
408         /* setup a handler for events on this socket */
409         conn->event.fde = event_add_fd(conn->event.event_ctx, conn->sock, 
410                                        socket_get_fd(conn->sock), 
411                                        EVENT_FD_READ, ldap_io_handler, conn);
412         if (conn->event.fde == NULL) {
413                 talloc_free(conn->sock);
414                 return NT_STATUS_INTERNAL_ERROR;
415         }
416
417         return NT_STATUS_OK;
418 }
419
420 /* destroy an open ldap request */
421 static int ldap_request_destructor(void *ptr)
422 {
423         struct ldap_request *req = talloc_get_type(ptr, struct ldap_request);
424         if (req->state == LDAP_REQUEST_SEND) {
425                 DLIST_REMOVE(req->conn->send_queue, req);
426         }
427         if (req->state == LDAP_REQUEST_PENDING) {
428                 DLIST_REMOVE(req->conn->pending, req);
429         }
430         return 0;
431 }
432
433 /*
434   called on timeout of a ldap request
435 */
436 static void ldap_request_timeout(struct event_context *ev, struct timed_event *te, 
437                                       struct timeval t, void *private)
438 {
439         struct ldap_request *req = talloc_get_type(private, struct ldap_request);
440         req->status = NT_STATUS_IO_TIMEOUT;
441         if (req->state == LDAP_REQUEST_SEND) {
442                 DLIST_REMOVE(req->conn->send_queue, req);
443         }
444         if (req->state == LDAP_REQUEST_PENDING) {
445                 DLIST_REMOVE(req->conn->pending, req);
446         }
447         req->state = LDAP_REQUEST_DONE;
448         if (req->async.fn) {
449                 req->async.fn(req);
450         }
451 }
452
453 /*
454   send a ldap message - async interface
455 */
456 struct ldap_request *ldap_request_send(struct ldap_connection *conn,
457                                        struct ldap_message *msg)
458 {
459         struct ldap_request *req;
460
461         if (conn->sock == NULL) {
462                 return NULL;
463         }
464
465         req = talloc_zero(conn, struct ldap_request);
466         if (req == NULL) goto failed;
467
468         req->state       = LDAP_REQUEST_SEND;
469         req->conn        = conn;
470         req->messageid   = conn->next_messageid++;
471         req->type        = msg->type;
472         if (req->messageid == -1) {
473                 goto failed;
474         }
475
476         talloc_set_destructor(req, ldap_request_destructor);
477
478         msg->messageid = req->messageid;
479
480         if (!ldap_encode(msg, &req->data)) {
481                 goto failed;            
482         }
483
484         /* possibly encrypt/sign the request */
485         if (conn->enable_wrap) {
486                 DATA_BLOB wrapped;
487                 NTSTATUS status;
488
489                 status = gensec_wrap(conn->gensec, req, &req->data, &wrapped);
490                 if (!NT_STATUS_IS_OK(status)) {
491                         goto failed;
492                 }
493                 data_blob_free(&req->data);
494                 req->data = data_blob_talloc(req, NULL, wrapped.length + 4);
495                 if (req->data.data == NULL) {
496                         goto failed;
497                 }
498                 RSIVAL(req->data.data, 0, wrapped.length);
499                 memcpy(req->data.data+4, wrapped.data, wrapped.length);
500                 data_blob_free(&wrapped);
501         }
502
503
504         if (conn->send_queue == NULL) {
505                 EVENT_FD_WRITEABLE(conn->event.fde);
506         }
507         DLIST_ADD_END(conn->send_queue, req, struct ldap_request *);
508
509         /* put a timeout on the request */
510         event_add_timed(conn->event.event_ctx, req, 
511                         timeval_current_ofs(conn->timeout, 0),
512                         ldap_request_timeout, req);
513
514         return req;
515
516 failed:
517         talloc_free(req);
518         return NULL;
519 }
520
521
522 /*
523   wait for a request to complete
524   note that this does not destroy the request
525 */
526 NTSTATUS ldap_request_wait(struct ldap_request *req)
527 {
528         while (req->state != LDAP_REQUEST_DONE) {
529                 if (event_loop_once(req->conn->event.event_ctx) != 0) {
530                         req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
531                         break;
532                 }
533         }
534         return req->status;
535 }
536
537
538 /*
539   used to setup the status code from a ldap response
540 */
541 NTSTATUS ldap_check_response(struct ldap_connection *conn, struct ldap_Result *r)
542 {
543         if (r->resultcode == LDAP_SUCCESS) {
544                 return NT_STATUS_OK;
545         }
546
547         if (conn->last_error) {
548                 talloc_free(conn->last_error);
549         }
550         conn->last_error = talloc_asprintf(conn, "LDAP error %u - %s <%s> <%s>", 
551                                            r->resultcode,
552                                            r->dn, r->errormessage, r->referral);
553         
554         return NT_STATUS_LDAP(r->resultcode);
555 }
556
557 /*
558   return error string representing the last error
559 */
560 const char *ldap_errstr(struct ldap_connection *conn, NTSTATUS status)
561 {
562         if (NT_STATUS_IS_LDAP(status) && conn->last_error != NULL) {
563                 return conn->last_error;
564         }
565         return nt_errstr(status);
566 }
567
568
569 /*
570   return the Nth result message, waiting if necessary
571 */
572 NTSTATUS ldap_result_n(struct ldap_request *req, int n, struct ldap_message **msg)
573 {
574         *msg = NULL;
575
576         NT_STATUS_HAVE_NO_MEMORY(req);
577
578         while (req->state != LDAP_REQUEST_DONE && n >= req->num_replies) {
579                 if (event_loop_once(req->conn->event.event_ctx) != 0) {
580                         return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
581                 }
582         }
583
584         if (n < req->num_replies) {
585                 *msg = req->replies[n];
586                 return NT_STATUS_OK;
587         }
588
589         if (!NT_STATUS_IS_OK(req->status)) {
590                 return req->status;
591         }
592
593         return NT_STATUS_NO_MORE_ENTRIES;
594 }
595
596
597 /*
598   return a single result message, checking if it is of the expected LDAP type
599 */
600 NTSTATUS ldap_result_one(struct ldap_request *req, struct ldap_message **msg, int type)
601 {
602         NTSTATUS status;
603         status = ldap_result_n(req, 0, msg);
604         if (!NT_STATUS_IS_OK(status)) {
605                 return status;
606         }
607         if ((*msg)->type != type) {
608                 *msg = NULL;
609                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
610         }
611         return status;
612 }
613
614 /*
615   a simple ldap transaction, for single result requests that only need a status code
616   this relies on single valued requests having the response type == request type + 1
617 */
618 NTSTATUS ldap_transaction(struct ldap_connection *conn, struct ldap_message *msg)
619 {
620         struct ldap_request *req = ldap_request_send(conn, msg);
621         struct ldap_message *res;
622         NTSTATUS status;
623         status = ldap_result_n(req, 0, &res);
624         if (!NT_STATUS_IS_OK(status)) {
625                 talloc_free(req);
626                 return status;
627         }
628         if (res->type != msg->type + 1) {
629                 talloc_free(req);
630                 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
631         }
632         status = ldap_check_response(conn, &res->r.GeneralResult);
633         talloc_free(req);
634         return status;
635 }