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