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