r14895: Merge the 3.0.22 change
[ira/wip.git] / source / nsswitch / winbindd_ldap.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    winbind ldap proxy code
5
6    Copyright (C) Volker Lendecke
7    
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.
12    
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.
17    
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.
21 */
22
23 #include "includes.h"
24 #include "winbindd.h"
25
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. */
30
31 struct ldap_message_queue {
32         struct ldap_message_queue *prev, *next;
33         struct ldap_message *msg;
34 };
35
36 struct rw_buffer {
37         uint8 *data;
38         size_t ofs, length;
39 };
40
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;
46 };
47
48 static struct winbind_ldap_client *ldap_clients;
49
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;
57 };
58         
59 static struct winbind_ldap_server *ldap_servers;
60
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;
66 };
67
68 struct pending_ldap_message *pending_messages;
69
70 static BOOL append_to_buf(struct rw_buffer *buf, uint8 *data, size_t length)
71 {
72         buf->data = SMB_REALLOC(buf->data, buf->length+length);
73
74         if (buf->data == NULL)
75                 return False;
76
77         memcpy(buf->data+buf->length, data, length);
78
79         buf->length += length;
80         return True;
81 }
82
83 static BOOL read_into_buf(int fd, struct rw_buffer *buf)
84 {
85         char tmp_buf[1024];
86         int len;
87
88         len = read(fd, tmp_buf, sizeof(tmp_buf));
89         if (len == 0)
90                 return False;
91
92         return append_to_buf(buf, tmp_buf, len);
93 }
94
95 static void peek_into_buf(struct rw_buffer *buf, uint8 **out,
96                           size_t *out_length)
97 {
98         *out = buf->data;
99         *out_length = buf->length;
100 }
101
102 static void consumed_from_buf(struct rw_buffer *buf, size_t length)
103 {
104         uint8 *new = memdup(buf->data+length, buf->length-length);
105         free(buf->data);
106         buf->data = new;
107         buf->length -= length;
108 }
109
110 static BOOL write_out_of_buf(int fd, struct rw_buffer *buf)
111 {
112         uint8 *tmp;
113         size_t tmp_length, written;
114
115         peek_into_buf(buf, &tmp, &tmp_length);
116         if (tmp_length == 0)
117                 return True;
118
119         written = write(fd, tmp, tmp_length);
120         if (written < 0)
121                 return False;
122
123         consumed_from_buf(buf, written);
124         return True;
125 }
126
127 static BOOL ldap_append_to_buf(struct ldap_message *msg, struct rw_buffer *buf)
128 {
129         DATA_BLOB blob;
130         BOOL res;
131
132         if (!ldap_encode(msg, &blob))
133                 return False;
134
135         res = append_to_buf(buf, blob.data, blob.length);
136
137         data_blob_free(&blob);
138         return res;
139 }
140
141 static void new_ldap_client(int listen_sock)
142 {
143         struct sockaddr_un sunaddr;
144         struct winbind_ldap_client *client;
145         socklen_t len;
146         int sock;
147         
148         /* Accept connection */
149         
150         len = sizeof(sunaddr);
151
152         do {
153                 sock = accept(listen_sock, (struct sockaddr *)&sunaddr, &len);
154         } while (sock == -1 && errno == EINTR);
155
156         if (sock == -1)
157                 return;
158         
159         DEBUG(6,("accepted socket %d\n", sock));
160         
161         /* Create new connection structure */
162
163         client = SMB_MALLOC_P(struct winbind_ldap_client);
164
165         if (client == NULL)
166                 return;
167
168         ZERO_STRUCTP(client);
169         
170         client->sock = sock;
171         client->finished = False;
172         
173         DLIST_ADD(ldap_clients, client);
174 }
175
176 static struct ldap_message *get_msg_from_buf(struct rw_buffer *buffer,
177                                              BOOL *error)
178 {
179         uint8 *buf;
180         int buf_length, msg_length;
181         DATA_BLOB blob;
182         ASN1_DATA data;
183         struct ldap_message *msg;
184
185         DEBUG(10,("ldapsrv_recv\n"));
186
187         *error = False;
188
189         peek_into_buf(buffer, &buf, &buf_length);
190
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;
195         }
196
197         /* LDAP Messages are always SEQUENCES */
198
199         if (!asn1_object_length(buf, buf_length, ASN1_SEQUENCE(0),
200                                 &msg_length))
201                 goto disconnect;
202
203         if (buf_length < msg_length) {
204                 /* Not enough yet */
205                 return NULL;
206         }
207
208         /* We've got a complete LDAP request in the in-buffer */
209
210         blob.data = buf;
211         blob.length = msg_length;
212
213         if (!asn1_load(&data, blob))
214                 goto disconnect;
215
216         msg = new_ldap_message();
217
218         if ((msg == NULL) || !ldap_decode(&data, msg)) {
219                 asn1_free(&data);
220                 goto disconnect;
221         }
222
223         asn1_free(&data);
224
225         consumed_from_buf(buffer, msg_length);
226
227         return msg;
228
229  disconnect:
230
231         *error = True;
232         return NULL;
233 }
234
235 static int send_msg_to_server(struct ldap_message *msg,
236                               struct winbind_ldap_server *server)
237 {
238         int cli_messageid;
239
240         cli_messageid = msg->messageid;
241         msg->messageid = ldap_servers->messageid;
242
243         if (!ldap_append_to_buf(msg, &ldap_servers->out_buffer))
244                 return -1;
245
246         msg->messageid = cli_messageid;
247         return ldap_servers->messageid++;
248 }
249
250 static int send_msg(struct ldap_message *msg)
251 {
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. */
255
256         SMB_ASSERT(ldap_servers != NULL);
257
258         if (!ldap_servers->ready)
259                 return -1;
260
261         return send_msg_to_server(msg, ldap_servers);
262 }
263
264 static void fake_bind_response(struct winbind_ldap_client *client,
265                                int messageid)
266 {
267         struct ldap_message *msg = new_ldap_message();
268
269         if (msg == NULL) {
270                 client->finished = True;
271                 return;
272         }
273
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);
283 }
284
285 static int open_ldap_socket(void)
286 {
287         static int fd = -1;
288
289         if (fd >= 0)
290                 return fd;
291
292         fd = create_pipe_sock(get_winbind_priv_pipe_dir(), "ldapi", 0750);
293         return fd;
294 }
295
296 static BOOL do_sigterm = False;
297
298 static void ldap_termination_handler(int signum)
299 {
300         do_sigterm = True;
301         sys_select_signal();
302 }
303
304 static BOOL handled_locally(struct ldap_message *msg,
305                             struct winbind_ldap_server *server)
306 {
307         struct ldap_Result *r = &msg->r.BindResponse.response;
308
309         if (msg->type != LDAP_TAG_BindResponse)
310                 return False;
311
312         if (r->resultcode != 0) {
313                 destroy_ldap_message(msg);
314                 server->finished = True;
315         }
316         destroy_ldap_message(msg);
317         server->ready = True;
318         return True;
319 }
320
321 static void client_has_data(struct winbind_ldap_client *client)
322 {
323                         
324         struct ldap_message *msg;
325
326         if (!read_into_buf(client->sock, &client->in_buffer)) {
327                 client->finished = True;
328                 return;
329         }
330
331         while ((msg = get_msg_from_buf(&client->in_buffer,
332                                        &client->finished))) {
333                 struct pending_ldap_message *pending;
334
335                 if (msg->type == LDAP_TAG_BindRequest) {
336                         fake_bind_response(client, msg->messageid);
337                         destroy_ldap_message(msg);
338                         continue;
339                 }
340
341                 if (msg->type == LDAP_TAG_UnbindRequest) {
342                         destroy_ldap_message(msg);
343                         client->finished = True;
344                         break;
345                 }
346
347                 pending = SMB_MALLOC_P(struct pending_ldap_message);
348                 if (pending == NULL)
349                         continue;
350
351                 pending->msg = msg;
352                 pending->client = client;
353                 pending->our_msgid = send_msg(msg);
354
355                 if (pending->our_msgid < 0) {
356                         /* could not send */
357                         client->finished = True;
358                         free(pending);
359                 }
360                 DLIST_ADD(pending_messages, pending);
361         }
362 }
363
364 static struct ldap_Result *ldap_msg2result(struct ldap_message *msg)
365 {
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;
383         }
384         return NULL;
385 }
386
387 static void server_has_data(struct winbind_ldap_server *server)
388 {
389         struct ldap_message *msg;
390
391         if (!read_into_buf(server->sock, &server->in_buffer)) {
392                 server->finished = True;
393                 return;
394         }
395
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;
401
402                 if (handled_locally(msg, server))
403                         continue;
404
405                 res = ldap_msg2result(msg);
406
407                 if ( (res != NULL) && (res->resultcode == 10) )
408                         DEBUG(5, ("Got Referral %s\n", res->referral));
409
410                 for (pending = pending_messages;
411                      pending != NULL;
412                      pending = pending->next) {
413                         if (pending->our_msgid == msg->messageid)
414                                 break;
415                 }
416
417                 if (pending == NULL) {
418                         talloc_destroy(msg->mem_ctx);
419                         continue;
420                 }
421
422                 msg->messageid = pending->msg->messageid;
423
424                 buf = &pending->client->out_buffer;
425                 ldap_append_to_buf(msg, buf);
426
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);
433                 }
434                 destroy_ldap_message(msg);
435         }
436 }
437
438 static void process_ldap_loop(void)
439 {
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;
445
446         /* Free up temporary memory */
447
448         lp_TALLOC_FREE();
449         main_loop_TALLOC_FREE();
450
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);
458         }
459
460         /* Initialise fd lists for select() */
461
462         listen_sock = open_ldap_socket();
463
464         if (listen_sock == -1) {
465                 perror("open_ldap_socket");
466                 exit(1);
467         }
468
469         maxfd = listen_sock;
470
471         FD_ZERO(&r_fds);
472         FD_ZERO(&w_fds);
473         FD_SET(listen_sock, &r_fds);
474
475         timeout.tv_sec = WINBINDD_ESTABLISH_LOOP;
476         timeout.tv_usec = 0;
477
478         /* Set up client readers and writers */
479         
480         client = ldap_clients;
481
482         while (client != NULL) {
483
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;
493                 }
494
495                 if (client->sock > maxfd)
496                         maxfd = client->sock;
497
498                 FD_SET(client->sock, &r_fds);
499
500                 if (client->out_buffer.length > 0)
501                         FD_SET(client->sock, &w_fds);
502
503                 client = client->next;
504         }
505
506         /* And now the servers */
507
508         server = ldap_servers;
509
510         while (server != NULL) {
511
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;
519                 }
520
521                 if (server->sock > maxfd)
522                         maxfd = server->sock;
523
524                 FD_SET(server->sock, &r_fds);
525
526                 if (server->out_buffer.length > 0)
527                         FD_SET(server->sock, &w_fds);
528
529                 server = server->next;
530         }
531
532         selret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout);
533
534         if (selret == 0)
535                 return;
536
537         if (selret == -1 && errno != EINTR) {
538                 perror("select");
539                 exit(1);
540         }
541
542         if (FD_ISSET(listen_sock, &r_fds))
543                 new_ldap_client(listen_sock);
544
545         for (client = ldap_clients; client != NULL; client = client->next) {
546
547                 if (FD_ISSET(client->sock, &r_fds))
548                         client_has_data(client);
549
550                 if ((!client->finished) && FD_ISSET(client->sock, &w_fds))
551                         write_out_of_buf(client->sock, &client->out_buffer);
552         }
553
554         for (server = ldap_servers; server != NULL; server = server->next) {
555
556                 if (FD_ISSET(server->sock, &r_fds))
557                         server_has_data(server);
558
559                 if (!server->finished && FD_ISSET(server->sock, &w_fds))
560                         write_out_of_buf(server->sock, &server->out_buffer);
561         }
562 }
563
564 static BOOL setup_ldap_serverconn(void)
565 {
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;
574
575         ldap_servers = SMB_MALLOC_P(struct winbind_ldap_server);
576
577         if ((ldap_servers == NULL) || (mem_ctx == NULL))
578                 return False;
579
580         if (!ldap_parse_basic_url(mem_ctx, "ldap://192.168.234.1:3899/",
581                                   &host, &port, &ldaps))
582                 return False;
583         
584         hp = sys_gethostbyname(host);
585
586         if ((hp == NULL) || (hp->h_addr == NULL))
587                 return False;
588
589         putip((char *)&ip, (char *)hp->h_addr);
590
591         ZERO_STRUCTP(ldap_servers);
592         ldap_servers->sock = open_socket_out(SOCK_STREAM, &ip, port, 10000);
593         ldap_servers->messageid = 1;
594
595         if (!fetch_ldap_pw(&dn, &pw))
596                 return False;
597
598         msg = new_ldap_simple_bind_msg(dn, pw);
599
600         SAFE_FREE(dn);
601         SAFE_FREE(pw);
602
603         if (msg == NULL)
604                 return False;
605
606         msg->messageid = ldap_servers->messageid++;
607
608         ldap_append_to_buf(msg, &ldap_servers->out_buffer);
609
610         destroy_ldap_message(msg);
611
612         return (ldap_servers->sock >= 0);
613 }
614
615 void do_ldap_proxy(void)
616 {
617         int ldap_child;
618
619         ldap_child = sys_fork();
620
621         if (ldap_child != 0)
622                 return;
623
624         /* tdb needs special fork handling */
625         if (tdb_reopen_all() == -1) {
626                 DEBUG(0,("tdb_reopen_all failed.\n"));
627                 _exit(0);
628         }
629
630         if (!message_init()) {
631                 DEBUG(0, ("message_init failed\n"));
632                 _exit(0);
633         }
634
635         CatchSignal(SIGINT, ldap_termination_handler);
636         CatchSignal(SIGQUIT, ldap_termination_handler);
637         CatchSignal(SIGTERM, ldap_termination_handler);
638
639         if (!setup_ldap_serverconn())
640                 return;
641
642         while (1)
643                 process_ldap_loop();
644
645         return;
646 }