r382: More C++ friendliness fixes.
[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         lldb->last_rc = ldap_delete_s(lldb->ldap, dn);
101         if (lldb->last_rc != LDAP_SUCCESS) {
102                 ret = -1;
103         }
104
105         return ret;
106 }
107
108 /*
109   free a search message
110 */
111 static int lldb_msg_free(struct ldb_context *ldb, struct ldb_message *msg)
112 {
113         int i, j;
114         free(msg->dn);
115         for (i=0;i<msg->num_elements;i++) {
116                 free(msg->elements[i].name);
117                 for (j=0;j<msg->elements[i].num_values;j++) {
118                         if (msg->elements[i].values[j].data) {
119                                 free(msg->elements[i].values[j].data);
120                         }
121                 }
122                 free(msg->elements[i].values);
123         }
124         if (msg->elements) free(msg->elements);
125         free(msg);
126         return 0;
127 }
128
129 /*
130   free a search result
131 */
132 static int lldb_search_free(struct ldb_context *ldb, struct ldb_message **res)
133 {
134         int i;
135         for (i=0;res[i];i++) {
136                 if (lldb_msg_free(ldb, res[i]) != 0) {
137                         return -1;
138                 }
139         }
140         free(res);
141         return 0;
142 }
143
144
145 /*
146   add a single set of ldap message values to a ldb_message
147 */
148 static int lldb_add_msg_attr(struct ldb_message *msg, 
149                              const char *attr, struct berval **bval)
150 {
151         int count, i;
152         struct ldb_message_element *el;
153
154         count = ldap_count_values_len(bval);
155
156         if (count <= 0) {
157                 return -1;
158         }
159
160         el = realloc_p(msg->elements, struct ldb_message_element, 
161                        msg->num_elements + 1);
162         if (!el) {
163                 errno = ENOMEM;
164                 return -1;
165         }
166
167         msg->elements = el;
168
169         el = &msg->elements[msg->num_elements];
170
171         el->name = strdup(attr);
172         if (!el->name) {
173                 errno = ENOMEM;
174                 return -1;
175         }
176         el->flags = 0;
177
178         el->num_values = 0;
179         el->values = malloc_array_p(struct ldb_val, count);
180         if (!el->values) {
181                 errno = ENOMEM;
182                 return -1;
183         }
184
185         for (i=0;i<count;i++) {
186                 el->values[i].data = malloc(bval[i]->bv_len);
187                 if (!el->values[i].data) {
188                         return -1;
189                 }
190                 memcpy(el->values[i].data, bval[i]->bv_val, bval[i]->bv_len);
191                 el->values[i].length = bval[i]->bv_len;
192                 el->num_values++;
193         }
194
195         msg->num_elements++;
196
197         return 0;
198 }
199
200 /*
201   search for matching records
202 */
203 static int lldb_search(struct ldb_context *ldb, const char *base,
204                        enum ldb_scope scope, const char *expression,
205                        const char **attrs, struct ldb_message ***res)
206 {
207         struct lldb_private *lldb = ldb->private_data;
208         int count, msg_count;
209         LDAPMessage *ldapres, *msg;
210
211         lldb->last_rc = ldap_search_s(lldb->ldap, base, (int)scope, 
212                                       expression, attrs, 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) = malloc_array_p(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                         fprintf(stderr,"Too many messages?!\n");
244                         break;
245                 }
246
247                 (*res)[msg_count] = malloc_p(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 = strdup(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((*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(ldb, *res);
294         return -1;
295 }
296
297
298 /*
299   free a set of mods from lldb_msg_to_mods()
300 */
301 static void lldb_mods_free(LDAPMod **mods)
302 {
303         int i, j;
304
305         if (!mods) return;
306
307         for (i=0;mods[i];i++) {
308                 if (mods[i]->mod_vals.modv_bvals) {
309                         for (j=0;mods[i]->mod_vals.modv_bvals[j];j++) {
310                                 free(mods[i]->mod_vals.modv_bvals[j]);
311                         }
312                         free(mods[i]->mod_vals.modv_bvals);
313                 }
314                 free(mods[i]);
315         }
316         free(mods);
317 }
318
319
320 /*
321   convert a ldb_message structure to a list of LDAPMod structures
322   ready for ldap_add() or ldap_modify()
323 */
324 static LDAPMod **lldb_msg_to_mods(const struct ldb_message *msg, int use_flags)
325 {
326         LDAPMod **mods;
327         int i, j, num_mods = 0;
328
329         /* allocate maximum number of elements needed */
330         mods = malloc_array_p(LDAPMod *, msg->num_elements+1);
331         if (!mods) {
332                 errno = ENOMEM;
333                 return NULL;
334         }
335         mods[0] = NULL;
336
337         for (i=0;i<msg->num_elements;i++) {
338                 const struct ldb_message_element *el = &msg->elements[i];
339
340                 mods[num_mods] = malloc_p(LDAPMod);
341                 if (!mods[num_mods]) {
342                         goto failed;
343                 }
344                 mods[num_mods+1] = NULL;
345                 mods[num_mods]->mod_op = LDAP_MOD_BVALUES;
346                 if (use_flags) {
347                         switch (el->flags & LDB_FLAG_MOD_MASK) {
348                         case LDB_FLAG_MOD_ADD:
349                                 mods[num_mods]->mod_op |= LDAP_MOD_ADD;
350                                 break;
351                         case LDB_FLAG_MOD_DELETE:
352                                 mods[num_mods]->mod_op |= LDAP_MOD_DELETE;
353                                 break;
354                         case LDB_FLAG_MOD_REPLACE:
355                                 mods[num_mods]->mod_op |= LDAP_MOD_REPLACE;
356                                 break;
357                         }
358                 }
359                 mods[num_mods]->mod_type = el->name;
360                 mods[num_mods]->mod_vals.modv_bvals = malloc_array_p(struct berval *, 
361                                                                      1+el->num_values);
362                 if (!mods[num_mods]->mod_vals.modv_bvals) {
363                         goto failed;
364                 }
365
366                 for (j=0;j<el->num_values;j++) {
367                         mods[num_mods]->mod_vals.modv_bvals[j] = malloc_p(struct berval);
368                         if (!mods[num_mods]->mod_vals.modv_bvals[j]) {
369                                 goto failed;
370                         }
371                         mods[num_mods]->mod_vals.modv_bvals[j]->bv_val = el->values[j].data;
372                         mods[num_mods]->mod_vals.modv_bvals[j]->bv_len = el->values[j].length;
373                 }
374                 mods[num_mods]->mod_vals.modv_bvals[j] = NULL;
375                 num_mods++;
376         }
377
378         return mods;
379
380 failed:
381         lldb_mods_free(mods);
382         return NULL;
383 }
384
385
386 /*
387   add a record
388 */
389 static int lldb_add(struct ldb_context *ldb, const struct ldb_message *msg)
390 {
391         struct lldb_private *lldb = ldb->private_data;
392         LDAPMod **mods;
393         int ret = 0;
394
395         mods = lldb_msg_to_mods(msg, 0);
396
397         lldb->last_rc = ldap_add_s(lldb->ldap, msg->dn, mods);
398         if (lldb->last_rc != LDAP_SUCCESS) {
399                 ret = -1;
400         }
401
402         lldb_mods_free(mods);
403
404         return ret;
405 }
406
407
408 /*
409   modify a record
410 */
411 static int lldb_modify(struct ldb_context *ldb, const struct ldb_message *msg)
412 {
413         struct lldb_private *lldb = ldb->private_data;
414         LDAPMod **mods;
415         int ret = 0;
416
417         mods = lldb_msg_to_mods(msg, 1);
418
419         lldb->last_rc = ldap_modify_s(lldb->ldap, msg->dn, mods);
420         if (lldb->last_rc != LDAP_SUCCESS) {
421                 ret = -1;
422         }
423
424         lldb_mods_free(mods);
425
426         return ret;
427 }
428
429
430 /*
431   return extended error information
432 */
433 static const char *lldb_errstring(struct ldb_context *ldb)
434 {
435         struct lldb_private *lldb = ldb->private_data;
436         return ldap_err2string(lldb->last_rc);
437 }
438
439
440 static const struct ldb_backend_ops lldb_ops = {
441         lldb_close, 
442         lldb_search,
443         lldb_search_free,
444         lldb_add,
445         lldb_modify,
446         lldb_delete,
447         lldb_errstring
448 };
449
450
451 /*
452   connect to the database
453 */
454 struct ldb_context *lldb_connect(const char *url, 
455                                  unsigned int flags, 
456                                  const char *options[])
457 {
458         struct ldb_context *ldb = NULL;
459         struct lldb_private *lldb = NULL;
460         int i;
461
462         ldb = malloc_p(struct ldb_context);
463         if (!ldb) {
464                 errno = ENOMEM;
465                 goto failed;
466         }
467
468         lldb = malloc_p(struct lldb_private);
469         if (!lldb) {
470                 free(ldb);
471                 errno = ENOMEM;
472                 goto failed;
473         }
474
475         lldb->ldap = NULL;
476         lldb->options = NULL;
477
478         lldb->last_rc = ldap_initialize(&lldb->ldap, url);
479         if (lldb->last_rc != LDAP_SUCCESS) {
480                 goto failed;
481         }
482
483         ldb->ops = &lldb_ops;
484         ldb->private_data = lldb;
485
486         if (options) {
487                 /* take a copy of the options array, so we don't have to rely
488                    on the caller keeping it around (it might be dynamic) */
489                 for (i=0;options[i];i++) ;
490
491                 lldb->options = malloc_array_p(char *, i+1);
492                 if (!lldb->options) {
493                         goto failed;
494                 }
495                 
496                 for (i=0;options[i];i++) {
497                         lldb->options[i+1] = NULL;
498                         lldb->options[i] = strdup(options[i]);
499                         if (!lldb->options[i]) {
500                                 goto failed;
501                         }
502                 }
503         }
504
505         return ldb;
506
507 failed:
508         if (lldb && lldb->options) {
509                 for (i=0;lldb->options[i];i++) {
510                         free(lldb->options[i]);
511                 }
512                 free(lldb->options);
513         }
514         if (lldb && lldb->ldap) {
515                 ldap_unbind(lldb->ldap);
516         }
517         if (lldb) free(lldb);
518         if (ldb) free(ldb);
519         return NULL;
520 }
521