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.
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
31 struct ldap_message_queue
{
32 struct ldap_message_queue
*prev
, *next
;
33 struct ldap_message
*msg
;
41 struct winbind_ldap_client
{
42 struct winbind_ldap_client
*next
, *prev
;
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
;
53 BOOL ready
; /* Bind successful? */
55 struct rw_buffer in_buffer
, out_buffer
;
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
)
77 memcpy(buf
->data
+buf
->length
, data
, length
);
79 buf
->length
+= length
;
83 static BOOL
read_into_buf(int fd
, struct rw_buffer
*buf
)
88 len
= read(fd
, tmp_buf
, sizeof(tmp_buf
));
92 return append_to_buf(buf
, tmp_buf
, len
);
95 static void peek_into_buf(struct rw_buffer
*buf
, uint8
**out
,
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
);
107 buf
->length
-= length
;
110 static BOOL
write_out_of_buf(int fd
, struct rw_buffer
*buf
)
113 size_t tmp_length
, written
;
115 peek_into_buf(buf
, &tmp
, &tmp_length
);
119 written
= write(fd
, tmp
, tmp_length
);
123 consumed_from_buf(buf
, written
);
127 static BOOL
ldap_append_to_buf(struct ldap_message
*msg
, struct rw_buffer
*buf
)
132 if (!ldap_encode(msg
, &blob
))
135 res
= append_to_buf(buf
, blob
.data
, blob
.length
);
137 data_blob_free(&blob
);
141 static void new_ldap_client(int listen_sock
)
143 struct sockaddr_un sunaddr
;
144 struct winbind_ldap_client
*client
;
148 /* Accept connection */
150 len
= sizeof(sunaddr
);
153 sock
= accept(listen_sock
, (struct sockaddr
*)&sunaddr
, &len
);
154 } while (sock
== -1 && errno
== EINTR
);
159 DEBUG(6,("accepted socket %d\n", sock
));
161 /* Create new connection structure */
163 client
= SMB_MALLOC_P(struct winbind_ldap_client
);
168 ZERO_STRUCTP(client
);
171 client
->finished
= False
;
173 DLIST_ADD(ldap_clients
, client
);
176 static struct ldap_message
*get_msg_from_buf(struct rw_buffer
*buffer
,
180 int buf_length
, msg_length
;
183 struct ldap_message
*msg
;
185 DEBUG(10,("ldapsrv_recv\n"));
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 */
197 /* LDAP Messages are always SEQUENCES */
199 if (!asn1_object_length(buf
, buf_length
, ASN1_SEQUENCE(0),
203 if (buf_length
< msg_length
) {
208 /* We've got a complete LDAP request in the in-buffer */
211 blob
.length
= msg_length
;
213 if (!asn1_load(&data
, blob
))
216 msg
= new_ldap_message();
218 if ((msg
== NULL
) || !ldap_decode(&data
, msg
)) {
225 consumed_from_buf(buffer
, msg_length
);
235 static int send_msg_to_server(struct ldap_message
*msg
,
236 struct winbind_ldap_server
*server
)
240 cli_messageid
= msg
->messageid
;
241 msg
->messageid
= ldap_servers
->messageid
;
243 if (!ldap_append_to_buf(msg
, &ldap_servers
->out_buffer
))
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
)
261 return send_msg_to_server(msg
, ldap_servers
);
264 static void fake_bind_response(struct winbind_ldap_client
*client
,
267 struct ldap_message
*msg
= new_ldap_message();
270 client
->finished
= True
;
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)
292 fd
= create_pipe_sock(get_winbind_priv_pipe_dir(), "ldapi", 0750);
296 static BOOL do_sigterm
= False
;
298 static void ldap_termination_handler(int signum
)
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
)
312 if (r
->resultcode
!= 0) {
313 destroy_ldap_message(msg
);
314 server
->finished
= True
;
316 destroy_ldap_message(msg
);
317 server
->ready
= 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
;
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
);
341 if (msg
->type
== LDAP_TAG_UnbindRequest
) {
342 destroy_ldap_message(msg
);
343 client
->finished
= True
;
347 pending
= SMB_MALLOC_P(struct pending_ldap_message
);
352 pending
->client
= client
;
353 pending
->our_msgid
= send_msg(msg
);
355 if (pending
->our_msgid
< 0) {
357 client
->finished
= True
;
360 DLIST_ADD(pending_messages
, pending
);
364 static struct ldap_Result
*ldap_msg2result(struct ldap_message
*msg
)
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
;
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
;
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
))
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
;
412 pending
= pending
->next
) {
413 if (pending
->our_msgid
== msg
->messageid
)
417 if (pending
== NULL
) {
418 talloc_destroy(msg
->mem_ctx
);
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
,
434 destroy_ldap_message(msg
);
438 static void process_ldap_loop(void)
440 struct winbind_ldap_client
*client
;
441 struct winbind_ldap_server
*server
;
443 int maxfd
, listen_sock
, selret
;
444 struct timeval timeout
;
446 /* Free up temporary memory */
449 main_loop_TALLOC_FREE();
453 TALLOC_CTX
*mem_ctx
= talloc_init("describe");
454 DEBUG(0, ("%s\n", talloc_describe_all(mem_ctx
)));
455 talloc_destroy(mem_ctx
);
460 /* Initialise fd lists for select() */
462 listen_sock
= open_ldap_socket();
464 if (listen_sock
== -1) {
465 perror("open_ldap_socket");
473 FD_SET(listen_sock
, &r_fds
);
475 timeout
.tv_sec
= WINBINDD_ESTABLISH_LOOP
;
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
);
488 SAFE_FREE(client
->in_buffer
.data
);
489 SAFE_FREE(client
->out_buffer
.data
);
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
);
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
);
537 if (selret
== -1 && errno
!= EINTR
) {
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)
571 TALLOC_CTX
*mem_ctx
= talloc_init("server");
572 struct ldap_message
*msg
;
575 ldap_servers
= SMB_MALLOC_P(struct winbind_ldap_server
);
577 if ((ldap_servers
== NULL
) || (mem_ctx
== NULL
))
580 if (!ldap_parse_basic_url(mem_ctx
, "ldap://192.168.234.1:3899/",
581 &host
, &port
, &ldaps
))
584 hp
= sys_gethostbyname(host
);
586 if ((hp
== NULL
) || (hp
->h_addr
== NULL
))
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
))
598 msg
= new_ldap_simple_bind_msg(dn
, pw
);
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)
619 ldap_child
= sys_fork();
624 /* tdb needs special fork handling */
625 if (tdb_reopen_all() == -1) {
626 DEBUG(0,("tdb_reopen_all failed.\n"));
630 if (!message_init()) {
631 DEBUG(0, ("message_init failed\n"));
635 CatchSignal(SIGINT
, ldap_termination_handler
);
636 CatchSignal(SIGQUIT
, ldap_termination_handler
);
637 CatchSignal(SIGTERM
, ldap_termination_handler
);
639 if (!setup_ldap_serverconn())