r13694: Committing patch from Aleksey Fedoseev <aleksey at fedoseev dot net> to NULL
[Samba/nascimento.git] / source3 / nsswitch / winbindd_ldap.c
blobcd0214ff45188ffec8637e6565764fd653e3ce8e
1 /*
2 Unix SMB/CIFS implementation.
4 winbind ldap proxy code
6 Copyright (C) Volker Lendecke
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "includes.h"
24 #include "winbindd.h"
26 /* This rw-buf api is made to avoid memcpy. For now do that like mad... The
27 idea is to write into a circular list of buffers where the ideal case is
28 that a read(2) holds a complete request that is then thrown away
29 completely. */
31 struct ldap_message_queue {
32 struct ldap_message_queue *prev, *next;
33 struct ldap_message *msg;
36 struct rw_buffer {
37 uint8 *data;
38 size_t ofs, length;
41 struct winbind_ldap_client {
42 struct winbind_ldap_client *next, *prev;
43 int sock;
44 BOOL finished;
45 struct rw_buffer in_buffer, out_buffer;
48 static struct winbind_ldap_client *ldap_clients;
50 struct winbind_ldap_server {
51 struct winbind_ldap_server *next, *prev;
52 int sock;
53 BOOL ready; /* Bind successful? */
54 BOOL finished;
55 struct rw_buffer in_buffer, out_buffer;
56 int messageid;
59 static struct winbind_ldap_server *ldap_servers;
61 struct pending_ldap_message {
62 struct pending_ldap_message *next, *prev;
63 struct ldap_message *msg; /* The message the client sent us */
64 int our_msgid; /* The messageid we used */
65 struct winbind_ldap_client *client;
68 struct pending_ldap_message *pending_messages;
70 static BOOL append_to_buf(struct rw_buffer *buf, uint8 *data, size_t length)
72 buf->data = SMB_REALLOC(buf->data, buf->length+length);
74 if (buf->data == NULL)
75 return False;
77 memcpy(buf->data+buf->length, data, length);
79 buf->length += length;
80 return True;
83 static BOOL read_into_buf(int fd, struct rw_buffer *buf)
85 char tmp_buf[1024];
86 int len;
88 len = read(fd, tmp_buf, sizeof(tmp_buf));
89 if (len == 0)
90 return False;
92 return append_to_buf(buf, tmp_buf, len);
95 static void peek_into_buf(struct rw_buffer *buf, uint8 **out,
96 size_t *out_length)
98 *out = buf->data;
99 *out_length = buf->length;
102 static void consumed_from_buf(struct rw_buffer *buf, size_t length)
104 uint8 *new = memdup(buf->data+length, buf->length-length);
105 free(buf->data);
106 buf->data = new;
107 buf->length -= length;
110 static BOOL write_out_of_buf(int fd, struct rw_buffer *buf)
112 uint8 *tmp;
113 size_t tmp_length, written;
115 peek_into_buf(buf, &tmp, &tmp_length);
116 if (tmp_length == 0)
117 return True;
119 written = write(fd, tmp, tmp_length);
120 if (written < 0)
121 return False;
123 consumed_from_buf(buf, written);
124 return True;
127 static BOOL ldap_append_to_buf(struct ldap_message *msg, struct rw_buffer *buf)
129 DATA_BLOB blob;
130 BOOL res;
132 if (!ldap_encode(msg, &blob))
133 return False;
135 res = append_to_buf(buf, blob.data, blob.length);
137 data_blob_free(&blob);
138 return res;
141 static void new_ldap_client(int listen_sock)
143 struct sockaddr_un sunaddr;
144 struct winbind_ldap_client *client;
145 socklen_t len;
146 int sock;
148 /* Accept connection */
150 len = sizeof(sunaddr);
152 do {
153 sock = accept(listen_sock, (struct sockaddr *)&sunaddr, &len);
154 } while (sock == -1 && errno == EINTR);
156 if (sock == -1)
157 return;
159 DEBUG(6,("accepted socket %d\n", sock));
161 /* Create new connection structure */
163 client = SMB_MALLOC_P(struct winbind_ldap_client);
165 if (client == NULL)
166 return;
168 ZERO_STRUCTP(client);
170 client->sock = sock;
171 client->finished = False;
173 DLIST_ADD(ldap_clients, client);
176 static struct ldap_message *get_msg_from_buf(struct rw_buffer *buffer,
177 BOOL *error)
179 uint8 *buf;
180 int buf_length, msg_length;
181 DATA_BLOB blob;
182 ASN1_DATA data;
183 struct ldap_message *msg;
185 DEBUG(10,("ldapsrv_recv\n"));
187 *error = False;
189 peek_into_buf(buffer, &buf, &buf_length);
191 if (buf_length < 8) {
192 /* Arbitrary heuristics: ldap messages are longer than eight
193 * bytes, and their tag length fits into the eight bytes */
194 return NULL;
197 /* LDAP Messages are always SEQUENCES */
199 if (!asn1_object_length(buf, buf_length, ASN1_SEQUENCE(0),
200 &msg_length))
201 goto disconnect;
203 if (buf_length < msg_length) {
204 /* Not enough yet */
205 return NULL;
208 /* We've got a complete LDAP request in the in-buffer */
210 blob.data = buf;
211 blob.length = msg_length;
213 if (!asn1_load(&data, blob))
214 goto disconnect;
216 msg = new_ldap_message();
218 if ((msg == NULL) || !ldap_decode(&data, msg)) {
219 asn1_free(&data);
220 goto disconnect;
223 asn1_free(&data);
225 consumed_from_buf(buffer, msg_length);
227 return msg;
229 disconnect:
231 *error = True;
232 return NULL;
235 static int send_msg_to_server(struct ldap_message *msg,
236 struct winbind_ldap_server *server)
238 int cli_messageid;
240 cli_messageid = msg->messageid;
241 msg->messageid = ldap_servers->messageid;
243 if (!ldap_append_to_buf(msg, &ldap_servers->out_buffer))
244 return -1;
246 msg->messageid = cli_messageid;
247 return ldap_servers->messageid++;
250 static int send_msg(struct ldap_message *msg)
252 /* This is the scheduling routine that should decide where to send
253 * stuff. The first attempt is easy: We only have one server. This
254 * will change once we handle referrals etc. */
256 SMB_ASSERT(ldap_servers != NULL);
258 if (!ldap_servers->ready)
259 return -1;
261 return send_msg_to_server(msg, ldap_servers);
264 static void fake_bind_response(struct winbind_ldap_client *client,
265 int messageid)
267 struct ldap_message *msg = new_ldap_message();
269 if (msg == NULL) {
270 client->finished = True;
271 return;
274 msg->messageid = messageid;
275 msg->type = LDAP_TAG_BindResponse;
276 msg->r.BindResponse.response.resultcode = 0;
277 msg->r.BindResponse.response.dn = "";
278 msg->r.BindResponse.response.dn = "";
279 msg->r.BindResponse.response.errormessage = "";
280 msg->r.BindResponse.response.referral = "";
281 ldap_append_to_buf(msg, &client->out_buffer);
282 destroy_ldap_message(msg);
285 static int open_ldap_socket(void)
287 static int fd = -1;
289 if (fd >= 0)
290 return fd;
292 fd = create_pipe_sock(get_winbind_priv_pipe_dir(), "ldapi", 0750);
293 return fd;
296 static BOOL do_sigterm = False;
298 static void ldap_termination_handler(int signum)
300 do_sigterm = True;
301 sys_select_signal();
304 static BOOL handled_locally(struct ldap_message *msg,
305 struct winbind_ldap_server *server)
307 struct ldap_Result *r = &msg->r.BindResponse.response;
309 if (msg->type != LDAP_TAG_BindResponse)
310 return False;
312 if (r->resultcode != 0) {
313 destroy_ldap_message(msg);
314 server->finished = True;
316 destroy_ldap_message(msg);
317 server->ready = True;
318 return True;
321 static void client_has_data(struct winbind_ldap_client *client)
324 struct ldap_message *msg;
326 if (!read_into_buf(client->sock, &client->in_buffer)) {
327 client->finished = True;
328 return;
331 while ((msg = get_msg_from_buf(&client->in_buffer,
332 &client->finished))) {
333 struct pending_ldap_message *pending;
335 if (msg->type == LDAP_TAG_BindRequest) {
336 fake_bind_response(client, msg->messageid);
337 destroy_ldap_message(msg);
338 continue;
341 if (msg->type == LDAP_TAG_UnbindRequest) {
342 destroy_ldap_message(msg);
343 client->finished = True;
344 break;
347 pending = SMB_MALLOC_P(struct pending_ldap_message);
348 if (pending == NULL)
349 continue;
351 pending->msg = msg;
352 pending->client = client;
353 pending->our_msgid = send_msg(msg);
355 if (pending->our_msgid < 0) {
356 /* could not send */
357 client->finished = True;
358 free(pending);
360 DLIST_ADD(pending_messages, pending);
364 static struct ldap_Result *ldap_msg2result(struct ldap_message *msg)
366 switch(msg->type) {
367 case LDAP_TAG_BindResponse:
368 return &msg->r.BindResponse.response;
369 case LDAP_TAG_SearchResultDone:
370 return &msg->r.SearchResultDone;
371 case LDAP_TAG_ModifyResponse:
372 return &msg->r.ModifyResponse;
373 case LDAP_TAG_AddResponse:
374 return &msg->r.AddResponse;
375 case LDAP_TAG_DelResponse:
376 return &msg->r.DelResponse;
377 case LDAP_TAG_ModifyDNResponse:
378 return &msg->r.ModifyDNResponse;
379 case LDAP_TAG_CompareResponse:
380 return &msg->r.CompareResponse;
381 case LDAP_TAG_ExtendedResponse:
382 return &msg->r.ExtendedResponse.response;
384 return NULL;
387 static void server_has_data(struct winbind_ldap_server *server)
389 struct ldap_message *msg;
391 if (!read_into_buf(server->sock, &server->in_buffer)) {
392 server->finished = True;
393 return;
396 while ((msg = get_msg_from_buf(&server->in_buffer,
397 &server->finished))) {
398 struct pending_ldap_message *pending;
399 struct rw_buffer *buf;
400 struct ldap_Result *res;
402 if (handled_locally(msg, server))
403 continue;
405 res = ldap_msg2result(msg);
407 if ( (res != NULL) && (res->resultcode == 10) )
408 DEBUG(5, ("Got Referral %s\n", res->referral));
410 for (pending = pending_messages;
411 pending != NULL;
412 pending = pending->next) {
413 if (pending->our_msgid == msg->messageid)
414 break;
417 if (pending == NULL) {
418 talloc_destroy(msg->mem_ctx);
419 continue;
422 msg->messageid = pending->msg->messageid;
424 buf = &pending->client->out_buffer;
425 ldap_append_to_buf(msg, buf);
427 if ( (msg->type != LDAP_TAG_SearchResultEntry) &&
428 (msg->type != LDAP_TAG_SearchResultReference) ) {
429 destroy_ldap_message(pending->msg);
430 DLIST_REMOVE(pending_messages,
431 pending);
432 SAFE_FREE(pending);
434 destroy_ldap_message(msg);
438 static void process_ldap_loop(void)
440 struct winbind_ldap_client *client;
441 struct winbind_ldap_server *server;
442 fd_set r_fds, w_fds;
443 int maxfd, listen_sock, selret;
444 struct timeval timeout;
446 /* Free up temporary memory */
448 lp_TALLOC_FREE();
449 main_loop_TALLOC_FREE();
451 if (do_sigterm) {
452 #if 0
453 TALLOC_CTX *mem_ctx = talloc_init("describe");
454 DEBUG(0, ("%s\n", talloc_describe_all(mem_ctx)));
455 talloc_destroy(mem_ctx);
456 #endif
457 exit(0);
460 /* Initialise fd lists for select() */
462 listen_sock = open_ldap_socket();
464 if (listen_sock == -1) {
465 perror("open_ldap_socket");
466 exit(1);
469 maxfd = listen_sock;
471 FD_ZERO(&r_fds);
472 FD_ZERO(&w_fds);
473 FD_SET(listen_sock, &r_fds);
475 timeout.tv_sec = WINBINDD_ESTABLISH_LOOP;
476 timeout.tv_usec = 0;
478 /* Set up client readers and writers */
480 client = ldap_clients;
482 while (client != NULL) {
484 if (client->finished) {
485 struct winbind_ldap_client *next = client->next;
486 DLIST_REMOVE(ldap_clients, client);
487 close(client->sock);
488 SAFE_FREE(client->in_buffer.data);
489 SAFE_FREE(client->out_buffer.data);
490 SAFE_FREE(client);
491 client = next;
492 continue;
495 if (client->sock > maxfd)
496 maxfd = client->sock;
498 FD_SET(client->sock, &r_fds);
500 if (client->out_buffer.length > 0)
501 FD_SET(client->sock, &w_fds);
503 client = client->next;
506 /* And now the servers */
508 server = ldap_servers;
510 while (server != NULL) {
512 if (server->finished) {
513 struct winbind_ldap_server *next = server->next;
514 DLIST_REMOVE(ldap_servers, server);
515 close(server->sock);
516 SAFE_FREE(server);
517 server = next;
518 continue;
521 if (server->sock > maxfd)
522 maxfd = server->sock;
524 FD_SET(server->sock, &r_fds);
526 if (server->out_buffer.length > 0)
527 FD_SET(server->sock, &w_fds);
529 server = server->next;
532 selret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout);
534 if (selret == 0)
535 return;
537 if (selret == -1 && errno != EINTR) {
538 perror("select");
539 exit(1);
542 if (FD_ISSET(listen_sock, &r_fds))
543 new_ldap_client(listen_sock);
545 for (client = ldap_clients; client != NULL; client = client->next) {
547 if (FD_ISSET(client->sock, &r_fds))
548 client_has_data(client);
550 if ((!client->finished) && FD_ISSET(client->sock, &w_fds))
551 write_out_of_buf(client->sock, &client->out_buffer);
554 for (server = ldap_servers; server != NULL; server = server->next) {
556 if (FD_ISSET(server->sock, &r_fds))
557 server_has_data(server);
559 if (!server->finished && FD_ISSET(server->sock, &w_fds))
560 write_out_of_buf(server->sock, &server->out_buffer);
564 static BOOL setup_ldap_serverconn(void)
566 char *host;
567 uint16 port;
568 BOOL ldaps;
569 struct hostent *hp;
570 struct in_addr ip;
571 TALLOC_CTX *mem_ctx = talloc_init("server");
572 struct ldap_message *msg;
573 char *dn, *pw;
575 ldap_servers = SMB_MALLOC_P(struct winbind_ldap_server);
577 if ((ldap_servers == NULL) || (mem_ctx == NULL))
578 return False;
580 if (!ldap_parse_basic_url(mem_ctx, "ldap://192.168.234.1:3899/",
581 &host, &port, &ldaps))
582 return False;
584 hp = sys_gethostbyname(host);
586 if ((hp == NULL) || (hp->h_addr == NULL))
587 return False;
589 putip((char *)&ip, (char *)hp->h_addr);
591 ZERO_STRUCTP(ldap_servers);
592 ldap_servers->sock = open_socket_out(SOCK_STREAM, &ip, port, 10000);
593 ldap_servers->messageid = 1;
595 if (!fetch_ldap_pw(&dn, &pw))
596 return False;
598 msg = new_ldap_simple_bind_msg(dn, pw);
600 SAFE_FREE(dn);
601 SAFE_FREE(pw);
603 if (msg == NULL)
604 return False;
606 msg->messageid = ldap_servers->messageid++;
608 ldap_append_to_buf(msg, &ldap_servers->out_buffer);
610 destroy_ldap_message(msg);
612 return (ldap_servers->sock >= 0);
615 void do_ldap_proxy(void)
617 int ldap_child;
619 ldap_child = sys_fork();
621 if (ldap_child != 0)
622 return;
624 /* tdb needs special fork handling */
625 if (tdb_reopen_all() == -1) {
626 DEBUG(0,("tdb_reopen_all failed.\n"));
627 _exit(0);
630 if (!message_init()) {
631 DEBUG(0, ("message_init failed\n"));
632 _exit(0);
635 CatchSignal(SIGINT, ldap_termination_handler);
636 CatchSignal(SIGQUIT, ldap_termination_handler);
637 CatchSignal(SIGTERM, ldap_termination_handler);
639 if (!setup_ldap_serverconn())
640 return;
642 while (1)
643 process_ldap_loop();
645 return;