r10477: expose transactions outside ldb and change the API once more
[metze/samba/wip.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/include/ldb.h"
37 #include "ldb/include/ldb_private.h"
38 #include "ldb/ldb_ldap/ldb_ldap.h"
39
40 /*
41   rename a record
42 */
43 static int lldb_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn)
44 {
45         TALLOC_CTX *local_ctx;
46         struct lldb_private *lldb = module->private_data;
47         int ret = 0;
48         char *old_dn;
49         char *newrdn;
50         const char *parentdn = "";
51
52         /* ignore ltdb specials */
53         if (ldb_dn_is_special(olddn) || ldb_dn_is_special(newdn)) {
54                 return 0;
55         }
56
57         local_ctx = talloc_named(lldb, 0, "lldb_rename local context");
58         if (local_ctx == NULL) {
59                 return -1;
60         }
61
62         old_dn = ldb_dn_linearize(local_ctx, olddn);
63         if (old_dn == NULL) {
64                 goto failed;
65         }
66
67         newrdn = talloc_asprintf(lldb, "%s=%s",
68                                       newdn->components[0].name,
69                                       ldb_dn_escape_value(lldb, newdn->components[0].value));
70         if (!newrdn) {
71                 goto failed;
72         }
73
74         parentdn = ldb_dn_linearize(lldb, ldb_dn_get_parent(lldb, newdn));
75         if (!parentdn) {
76                 goto failed;
77         }
78
79         lldb->last_rc = ldap_rename_s(lldb->ldap, old_dn, newrdn, parentdn, 1, NULL, NULL);
80         if (lldb->last_rc != LDAP_SUCCESS) {
81                 ldb_set_errstring(module, talloc_strdup(module, ldap_err2string(lldb->last_rc)));
82                 ret = -1;
83         }
84
85         talloc_free(local_ctx);
86         return ret;
87
88 failed:
89         talloc_free(local_ctx);
90         return -1;
91 }
92
93 /*
94   delete a record
95 */
96 static int lldb_delete(struct ldb_module *module, const struct ldb_dn *edn)
97 {
98         struct lldb_private *lldb = module->private_data;
99         char *dn;
100         int ret = 0;
101
102         /* ignore ltdb specials */
103         if (ldb_dn_is_special(edn)) {
104                 return 0;
105         }
106
107         dn = ldb_dn_linearize(lldb, edn);
108
109         lldb->last_rc = ldap_delete_s(lldb->ldap, dn);
110         if (lldb->last_rc != LDAP_SUCCESS) {
111                 ldb_set_errstring(module, talloc_strdup(module, ldap_err2string(lldb->last_rc)));
112                 ret = -1;
113         }
114
115         talloc_free(dn);
116         return ret;
117 }
118
119 /*
120   add a single set of ldap message values to a ldb_message
121 */
122 static int lldb_add_msg_attr(struct ldb_context *ldb,
123                              struct ldb_message *msg, 
124                              const char *attr, struct berval **bval)
125 {
126         int count, i;
127         struct ldb_message_element *el;
128
129         count = ldap_count_values_len(bval);
130
131         if (count <= 0) {
132                 return -1;
133         }
134
135         el = talloc_realloc(msg, msg->elements, struct ldb_message_element, 
136                               msg->num_elements + 1);
137         if (!el) {
138                 errno = ENOMEM;
139                 return -1;
140         }
141
142         msg->elements = el;
143
144         el = &msg->elements[msg->num_elements];
145
146         el->name = talloc_strdup(msg->elements, attr);
147         if (!el->name) {
148                 errno = ENOMEM;
149                 return -1;
150         }
151         el->flags = 0;
152
153         el->num_values = 0;
154         el->values = talloc_array(msg->elements, struct ldb_val, count);
155         if (!el->values) {
156                 errno = ENOMEM;
157                 return -1;
158         }
159
160         for (i=0;i<count;i++) {
161                 el->values[i].data = talloc_memdup(el->values, bval[i]->bv_val, bval[i]->bv_len);
162                 if (!el->values[i].data) {
163                         return -1;
164                 }
165                 el->values[i].length = bval[i]->bv_len;
166                 el->num_values++;
167         }
168
169         msg->num_elements++;
170
171         return 0;
172 }
173
174 /*
175   search for matching records
176 */
177 static int lldb_search(struct ldb_module *module, const struct ldb_dn *base,
178                        enum ldb_scope scope, const char *expression,
179                        const char * const *attrs, struct ldb_message ***res)
180 {
181         struct ldb_context *ldb = module->ldb;
182         struct lldb_private *lldb = module->private_data;
183         int count, msg_count;
184         char *search_base;
185         LDAPMessage *ldapres, *msg;
186
187         search_base = ldb_dn_linearize(ldb, base);
188         if (base == NULL) {
189                 search_base = talloc_strdup(ldb, "");
190         }
191         if (search_base == NULL) {
192                 return -1;
193         }
194
195         if (expression == NULL || expression[0] == '\0') {
196                 expression = "objectClass=*";
197         }
198
199         lldb->last_rc = ldap_search_s(lldb->ldap, search_base, (int)scope, 
200                                       expression, 
201                                       discard_const_p(char *, attrs), 
202                                       0, &ldapres);
203         talloc_free(search_base);
204         if (lldb->last_rc != LDAP_SUCCESS) {
205                 ldb_set_errstring(module, talloc_strdup(module, ldap_err2string(lldb->last_rc)));
206                 return -1;
207         }
208
209         count = ldap_count_entries(lldb->ldap, ldapres);
210         if (count == -1 || count == 0) {
211                 ldap_msgfree(ldapres);
212                 return count;
213         }
214
215         (*res) = talloc_array(lldb, struct ldb_message *, count+1);
216         if (! *res) {
217                 ldap_msgfree(ldapres);
218                 errno = ENOMEM;
219                 return -1;
220         }
221
222         (*res)[0] = NULL;
223
224         msg_count = 0;
225
226         /* loop over all messages */
227         for (msg=ldap_first_entry(lldb->ldap, ldapres); 
228              msg; 
229              msg=ldap_next_entry(lldb->ldap, msg)) {
230                 BerElement *berptr = NULL;
231                 char *attr, *dn;
232
233                 if (msg_count == count) {
234                         /* hmm, got too many? */
235                         ldb_debug(ldb, LDB_DEBUG_FATAL, "Fatal: ldap message count inconsistent\n");
236                         break;
237                 }
238
239                 (*res)[msg_count] = talloc(*res, struct ldb_message);
240                 if (!(*res)[msg_count]) {
241                         goto failed;
242                 }
243                 (*res)[msg_count+1] = NULL;
244
245                 dn = ldap_get_dn(lldb->ldap, msg);
246                 if (!dn) {
247                         goto failed;
248                 }
249
250                 (*res)[msg_count]->dn = ldb_dn_explode((*res)[msg_count], dn);
251                 ldap_memfree(dn);
252                 if (!(*res)[msg_count]->dn) {
253                         goto failed;
254                 }
255
256
257                 (*res)[msg_count]->num_elements = 0;
258                 (*res)[msg_count]->elements = NULL;
259                 (*res)[msg_count]->private_data = NULL;
260
261                 /* loop over all attributes */
262                 for (attr=ldap_first_attribute(lldb->ldap, msg, &berptr);
263                      attr;
264                      attr=ldap_next_attribute(lldb->ldap, msg, berptr)) {
265                         struct berval **bval;
266                         bval = ldap_get_values_len(lldb->ldap, msg, attr);
267
268                         if (bval) {
269                                 lldb_add_msg_attr(ldb, (*res)[msg_count], attr, bval);
270                                 ldap_value_free_len(bval);
271                         }                                         
272                         
273                         ldap_memfree(attr);
274                 }
275                 if (berptr) ber_free(berptr, 0);
276
277                 msg_count++;
278         }
279
280         ldap_msgfree(ldapres);
281
282         return msg_count;
283
284 failed:
285         if (*res) talloc_free(*res);
286         return -1;
287 }
288
289
290 /*
291   search for matching records using a ldb_parse_tree
292 */
293 static int lldb_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
294                               enum ldb_scope scope, struct ldb_parse_tree *tree,
295                               const char * const *attrs, struct ldb_message ***res)
296 {
297         struct lldb_private *lldb = module->private_data;
298         char *expression;
299         int ret;
300
301         expression = ldb_filter_from_tree(lldb, tree);
302         if (expression == NULL) {
303                 return -1;
304         }
305         ret = lldb_search(module, base, scope, expression, attrs, res);
306         talloc_free(expression);
307         return ret;
308 }
309
310
311 /*
312   convert a ldb_message structure to a list of LDAPMod structures
313   ready for ldap_add() or ldap_modify()
314 */
315 static LDAPMod **lldb_msg_to_mods(struct ldb_context *ldb,
316                                   const struct ldb_message *msg, int use_flags)
317 {
318         LDAPMod **mods;
319         unsigned int i, j;
320         int num_mods = 0;
321
322         /* allocate maximum number of elements needed */
323         mods = talloc_array(ldb, LDAPMod *, msg->num_elements+1);
324         if (!mods) {
325                 errno = ENOMEM;
326                 return NULL;
327         }
328         mods[0] = NULL;
329
330         for (i=0;i<msg->num_elements;i++) {
331                 const struct ldb_message_element *el = &msg->elements[i];
332
333                 mods[num_mods] = talloc(ldb, LDAPMod);
334                 if (!mods[num_mods]) {
335                         goto failed;
336                 }
337                 mods[num_mods+1] = NULL;
338                 mods[num_mods]->mod_op = LDAP_MOD_BVALUES;
339                 if (use_flags) {
340                         switch (el->flags & LDB_FLAG_MOD_MASK) {
341                         case LDB_FLAG_MOD_ADD:
342                                 mods[num_mods]->mod_op |= LDAP_MOD_ADD;
343                                 break;
344                         case LDB_FLAG_MOD_DELETE:
345                                 mods[num_mods]->mod_op |= LDAP_MOD_DELETE;
346                                 break;
347                         case LDB_FLAG_MOD_REPLACE:
348                                 mods[num_mods]->mod_op |= LDAP_MOD_REPLACE;
349                                 break;
350                         }
351                 }
352                 mods[num_mods]->mod_type = discard_const_p(char, el->name);
353                 mods[num_mods]->mod_vals.modv_bvals = talloc_array(mods[num_mods], 
354                                                                      struct berval *,
355                                                                      1+el->num_values);
356                 if (!mods[num_mods]->mod_vals.modv_bvals) {
357                         goto failed;
358                 }
359
360                 for (j=0;j<el->num_values;j++) {
361                         mods[num_mods]->mod_vals.modv_bvals[j] = talloc(mods[num_mods]->mod_vals.modv_bvals,
362                                                                           struct berval);
363                         if (!mods[num_mods]->mod_vals.modv_bvals[j]) {
364                                 goto failed;
365                         }
366                         mods[num_mods]->mod_vals.modv_bvals[j]->bv_val = el->values[j].data;
367                         mods[num_mods]->mod_vals.modv_bvals[j]->bv_len = el->values[j].length;
368                 }
369                 mods[num_mods]->mod_vals.modv_bvals[j] = NULL;
370                 num_mods++;
371         }
372
373         return mods;
374
375 failed:
376         talloc_free(mods);
377         return NULL;
378 }
379
380
381 /*
382   add a record
383 */
384 static int lldb_add(struct ldb_module *module, const struct ldb_message *msg)
385 {
386         struct ldb_context *ldb = module->ldb;
387         struct lldb_private *lldb = module->private_data;
388         LDAPMod **mods;
389         char *dn;
390         int ret = 0;
391
392         /* ignore ltdb specials */
393         if (ldb_dn_is_special(msg->dn)) {
394                 return 0;
395         }
396
397         mods = lldb_msg_to_mods(ldb, msg, 0);
398         if (mods == NULL) {
399                 return -1;
400         }
401
402         dn = ldb_dn_linearize(mods, msg->dn);
403         if (dn == NULL) {
404                 talloc_free(mods);
405                 return -1;
406         }
407
408         lldb->last_rc = ldap_add_s(lldb->ldap, dn, mods);
409         if (lldb->last_rc != LDAP_SUCCESS) {
410                 ldb_set_errstring(module, talloc_strdup(module, ldap_err2string(lldb->last_rc)));
411                 ret = -1;
412         }
413
414         talloc_free(mods);
415
416         return ret;
417 }
418
419
420 /*
421   modify a record
422 */
423 static int lldb_modify(struct ldb_module *module, const struct ldb_message *msg)
424 {
425         struct ldb_context *ldb = module->ldb;
426         struct lldb_private *lldb = module->private_data;
427         LDAPMod **mods;
428         char *dn;
429         int ret = 0;
430
431         /* ignore ltdb specials */
432         if (ldb_dn_is_special(msg->dn)) {
433                 return 0;
434         }
435
436         mods = lldb_msg_to_mods(ldb, msg, 1);
437         if (mods == NULL) {
438                 return -1;
439         }
440
441         dn = ldb_dn_linearize(mods, msg->dn);
442         if (dn == NULL) {
443                 talloc_free(mods);
444                 return -1;
445         }
446
447         lldb->last_rc = ldap_modify_s(lldb->ldap, dn, mods);
448         if (lldb->last_rc != LDAP_SUCCESS) {
449                 ldb_set_errstring(module, talloc_strdup(module, ldap_err2string(lldb->last_rc)));
450                 ret = -1;
451         }
452
453         talloc_free(mods);
454
455         return ret;
456 }
457
458 static int lldb_start_trans(struct ldb_module *module)
459 {
460         /* TODO implement a local transaction mechanism here */
461
462         return 0;
463 }
464
465 static int lldb_end_trans(struct ldb_module *module)
466 {
467         /* TODO implement a local transaction mechanism here */
468
469         return 0;
470 }
471
472 static int lldb_del_trans(struct ldb_module *module)
473 {
474         /* TODO implement a local transaction mechanism here */
475
476         return 0;
477 }
478
479 static const struct ldb_module_ops lldb_ops = {
480         .name              = "ldap",
481         .search            = lldb_search,
482         .search_bytree     = lldb_search_bytree,
483         .add_record        = lldb_add,
484         .modify_record     = lldb_modify,
485         .delete_record     = lldb_delete,
486         .rename_record     = lldb_rename,
487         .start_transaction = lldb_start_trans,
488         .end_transaction   = lldb_end_trans,
489         .del_transaction   = lldb_del_trans
490 };
491
492
493 static int lldb_destructor(void *p)
494 {
495         struct lldb_private *lldb = p;
496         ldap_unbind(lldb->ldap);
497         return 0;
498 }
499
500 /*
501   connect to the database
502 */
503 int lldb_connect(struct ldb_context *ldb,
504                  const char *url, 
505                  unsigned int flags, 
506                  const char *options[])
507 {
508         struct lldb_private *lldb = NULL;
509         int version = 3;
510
511         lldb = talloc(ldb, struct lldb_private);
512         if (!lldb) {
513                 ldb_oom(ldb);
514                 goto failed;
515         }
516
517         lldb->ldap = NULL;
518         lldb->options = NULL;
519
520         lldb->last_rc = ldap_initialize(&lldb->ldap, url);
521         if (lldb->last_rc != LDAP_SUCCESS) {
522                 ldb_debug(ldb, LDB_DEBUG_FATAL, "ldap_initialize failed for URL '%s' - %s\n",
523                           url, ldap_err2string(lldb->last_rc));
524                 goto failed;
525         }
526
527         talloc_set_destructor(lldb, lldb_destructor);
528
529         lldb->last_rc = ldap_set_option(lldb->ldap, LDAP_OPT_PROTOCOL_VERSION, &version);
530         if (lldb->last_rc != LDAP_SUCCESS) {
531                 ldb_debug(ldb, LDB_DEBUG_FATAL, "ldap_set_option failed - %s\n",
532                           ldap_err2string(lldb->last_rc));
533         }
534
535         ldb->modules = talloc(ldb, struct ldb_module);
536         if (!ldb->modules) {
537                 ldb_oom(ldb);
538                 goto failed;
539         }
540         ldb->modules->ldb = ldb;
541         ldb->modules->prev = ldb->modules->next = NULL;
542         ldb->modules->private_data = lldb;
543         ldb->modules->ops = &lldb_ops;
544
545         return 0;
546
547 failed:
548         talloc_free(lldb);
549         return -1;
550 }
551