r502: modified ldb to allow the use of an external pool memory
[samba.git] / source4 / lib / ldb / ldb_ldap / ldb_ldap.c
1 /* 
2    ldb database library
3
4    Copyright (C) Andrew Tridgell  2004
5
6      ** NOTE! The following LGPL license applies to the ldb
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9    
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 2 of the License, or (at your option) any later version.
14
15    This library 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 GNU
18    Lesser General Public License for more details.
19
20    You should have received a copy of the GNU Lesser General Public
21    License along with this library; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25 /*
26  *  Name: ldb
27  *
28  *  Component: ldb ldap backend
29  *
30  *  Description: core files for LDAP backend
31  *
32  *  Author: Andrew Tridgell
33  */
34
35 #include "includes.h"
36 #include "ldb/ldb_ldap/ldb_ldap.h"
37
38 #if 0
39 /*
40   we don't need this right now, but will once we add some backend 
41   options
42 */
43
44 /*
45   find an option in an option list (a null terminated list of strings)
46
47   this assumes the list is short. If it ever gets long then we really
48   should do this in some smarter way
49  */
50 static const char *lldb_option_find(const struct lldb_private *lldb, const char *name)
51 {
52         int i;
53         size_t len = strlen(name);
54
55         if (!lldb->options) return NULL;
56
57         for (i=0;lldb->options[i];i++) {                
58                 if (strncmp(lldb->options[i], name, len) == 0 &&
59                     lldb->options[i][len] == '=') {
60                         return &lldb->options[i][len+1];
61                 }
62         }
63
64         return NULL;
65 }
66 #endif
67
68 /*
69   close/free the connection
70 */
71 static int lldb_close(struct ldb_context *ldb)
72 {
73         int i, ret = 0;
74         struct lldb_private *lldb = ldb->private_data;
75
76         if (ldap_unbind(lldb->ldap) != LDAP_SUCCESS) {
77                 ret = -1;
78         }
79
80         ldb_set_alloc(ldb, NULL, NULL);
81
82         if (lldb->options) {
83                 for (i=0;lldb->options[i];i++) {
84                         ldb_free(ldb, lldb->options[i]);
85                 }
86                 ldb_free(ldb, lldb->options);
87         }
88         ldb_free(ldb, lldb);
89         free(ldb);
90
91         return ret;
92 }
93
94 /*
95   delete a record
96 */
97 static int lldb_delete(struct ldb_context *ldb, const char *dn)
98 {
99         struct lldb_private *lldb = ldb->private_data;
100         int ret = 0;
101
102         /* ignore ltdb specials */
103         if (dn[0] == '@') {
104                 return 0;
105         }
106         
107         lldb->last_rc = ldap_delete_s(lldb->ldap, dn);
108         if (lldb->last_rc != LDAP_SUCCESS) {
109                 ret = -1;
110         }
111
112         return ret;
113 }
114
115 /*
116   free a search message
117 */
118 static int lldb_msg_free(struct ldb_context *ldb, struct ldb_message *msg)
119 {
120         int i, j;
121         ldb_free(ldb, msg->dn);
122         for (i=0;i<msg->num_elements;i++) {
123                 ldb_free(ldb, msg->elements[i].name);
124                 for (j=0;j<msg->elements[i].num_values;j++) {
125                         if (msg->elements[i].values[j].data) {
126                                 ldb_free(ldb, msg->elements[i].values[j].data);
127                         }
128                 }
129                 ldb_free(ldb, msg->elements[i].values);
130         }
131         if (msg->elements) ldb_free(ldb, msg->elements);
132         ldb_free(ldb, msg);
133         return 0;
134 }
135
136 /*
137   free a search result
138 */
139 static int lldb_search_free(struct ldb_context *ldb, struct ldb_message **res)
140 {
141         int i;
142         for (i=0;res[i];i++) {
143                 if (lldb_msg_free(ldb, res[i]) != 0) {
144                         return -1;
145                 }
146         }
147         ldb_free(ldb, res);
148         return 0;
149 }
150
151
152 /*
153   add a single set of ldap message values to a ldb_message
154 */
155 static int lldb_add_msg_attr(struct ldb_context *ldb,
156                              struct ldb_message *msg, 
157                              const char *attr, struct berval **bval)
158 {
159         int count, i;
160         struct ldb_message_element *el;
161
162         count = ldap_count_values_len(bval);
163
164         if (count <= 0) {
165                 return -1;
166         }
167
168         el = ldb_realloc_p(ldb, msg->elements, struct ldb_message_element, 
169                            msg->num_elements + 1);
170         if (!el) {
171                 errno = ENOMEM;
172                 return -1;
173         }
174
175         msg->elements = el;
176
177         el = &msg->elements[msg->num_elements];
178
179         el->name = ldb_strdup(ldb, attr);
180         if (!el->name) {
181                 errno = ENOMEM;
182                 return -1;
183         }
184         el->flags = 0;
185
186         el->num_values = 0;
187         el->values = ldb_malloc_array_p(ldb, struct ldb_val, count);
188         if (!el->values) {
189                 errno = ENOMEM;
190                 return -1;
191         }
192
193         for (i=0;i<count;i++) {
194                 el->values[i].data = ldb_malloc(ldb, bval[i]->bv_len);
195                 if (!el->values[i].data) {
196                         return -1;
197                 }
198                 memcpy(el->values[i].data, bval[i]->bv_val, bval[i]->bv_len);
199                 el->values[i].length = bval[i]->bv_len;
200                 el->num_values++;
201         }
202
203         msg->num_elements++;
204
205         return 0;
206 }
207
208 /*
209   search for matching records
210 */
211 static int lldb_search(struct ldb_context *ldb, const char *base,
212                        enum ldb_scope scope, const char *expression,
213                        char * const *attrs, struct ldb_message ***res)
214 {
215         struct lldb_private *lldb = ldb->private_data;
216         int count, msg_count;
217         LDAPMessage *ldapres, *msg;
218
219         lldb->last_rc = ldap_search_s(lldb->ldap, base, (int)scope, 
220                                       expression, attrs, 0, &ldapres);
221         if (lldb->last_rc != LDAP_SUCCESS) {
222                 return -1;
223         }
224
225         count = ldap_count_entries(lldb->ldap, ldapres);
226         if (count == -1 || count == 0) {
227                 ldap_msgfree(ldapres);
228                 return count;
229         }
230
231         (*res) = ldb_malloc_array_p(ldb, struct ldb_message *, count+1);
232         if (! *res) {
233                 ldap_msgfree(ldapres);
234                 errno = ENOMEM;
235                 return -1;
236         }
237
238         (*res)[0] = NULL;
239
240         msg_count = 0;
241
242         /* loop over all messages */
243         for (msg=ldap_first_entry(lldb->ldap, ldapres); 
244              msg; 
245              msg=ldap_next_entry(lldb->ldap, msg)) {
246                 BerElement *berptr = NULL;
247                 char *attr, *dn;
248
249                 if (msg_count == count) {
250                         /* hmm, got too many? */
251                         fprintf(stderr,"Too many messages?!\n");
252                         break;
253                 }
254
255                 (*res)[msg_count] = ldb_malloc_p(ldb, struct ldb_message);
256                 if (!(*res)[msg_count]) {
257                         goto failed;
258                 }
259                 (*res)[msg_count+1] = NULL;
260
261                 dn = ldap_get_dn(lldb->ldap, msg);
262                 if (!dn) {
263                         goto failed;
264                 }
265
266                 (*res)[msg_count]->dn = ldb_strdup(ldb, dn);
267                 ldap_memfree(dn);
268                 if (!(*res)[msg_count]->dn) {
269                         goto failed;
270                 }
271
272
273                 (*res)[msg_count]->num_elements = 0;
274                 (*res)[msg_count]->elements = NULL;
275                 (*res)[msg_count]->private_data = NULL;
276
277                 /* loop over all attributes */
278                 for (attr=ldap_first_attribute(lldb->ldap, msg, &berptr);
279                      attr;
280                      attr=ldap_next_attribute(lldb->ldap, msg, berptr)) {
281                         struct berval **bval;
282                         bval = ldap_get_values_len(lldb->ldap, msg, attr);
283
284                         if (bval) {
285                                 lldb_add_msg_attr(ldb, (*res)[msg_count], attr, bval);
286                                 ldap_value_free_len(bval);
287                         }                                         
288                         
289                         ldap_memfree(attr);
290                 }
291                 if (berptr) ber_free(berptr, 0);
292
293                 msg_count++;
294         }
295
296         ldap_msgfree(ldapres);
297
298         return msg_count;
299
300 failed:
301         if (*res) lldb_search_free(ldb, *res);
302         return -1;
303 }
304
305
306 /*
307   free a set of mods from lldb_msg_to_mods()
308 */
309 static void lldb_mods_free(struct ldb_context *ldb, LDAPMod **mods)
310 {
311         int i, j;
312
313         if (!mods) return;
314
315         for (i=0;mods[i];i++) {
316                 if (mods[i]->mod_vals.modv_bvals) {
317                         for (j=0;mods[i]->mod_vals.modv_bvals[j];j++) {
318                                 ldb_free(ldb, mods[i]->mod_vals.modv_bvals[j]);
319                         }
320                         ldb_free(ldb, mods[i]->mod_vals.modv_bvals);
321                 }
322                 ldb_free(ldb, mods[i]);
323         }
324         ldb_free(ldb, mods);
325 }
326
327
328 /*
329   convert a ldb_message structure to a list of LDAPMod structures
330   ready for ldap_add() or ldap_modify()
331 */
332 static LDAPMod **lldb_msg_to_mods(struct ldb_context *ldb,
333                                   const struct ldb_message *msg, int use_flags)
334 {
335         LDAPMod **mods;
336         int i, j, num_mods = 0;
337
338         /* allocate maximum number of elements needed */
339         mods = ldb_malloc_array_p(ldb, LDAPMod *, msg->num_elements+1);
340         if (!mods) {
341                 errno = ENOMEM;
342                 return NULL;
343         }
344         mods[0] = NULL;
345
346         for (i=0;i<msg->num_elements;i++) {
347                 const struct ldb_message_element *el = &msg->elements[i];
348
349                 mods[num_mods] = ldb_malloc_p(ldb, LDAPMod);
350                 if (!mods[num_mods]) {
351                         goto failed;
352                 }
353                 mods[num_mods+1] = NULL;
354                 mods[num_mods]->mod_op = LDAP_MOD_BVALUES;
355                 if (use_flags) {
356                         switch (el->flags & LDB_FLAG_MOD_MASK) {
357                         case LDB_FLAG_MOD_ADD:
358                                 mods[num_mods]->mod_op |= LDAP_MOD_ADD;
359                                 break;
360                         case LDB_FLAG_MOD_DELETE:
361                                 mods[num_mods]->mod_op |= LDAP_MOD_DELETE;
362                                 break;
363                         case LDB_FLAG_MOD_REPLACE:
364                                 mods[num_mods]->mod_op |= LDAP_MOD_REPLACE;
365                                 break;
366                         }
367                 }
368                 mods[num_mods]->mod_type = el->name;
369                 mods[num_mods]->mod_vals.modv_bvals = ldb_malloc_array_p(ldb, 
370                                                                          struct berval *,
371                                                                          1+el->num_values);
372                 if (!mods[num_mods]->mod_vals.modv_bvals) {
373                         goto failed;
374                 }
375
376                 for (j=0;j<el->num_values;j++) {
377                         mods[num_mods]->mod_vals.modv_bvals[j] = ldb_malloc_p(ldb, struct berval);
378                         if (!mods[num_mods]->mod_vals.modv_bvals[j]) {
379                                 goto failed;
380                         }
381                         mods[num_mods]->mod_vals.modv_bvals[j]->bv_val = el->values[j].data;
382                         mods[num_mods]->mod_vals.modv_bvals[j]->bv_len = el->values[j].length;
383                 }
384                 mods[num_mods]->mod_vals.modv_bvals[j] = NULL;
385                 num_mods++;
386         }
387
388         return mods;
389
390 failed:
391         lldb_mods_free(ldb, mods);
392         return NULL;
393 }
394
395
396 /*
397   add a record
398 */
399 static int lldb_add(struct ldb_context *ldb, const struct ldb_message *msg)
400 {
401         struct lldb_private *lldb = ldb->private_data;
402         LDAPMod **mods;
403         int ret = 0;
404
405         /* ignore ltdb specials */
406         if (msg->dn[0] == '@') {
407                 return 0;
408         }
409
410         mods = lldb_msg_to_mods(ldb, msg, 0);
411
412         lldb->last_rc = ldap_add_s(lldb->ldap, msg->dn, mods);
413         if (lldb->last_rc != LDAP_SUCCESS) {
414                 ret = -1;
415         }
416
417         lldb_mods_free(ldb, mods);
418
419         return ret;
420 }
421
422
423 /*
424   modify a record
425 */
426 static int lldb_modify(struct ldb_context *ldb, const struct ldb_message *msg)
427 {
428         struct lldb_private *lldb = ldb->private_data;
429         LDAPMod **mods;
430         int ret = 0;
431
432         /* ignore ltdb specials */
433         if (msg->dn[0] == '@') {
434                 return 0;
435         }
436
437         mods = lldb_msg_to_mods(ldb, msg, 1);
438
439         lldb->last_rc = ldap_modify_s(lldb->ldap, msg->dn, mods);
440         if (lldb->last_rc != LDAP_SUCCESS) {
441                 ret = -1;
442         }
443
444         lldb_mods_free(ldb, mods);
445
446         return ret;
447 }
448
449
450 /*
451   return extended error information
452 */
453 static const char *lldb_errstring(struct ldb_context *ldb)
454 {
455         struct lldb_private *lldb = ldb->private_data;
456         return ldap_err2string(lldb->last_rc);
457 }
458
459
460 static const struct ldb_backend_ops lldb_ops = {
461         lldb_close, 
462         lldb_search,
463         lldb_search_free,
464         lldb_add,
465         lldb_modify,
466         lldb_delete,
467         lldb_errstring
468 };
469
470
471 /*
472   connect to the database
473 */
474 struct ldb_context *lldb_connect(const char *url, 
475                                  unsigned int flags, 
476                                  const char *options[])
477 {
478         struct ldb_context *ldb = NULL;
479         struct lldb_private *lldb = NULL;
480         int i;
481
482         ldb = calloc(1, sizeof(struct ldb_context));
483         if (!ldb) {
484                 errno = ENOMEM;
485                 goto failed;
486         }
487
488         lldb = ldb_malloc_p(ldb, struct lldb_private);
489         if (!lldb) {
490                 ldb_free(ldb, ldb);
491                 errno = ENOMEM;
492                 goto failed;
493         }
494
495         lldb->ldap = NULL;
496         lldb->options = NULL;
497
498         lldb->last_rc = ldap_initialize(&lldb->ldap, url);
499         if (lldb->last_rc != LDAP_SUCCESS) {
500                 goto failed;
501         }
502
503         ldb->ops = &lldb_ops;
504         ldb->private_data = lldb;
505
506         if (options) {
507                 /* take a copy of the options array, so we don't have to rely
508                    on the caller keeping it around (it might be dynamic) */
509                 for (i=0;options[i];i++) ;
510
511                 lldb->options = ldb_malloc_array_p(ldb, char *, i+1);
512                 if (!lldb->options) {
513                         goto failed;
514                 }
515                 
516                 for (i=0;options[i];i++) {
517                         lldb->options[i+1] = NULL;
518                         lldb->options[i] = ldb_strdup(ldb, options[i]);
519                         if (!lldb->options[i]) {
520                                 goto failed;
521                         }
522                 }
523         }
524
525         return ldb;
526
527 failed:
528         if (lldb && lldb->options) {
529                 for (i=0;lldb->options[i];i++) {
530                         ldb_free(ldb, lldb->options[i]);
531                 }
532                 ldb_free(ldb, lldb->options);
533         }
534         if (lldb && lldb->ldap) {
535                 ldap_unbind(lldb->ldap);
536         }
537         ldb_free(ldb, lldb);
538         if (ldb) free(ldb);
539         return NULL;
540 }
541