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