r3926: fix compiler warnings
[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/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   close/free the connection
72 */
73 static int lldb_close(struct ldb_module *module)
74 {
75         int i, ret = 0;
76         struct ldb_context *ldb = module->ldb;
77         struct lldb_private *lldb = module->private_data;
78
79         if (ldap_unbind(lldb->ldap) != LDAP_SUCCESS) {
80                 ret = -1;
81         }
82
83         ldb_set_alloc(ldb, NULL, NULL);
84
85         if (lldb->options) {
86                 for (i=0;lldb->options[i];i++) {
87                         ldb_free(ldb, lldb->options[i]);
88                 }
89                 ldb_free(ldb, lldb->options);
90         }
91         ldb_free(ldb, lldb);
92         free(ldb);
93
94         return ret;
95 }
96
97 /*
98   rename a record
99 */
100 static int lldb_rename(struct ldb_module *module, const char *olddn, const char *newdn)
101 {
102         struct ldb_context *ldb = module->ldb;
103         struct lldb_private *lldb = module->private_data;
104         int ret = 0;
105         char *newrdn, *p;
106         const char *parentdn = "";
107
108         /* ignore ltdb specials */
109         if (olddn[0] == '@' ||newdn[0] == '@') {
110                 return 0;
111         }
112
113         newrdn = ldb_strdup(ldb, newdn);
114         if (!newrdn) {
115                 return -1;
116         }
117
118         p = strchr(newrdn, ',');
119         if (p) {
120                 *p++ = '\0';
121                 parentdn = p;
122         }
123
124         lldb->last_rc = ldap_rename_s(lldb->ldap, olddn, newrdn, parentdn, 1, NULL, NULL);
125         ldb_free(ldb, newrdn);
126         if (lldb->last_rc != LDAP_SUCCESS) {
127                 ret = -1;
128         }
129
130         return ret;
131 }
132
133 /*
134   delete a record
135 */
136 static int lldb_delete(struct ldb_module *module, const char *dn)
137 {
138         struct lldb_private *lldb = module->private_data;
139         int ret = 0;
140
141         /* ignore ltdb specials */
142         if (dn[0] == '@') {
143                 return 0;
144         }
145         
146         lldb->last_rc = ldap_delete_s(lldb->ldap, dn);
147         if (lldb->last_rc != LDAP_SUCCESS) {
148                 ret = -1;
149         }
150
151         return ret;
152 }
153
154 /*
155   free a search message
156 */
157 static int lldb_msg_free(struct ldb_context *ldb, struct ldb_message *msg)
158 {
159         unsigned int i, j;
160         ldb_free(ldb, msg->dn);
161         for (i=0;i<msg->num_elements;i++) {
162                 ldb_free(ldb, msg->elements[i].name);
163                 for (j=0;j<msg->elements[i].num_values;j++) {
164                         if (msg->elements[i].values[j].data) {
165                                 ldb_free(ldb, msg->elements[i].values[j].data);
166                         }
167                 }
168                 ldb_free(ldb, msg->elements[i].values);
169         }
170         if (msg->elements) ldb_free(ldb, msg->elements);
171         ldb_free(ldb, msg);
172         return 0;
173 }
174
175 /*
176   free a search result
177 */
178 static int lldb_search_free(struct ldb_module *module, struct ldb_message **res)
179 {
180         struct ldb_context *ldb = module->ldb;
181         int i;
182         for (i=0;res[i];i++) {
183                 if (lldb_msg_free(ldb, res[i]) != 0) {
184                         return -1;
185                 }
186         }
187         ldb_free(ldb, res);
188         return 0;
189 }
190
191
192 /*
193   add a single set of ldap message values to a ldb_message
194 */
195 static int lldb_add_msg_attr(struct ldb_context *ldb,
196                              struct ldb_message *msg, 
197                              const char *attr, struct berval **bval)
198 {
199         int count, i;
200         struct ldb_message_element *el;
201
202         count = ldap_count_values_len(bval);
203
204         if (count <= 0) {
205                 return -1;
206         }
207
208         el = ldb_realloc_p(ldb, msg->elements, struct ldb_message_element, 
209                            msg->num_elements + 1);
210         if (!el) {
211                 errno = ENOMEM;
212                 return -1;
213         }
214
215         msg->elements = el;
216
217         el = &msg->elements[msg->num_elements];
218
219         el->name = ldb_strdup(ldb, attr);
220         if (!el->name) {
221                 errno = ENOMEM;
222                 return -1;
223         }
224         el->flags = 0;
225
226         el->num_values = 0;
227         el->values = ldb_malloc_array_p(ldb, struct ldb_val, count);
228         if (!el->values) {
229                 errno = ENOMEM;
230                 return -1;
231         }
232
233         for (i=0;i<count;i++) {
234                 el->values[i].data = ldb_malloc(ldb, bval[i]->bv_len);
235                 if (!el->values[i].data) {
236                         return -1;
237                 }
238                 memcpy(el->values[i].data, bval[i]->bv_val, bval[i]->bv_len);
239                 el->values[i].length = bval[i]->bv_len;
240                 el->num_values++;
241         }
242
243         msg->num_elements++;
244
245         return 0;
246 }
247
248 /*
249   search for matching records
250 */
251 static int lldb_search(struct ldb_module *module, const char *base,
252                        enum ldb_scope scope, const char *expression,
253                        const char * const *attrs, struct ldb_message ***res)
254 {
255         struct ldb_context *ldb = module->ldb;
256         struct lldb_private *lldb = module->private_data;
257         int count, msg_count;
258         LDAPMessage *ldapres, *msg;
259
260         if (base == NULL) {
261                 base = "";
262         }
263
264         lldb->last_rc = ldap_search_s(lldb->ldap, base, (int)scope, 
265                                       expression, 
266                                       discard_const_p(char *, attrs), 
267                                       0, &ldapres);
268         if (lldb->last_rc != LDAP_SUCCESS) {
269                 return -1;
270         }
271
272         count = ldap_count_entries(lldb->ldap, ldapres);
273         if (count == -1 || count == 0) {
274                 ldap_msgfree(ldapres);
275                 return count;
276         }
277
278         (*res) = ldb_malloc_array_p(ldb, struct ldb_message *, count+1);
279         if (! *res) {
280                 ldap_msgfree(ldapres);
281                 errno = ENOMEM;
282                 return -1;
283         }
284
285         (*res)[0] = NULL;
286
287         msg_count = 0;
288
289         /* loop over all messages */
290         for (msg=ldap_first_entry(lldb->ldap, ldapres); 
291              msg; 
292              msg=ldap_next_entry(lldb->ldap, msg)) {
293                 BerElement *berptr = NULL;
294                 char *attr, *dn;
295
296                 if (msg_count == count) {
297                         /* hmm, got too many? */
298                         ldb_debug(ldb, LDB_DEBUG_FATAL, "Fatal: ldap message count inconsistent\n");
299                         break;
300                 }
301
302                 (*res)[msg_count] = ldb_malloc_p(ldb, struct ldb_message);
303                 if (!(*res)[msg_count]) {
304                         goto failed;
305                 }
306                 (*res)[msg_count+1] = NULL;
307
308                 dn = ldap_get_dn(lldb->ldap, msg);
309                 if (!dn) {
310                         goto failed;
311                 }
312
313                 (*res)[msg_count]->dn = ldb_strdup(ldb, dn);
314                 ldap_memfree(dn);
315                 if (!(*res)[msg_count]->dn) {
316                         goto failed;
317                 }
318
319
320                 (*res)[msg_count]->num_elements = 0;
321                 (*res)[msg_count]->elements = NULL;
322                 (*res)[msg_count]->private_data = NULL;
323
324                 /* loop over all attributes */
325                 for (attr=ldap_first_attribute(lldb->ldap, msg, &berptr);
326                      attr;
327                      attr=ldap_next_attribute(lldb->ldap, msg, berptr)) {
328                         struct berval **bval;
329                         bval = ldap_get_values_len(lldb->ldap, msg, attr);
330
331                         if (bval) {
332                                 lldb_add_msg_attr(ldb, (*res)[msg_count], attr, bval);
333                                 ldap_value_free_len(bval);
334                         }                                         
335                         
336                         ldap_memfree(attr);
337                 }
338                 if (berptr) ber_free(berptr, 0);
339
340                 msg_count++;
341         }
342
343         ldap_msgfree(ldapres);
344
345         return msg_count;
346
347 failed:
348         if (*res) lldb_search_free(module, *res);
349         return -1;
350 }
351
352
353 /*
354   free a set of mods from lldb_msg_to_mods()
355 */
356 static void lldb_mods_free(struct ldb_context *ldb, LDAPMod **mods)
357 {
358         int i, j;
359
360         if (!mods) return;
361
362         for (i=0;mods[i];i++) {
363                 if (mods[i]->mod_vals.modv_bvals) {
364                         for (j=0;mods[i]->mod_vals.modv_bvals[j];j++) {
365                                 ldb_free(ldb, mods[i]->mod_vals.modv_bvals[j]);
366                         }
367                         ldb_free(ldb, mods[i]->mod_vals.modv_bvals);
368                 }
369                 ldb_free(ldb, mods[i]);
370         }
371         ldb_free(ldb, mods);
372 }
373
374
375 /*
376   convert a ldb_message structure to a list of LDAPMod structures
377   ready for ldap_add() or ldap_modify()
378 */
379 static LDAPMod **lldb_msg_to_mods(struct ldb_context *ldb,
380                                   const struct ldb_message *msg, int use_flags)
381 {
382         LDAPMod **mods;
383         unsigned int i, j;
384         int num_mods = 0;
385
386         /* allocate maximum number of elements needed */
387         mods = ldb_malloc_array_p(ldb, LDAPMod *, msg->num_elements+1);
388         if (!mods) {
389                 errno = ENOMEM;
390                 return NULL;
391         }
392         mods[0] = NULL;
393
394         for (i=0;i<msg->num_elements;i++) {
395                 const struct ldb_message_element *el = &msg->elements[i];
396
397                 mods[num_mods] = ldb_malloc_p(ldb, LDAPMod);
398                 if (!mods[num_mods]) {
399                         goto failed;
400                 }
401                 mods[num_mods+1] = NULL;
402                 mods[num_mods]->mod_op = LDAP_MOD_BVALUES;
403                 if (use_flags) {
404                         switch (el->flags & LDB_FLAG_MOD_MASK) {
405                         case LDB_FLAG_MOD_ADD:
406                                 mods[num_mods]->mod_op |= LDAP_MOD_ADD;
407                                 break;
408                         case LDB_FLAG_MOD_DELETE:
409                                 mods[num_mods]->mod_op |= LDAP_MOD_DELETE;
410                                 break;
411                         case LDB_FLAG_MOD_REPLACE:
412                                 mods[num_mods]->mod_op |= LDAP_MOD_REPLACE;
413                                 break;
414                         }
415                 }
416                 mods[num_mods]->mod_type = el->name;
417                 mods[num_mods]->mod_vals.modv_bvals = ldb_malloc_array_p(ldb, 
418                                                                          struct berval *,
419                                                                          1+el->num_values);
420                 if (!mods[num_mods]->mod_vals.modv_bvals) {
421                         goto failed;
422                 }
423
424                 for (j=0;j<el->num_values;j++) {
425                         mods[num_mods]->mod_vals.modv_bvals[j] = ldb_malloc_p(ldb, struct berval);
426                         if (!mods[num_mods]->mod_vals.modv_bvals[j]) {
427                                 goto failed;
428                         }
429                         mods[num_mods]->mod_vals.modv_bvals[j]->bv_val = el->values[j].data;
430                         mods[num_mods]->mod_vals.modv_bvals[j]->bv_len = el->values[j].length;
431                 }
432                 mods[num_mods]->mod_vals.modv_bvals[j] = NULL;
433                 num_mods++;
434         }
435
436         return mods;
437
438 failed:
439         lldb_mods_free(ldb, mods);
440         return NULL;
441 }
442
443
444 /*
445   add a record
446 */
447 static int lldb_add(struct ldb_module *module, const struct ldb_message *msg)
448 {
449         struct ldb_context *ldb = module->ldb;
450         struct lldb_private *lldb = module->private_data;
451         LDAPMod **mods;
452         int ret = 0;
453
454         /* ignore ltdb specials */
455         if (msg->dn[0] == '@') {
456                 return 0;
457         }
458
459         mods = lldb_msg_to_mods(ldb, msg, 0);
460
461         lldb->last_rc = ldap_add_s(lldb->ldap, msg->dn, mods);
462         if (lldb->last_rc != LDAP_SUCCESS) {
463                 ret = -1;
464         }
465
466         lldb_mods_free(ldb, mods);
467
468         return ret;
469 }
470
471
472 /*
473   modify a record
474 */
475 static int lldb_modify(struct ldb_module *module, const struct ldb_message *msg)
476 {
477         struct ldb_context *ldb = module->ldb;
478         struct lldb_private *lldb = module->private_data;
479         LDAPMod **mods;
480         int ret = 0;
481
482         /* ignore ltdb specials */
483         if (msg->dn[0] == '@') {
484                 return 0;
485         }
486
487         mods = lldb_msg_to_mods(ldb, msg, 1);
488
489         lldb->last_rc = ldap_modify_s(lldb->ldap, msg->dn, mods);
490         if (lldb->last_rc != LDAP_SUCCESS) {
491                 ret = -1;
492         }
493
494         lldb_mods_free(ldb, mods);
495
496         return ret;
497 }
498
499 static int lldb_lock(struct ldb_module *module, const char *lockname)
500 {
501         int ret = 0;
502
503         if (lockname == NULL) {
504                 return -1;
505         }
506
507         /* TODO implement a local locking mechanism here */
508
509         return ret;
510 }
511
512 static int lldb_unlock(struct ldb_module *module, const char *lockname)
513 {
514         int ret = 0;
515
516         if (lockname == NULL) {
517                 return -1;
518         }
519
520         /* TODO implement a local unlocking mechanism here */
521
522         return ret;
523 }
524
525 /*
526   return extended error information
527 */
528 static const char *lldb_errstring(struct ldb_module *module)
529 {
530         struct lldb_private *lldb = module->private_data;
531         return ldap_err2string(lldb->last_rc);
532 }
533
534
535 static const struct ldb_module_ops lldb_ops = {
536         "ldap",
537         lldb_close, 
538         lldb_search,
539         lldb_search_free,
540         lldb_add,
541         lldb_modify,
542         lldb_delete,
543         lldb_rename,
544         lldb_lock,
545         lldb_unlock,
546         lldb_errstring
547 };
548
549
550 /*
551   connect to the database
552 */
553 struct ldb_context *lldb_connect(const char *url, 
554                                  unsigned int flags, 
555                                  const char *options[])
556 {
557         struct ldb_context *ldb = NULL;
558         struct lldb_private *lldb = NULL;
559         int i, version = 3;
560
561         ldb = calloc(1, sizeof(struct ldb_context));
562         if (!ldb) {
563                 errno = ENOMEM;
564                 goto failed;
565         }
566
567         lldb = ldb_malloc_p(ldb, struct lldb_private);
568         if (!lldb) {
569                 ldb_free(ldb, ldb);
570                 errno = ENOMEM;
571                 goto failed;
572         }
573
574         lldb->ldap = NULL;
575         lldb->options = NULL;
576
577         lldb->last_rc = ldap_initialize(&lldb->ldap, url);
578         if (lldb->last_rc != LDAP_SUCCESS) {
579                 goto failed;
580         }
581
582         lldb->last_rc = ldap_set_option(lldb->ldap, LDAP_OPT_PROTOCOL_VERSION, &version);
583         if (lldb->last_rc != LDAP_SUCCESS) {
584                 goto failed;
585         }
586
587         ldb->modules = ldb_malloc_p(ldb, struct ldb_module);
588         if (!ldb->modules) {
589                 ldb_free(ldb, ldb);
590                 errno = ENOMEM;
591                 goto failed;
592         }
593         ldb->modules->ldb = ldb;
594         ldb->modules->prev = ldb->modules->next = NULL;
595         ldb->modules->private_data = lldb;
596         ldb->modules->ops = &lldb_ops;
597
598         if (options) {
599                 /* take a copy of the options array, so we don't have to rely
600                    on the caller keeping it around (it might be dynamic) */
601                 for (i=0;options[i];i++) ;
602
603                 lldb->options = ldb_malloc_array_p(ldb, char *, i+1);
604                 if (!lldb->options) {
605                         goto failed;
606                 }
607                 
608                 for (i=0;options[i];i++) {
609                         lldb->options[i+1] = NULL;
610                         lldb->options[i] = ldb_strdup(ldb, options[i]);
611                         if (!lldb->options[i]) {
612                                 goto failed;
613                         }
614                 }
615         }
616
617         return ldb;
618
619 failed:
620         if (lldb && lldb->options) {
621                 for (i=0;lldb->options[i];i++) {
622                         ldb_free(ldb, lldb->options[i]);
623                 }
624                 ldb_free(ldb, lldb->options);
625         }
626         if (lldb && lldb->ldap) {
627                 ldap_unbind(lldb->ldap);
628         }
629         ldb_free(ldb, lldb);
630         if (ldb) free(ldb);
631         return NULL;
632 }
633