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