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())