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