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