r7776: add a method for getting arbitrary opaque data into a ldb context, for use...
[ambi/samba-autobuild/.git] / source4 / lib / ldb / ldb_ildap / ldb_ildap.c
1 /* 
2    ldb database library - ildap backend
3
4    Copyright (C) Andrew Tridgell  2005
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   This is a ldb backend for the internal ldap client library in
27   Samba4. By using this backend we are independent of a system ldap
28   library
29 */
30
31
32 #include "includes.h"
33 #include "ldb/include/ldb.h"
34 #include "ldb/include/ldb_private.h"
35 #include "libcli/ldap/ldap.h"
36 #include "libcli/ldap/ldap_client.h"
37 #include "lib/cmdline/popt_common.h"
38
39 struct ildb_private {
40         struct ldap_connection *ldap;
41         NTSTATUS last_rc;
42         struct ldb_message *rootDSE;
43 };
44
45 /*
46   rename a record
47 */
48 static int ildb_rename(struct ldb_module *module, const char *olddn, const char *newdn)
49 {
50         struct ildb_private *ildb = module->private_data;
51         int ret = 0;
52         char *newrdn, *p;
53         const char *parentdn = "";
54
55         /* ignore ltdb specials */
56         if (olddn[0] == '@' ||newdn[0] == '@') {
57                 return 0;
58         }
59
60         newrdn = talloc_strdup(ildb, newdn);
61         if (!newrdn) {
62                 return -1;
63         }
64
65         p = strchr(newrdn, ',');
66         if (p) {
67                 *p++ = '\0';
68                 parentdn = p;
69         }
70
71         ildb->last_rc = ildap_rename(ildb->ldap, olddn, newrdn, parentdn, True);
72         if (!NT_STATUS_IS_OK(ildb->last_rc)) {
73                 ret = -1;
74         }
75
76         talloc_free(newrdn);
77
78         return ret;
79 }
80
81 /*
82   delete a record
83 */
84 static int ildb_delete(struct ldb_module *module, const char *dn)
85 {
86         struct ildb_private *ildb = module->private_data;
87         int ret = 0;
88
89         /* ignore ltdb specials */
90         if (dn[0] == '@') {
91                 return 0;
92         }
93         
94         ildb->last_rc = ildap_delete(ildb->ldap, dn);
95         if (!NT_STATUS_IS_OK(ildb->last_rc)) {
96                 ret = -1;
97         }
98
99         return ret;
100 }
101
102
103 static void ildb_rootdse(struct ldb_module *module);
104
105 /*
106   search for matching records
107 */
108 static int ildb_search(struct ldb_module *module, const char *base,
109                        enum ldb_scope scope, const char *expression,
110                        const char * const *attrs, struct ldb_message ***res)
111 {
112         struct ildb_private *ildb = module->private_data;
113         int count, i;
114         struct ldap_message **ldapres, *msg;
115
116         if (scope == LDB_SCOPE_DEFAULT) {
117                 scope = LDB_SCOPE_SUBTREE;
118         }
119         
120         if (base == NULL) {
121                 if (ildb->rootDSE == NULL) {
122                         ildb_rootdse(module);
123                 }
124                 if (ildb->rootDSE != NULL) {
125                         base = ldb_msg_find_string(ildb->rootDSE, 
126                                                    "defaultNamingContext", "");
127                 } else {
128                         base = "";
129                 }
130         }
131
132         if (expression == NULL || expression[0] == '\0') {
133                 expression = "objectClass=*";
134         }
135
136         ildb->last_rc = ildap_search(ildb->ldap, base, scope, expression, attrs, 
137                                      0, &ldapres);
138         if (!NT_STATUS_IS_OK(ildb->last_rc)) {
139                 return -1;
140         }
141
142         count = ildap_count_entries(ildb->ldap, ldapres);
143         if (count == -1 || count == 0) {
144                 talloc_free(ldapres);
145                 return count;
146         }
147
148         (*res) = talloc_array(ildb, struct ldb_message *, count+1);
149         if (! *res) {
150                 talloc_free(ldapres);
151                 return -1;
152         }
153
154         (*res)[0] = NULL;
155
156         /* loop over all messages */
157         for (i=0;i<count;i++) {
158                 struct ldap_SearchResEntry *search;
159
160                 msg = ldapres[i];
161                 search = &msg->r.SearchResultEntry;
162
163                 (*res)[i] = talloc(*res, struct ldb_message);
164                 if (!(*res)[i]) {
165                         goto failed;
166                 }
167                 (*res)[i+1] = NULL;
168
169                 (*res)[i]->dn = talloc_steal((*res)[i], search->dn);
170                 (*res)[i]->num_elements = search->num_attributes;
171                 (*res)[i]->elements = talloc_steal((*res)[i], search->attributes);
172                 (*res)[i]->private_data = NULL;
173         }
174
175         talloc_free(ldapres);
176
177         return count;
178
179 failed:
180         if (*res) talloc_free(*res);
181         return -1;
182 }
183
184
185 /*
186   search for matching records using a ldb_parse_tree
187 */
188 static int ildb_search_bytree(struct ldb_module *module, const char *base,
189                               enum ldb_scope scope, struct ldb_parse_tree *tree,
190                               const char * const *attrs, struct ldb_message ***res)
191 {
192         struct ildb_private *ildb = module->private_data;
193         char *expression;
194         int ret;
195
196         expression = ldb_filter_from_tree(ildb, tree);
197         if (expression == NULL) {
198                 return -1;
199         }
200         ret = ildb_search(module, base, scope, expression, attrs, res);
201         talloc_free(expression);
202         return ret;
203 }
204
205
206 /*
207   convert a ldb_message structure to a list of ldap_mod structures
208   ready for ildap_add() or ildap_modify()
209 */
210 static struct ldap_mod **ildb_msg_to_mods(struct ldb_context *ldb,
211                                           const struct ldb_message *msg, int use_flags)
212 {
213         struct ldap_mod **mods;
214         unsigned int i;
215         int num_mods = 0;
216
217         /* allocate maximum number of elements needed */
218         mods = talloc_array(ldb, struct ldap_mod *, msg->num_elements+1);
219         if (!mods) {
220                 errno = ENOMEM;
221                 return NULL;
222         }
223         mods[0] = NULL;
224
225         for (i=0;i<msg->num_elements;i++) {
226                 const struct ldb_message_element *el = &msg->elements[i];
227
228                 mods[num_mods] = talloc(ldb, struct ldap_mod);
229                 if (!mods[num_mods]) {
230                         goto failed;
231                 }
232                 mods[num_mods+1] = NULL;
233                 mods[num_mods]->type = 0;
234                 mods[num_mods]->attrib = *el;
235                 if (use_flags) {
236                         switch (el->flags & LDB_FLAG_MOD_MASK) {
237                         case LDB_FLAG_MOD_ADD:
238                                 mods[num_mods]->type = LDAP_MODIFY_ADD;
239                                 break;
240                         case LDB_FLAG_MOD_DELETE:
241                                 mods[num_mods]->type = LDAP_MODIFY_DELETE;
242                                 break;
243                         case LDB_FLAG_MOD_REPLACE:
244                                 mods[num_mods]->type = LDAP_MODIFY_REPLACE;
245                                 break;
246                         }
247                 }
248                 num_mods++;
249         }
250
251         return mods;
252
253 failed:
254         talloc_free(mods);
255         return NULL;
256 }
257
258
259 /*
260   add a record
261 */
262 static int ildb_add(struct ldb_module *module, const struct ldb_message *msg)
263 {
264         struct ldb_context *ldb = module->ldb;
265         struct ildb_private *ildb = module->private_data;
266         struct ldap_mod **mods;
267         int ret = 0;
268
269         /* ignore ltdb specials */
270         if (msg->dn[0] == '@') {
271                 return 0;
272         }
273
274         mods = ildb_msg_to_mods(ldb, msg, 0);
275
276         ildb->last_rc = ildap_add(ildb->ldap, msg->dn, mods);
277         if (!NT_STATUS_IS_OK(ildb->last_rc)) {
278                 ret = -1;
279         }
280
281         talloc_free(mods);
282
283         return ret;
284 }
285
286
287 /*
288   modify a record
289 */
290 static int ildb_modify(struct ldb_module *module, const struct ldb_message *msg)
291 {
292         struct ldb_context *ldb = module->ldb;
293         struct ildb_private *ildb = module->private_data;
294         struct ldap_mod **mods;
295         int ret = 0;
296
297         /* ignore ltdb specials */
298         if (msg->dn[0] == '@') {
299                 return 0;
300         }
301
302         mods = ildb_msg_to_mods(ldb, msg, 1);
303
304         ildb->last_rc = ildap_modify(ildb->ldap, msg->dn, mods);
305         if (!NT_STATUS_IS_OK(ildb->last_rc)) {
306                 ret = -1;
307         }
308
309         talloc_free(mods);
310
311         return ret;
312 }
313
314 static int ildb_lock(struct ldb_module *module, const char *lockname)
315 {
316         int ret = 0;
317
318         if (lockname == NULL) {
319                 return -1;
320         }
321
322         /* TODO implement a local locking mechanism here */
323
324         return ret;
325 }
326
327 static int ildb_unlock(struct ldb_module *module, const char *lockname)
328 {
329         int ret = 0;
330
331         if (lockname == NULL) {
332                 return -1;
333         }
334
335         /* TODO implement a local unlocking mechanism here */
336
337         return ret;
338 }
339
340 /*
341   return extended error information
342 */
343 static const char *ildb_errstring(struct ldb_module *module)
344 {
345         struct ildb_private *ildb = talloc_get_type(module->private_data, 
346                                                     struct ildb_private);
347         if (ildb == NULL) {
348                 return "ildap not connected";
349         }
350         return ldap_errstr(ildb->ldap, ildb->last_rc);
351 }
352
353
354 static const struct ldb_module_ops ildb_ops = {
355         .name          = "ldap",
356         .search        = ildb_search,
357         .search_bytree = ildb_search_bytree,
358         .add_record    = ildb_add,
359         .modify_record = ildb_modify,
360         .delete_record = ildb_delete,
361         .rename_record = ildb_rename,
362         .named_lock    = ildb_lock,
363         .named_unlock  = ildb_unlock,
364         .errstring     = ildb_errstring
365 };
366
367
368 /*
369   fetch the rootDSE
370 */
371 static void ildb_rootdse(struct ldb_module *module)
372 {
373         struct ildb_private *ildb = module->private_data;
374         struct ldb_message **res = NULL;
375         int ret;
376         ret = ildb_search(module, "", LDB_SCOPE_BASE, "dn=dc=rootDSE", NULL, &res);
377         if (ret == 1) {
378                 ildb->rootDSE = talloc_steal(ildb, res[0]);
379         }
380         talloc_free(res);
381 }
382
383
384 /*
385   connect to the database
386 */
387 int ildb_connect(struct ldb_context *ldb, const char *url, 
388                  unsigned int flags, const char *options[])
389 {
390         struct ildb_private *ildb = NULL;
391         NTSTATUS status;
392
393         ildb = talloc(ldb, struct ildb_private);
394         if (!ildb) {
395                 ldb_oom(ldb);
396                 goto failed;
397         }
398
399         ildb->rootDSE = NULL;
400
401         ildb->ldap = ldap_new_connection(ildb, ldb_get_opaque(ldb, "EventContext"));
402         if (!ildb->ldap) {
403                 ldb_oom(ldb);
404                 goto failed;
405         }
406
407         status = ldap_connect(ildb->ldap, url);
408         if (!NT_STATUS_IS_OK(status)) {
409                 ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to connect to ldap URL '%s' - %s\n",
410                           url, ldap_errstr(ildb->ldap, status));
411                 goto failed;
412         }
413
414         ldb->modules = talloc(ldb, struct ldb_module);
415         if (!ldb->modules) {
416                 ldb_oom(ldb);
417                 goto failed;
418         }
419         ldb->modules->ldb = ldb;
420         ldb->modules->prev = ldb->modules->next = NULL;
421         ldb->modules->private_data = ildb;
422         ldb->modules->ops = &ildb_ops;
423
424         if (cmdline_credentials != NULL &&
425             cmdline_credentials->username_obtained > CRED_GUESSED) {
426                 status = ldap_bind_sasl(ildb->ldap, cmdline_credentials);
427                 if (!NT_STATUS_IS_OK(status)) {
428                         ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s\n",
429                                   ldap_errstr(ildb->ldap, status));
430                         goto failed;
431                 }
432         }
433
434         return 0;
435
436 failed:
437         if (ldb->modules) {
438                 ldb->modules->private_data = NULL;
439         }
440         talloc_free(ildb);
441         return -1;
442 }
443