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