r7726: - removed some unused variables
[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                 }
128         }
129
130         if (expression == NULL || expression[0] == '\0') {
131                 expression = "objectClass=*";
132         }
133
134         ildb->last_rc = ildap_search(ildb->ldap, base, scope, expression, attrs, 
135                                      0, &ldapres);
136         if (!NT_STATUS_IS_OK(ildb->last_rc)) {
137                 return -1;
138         }
139
140         count = ildap_count_entries(ildb->ldap, ldapres);
141         if (count == -1 || count == 0) {
142                 talloc_free(ldapres);
143                 return count;
144         }
145
146         (*res) = talloc_array(ildb, struct ldb_message *, count+1);
147         if (! *res) {
148                 talloc_free(ldapres);
149                 return -1;
150         }
151
152         (*res)[0] = NULL;
153
154         /* loop over all messages */
155         for (i=0;i<count;i++) {
156                 struct ldap_SearchResEntry *search;
157
158                 msg = ldapres[i];
159                 search = &msg->r.SearchResultEntry;
160
161                 (*res)[i] = talloc(*res, struct ldb_message);
162                 if (!(*res)[i]) {
163                         goto failed;
164                 }
165                 (*res)[i+1] = NULL;
166
167                 (*res)[i]->dn = talloc_steal((*res)[i], search->dn);
168                 (*res)[i]->num_elements = search->num_attributes;
169                 (*res)[i]->elements = talloc_steal((*res)[i], search->attributes);
170                 (*res)[i]->private_data = NULL;
171         }
172
173         talloc_free(ldapres);
174
175         return count;
176
177 failed:
178         if (*res) talloc_free(*res);
179         return -1;
180 }
181
182
183 /*
184   search for matching records using a ldb_parse_tree
185 */
186 static int ildb_search_bytree(struct ldb_module *module, const char *base,
187                               enum ldb_scope scope, struct ldb_parse_tree *tree,
188                               const char * const *attrs, struct ldb_message ***res)
189 {
190         struct ildb_private *ildb = module->private_data;
191         char *expression;
192         int ret;
193
194         expression = ldb_filter_from_tree(ildb, tree);
195         if (expression == NULL) {
196                 return -1;
197         }
198         ret = ildb_search(module, base, scope, expression, attrs, res);
199         talloc_free(expression);
200         return ret;
201 }
202
203
204 /*
205   convert a ldb_message structure to a list of ldap_mod structures
206   ready for ildap_add() or ildap_modify()
207 */
208 static struct ldap_mod **ildb_msg_to_mods(struct ldb_context *ldb,
209                                           const struct ldb_message *msg, int use_flags)
210 {
211         struct ldap_mod **mods;
212         unsigned int i;
213         int num_mods = 0;
214
215         /* allocate maximum number of elements needed */
216         mods = talloc_array(ldb, struct ldap_mod *, msg->num_elements+1);
217         if (!mods) {
218                 errno = ENOMEM;
219                 return NULL;
220         }
221         mods[0] = NULL;
222
223         for (i=0;i<msg->num_elements;i++) {
224                 const struct ldb_message_element *el = &msg->elements[i];
225
226                 mods[num_mods] = talloc(ldb, struct ldap_mod);
227                 if (!mods[num_mods]) {
228                         goto failed;
229                 }
230                 mods[num_mods+1] = NULL;
231                 mods[num_mods]->type = 0;
232                 mods[num_mods]->attrib = *el;
233                 if (use_flags) {
234                         switch (el->flags & LDB_FLAG_MOD_MASK) {
235                         case LDB_FLAG_MOD_ADD:
236                                 mods[num_mods]->type = LDAP_MODIFY_ADD;
237                                 break;
238                         case LDB_FLAG_MOD_DELETE:
239                                 mods[num_mods]->type = LDAP_MODIFY_DELETE;
240                                 break;
241                         case LDB_FLAG_MOD_REPLACE:
242                                 mods[num_mods]->type = LDAP_MODIFY_REPLACE;
243                                 break;
244                         }
245                 }
246                 num_mods++;
247         }
248
249         return mods;
250
251 failed:
252         talloc_free(mods);
253         return NULL;
254 }
255
256
257 /*
258   add a record
259 */
260 static int ildb_add(struct ldb_module *module, const struct ldb_message *msg)
261 {
262         struct ldb_context *ldb = module->ldb;
263         struct ildb_private *ildb = module->private_data;
264         struct ldap_mod **mods;
265         int ret = 0;
266
267         /* ignore ltdb specials */
268         if (msg->dn[0] == '@') {
269                 return 0;
270         }
271
272         mods = ildb_msg_to_mods(ldb, msg, 0);
273
274         ildb->last_rc = ildap_add(ildb->ldap, msg->dn, mods);
275         if (!NT_STATUS_IS_OK(ildb->last_rc)) {
276                 ret = -1;
277         }
278
279         talloc_free(mods);
280
281         return ret;
282 }
283
284
285 /*
286   modify a record
287 */
288 static int ildb_modify(struct ldb_module *module, const struct ldb_message *msg)
289 {
290         struct ldb_context *ldb = module->ldb;
291         struct ildb_private *ildb = module->private_data;
292         struct ldap_mod **mods;
293         int ret = 0;
294
295         /* ignore ltdb specials */
296         if (msg->dn[0] == '@') {
297                 return 0;
298         }
299
300         mods = ildb_msg_to_mods(ldb, msg, 1);
301
302         ildb->last_rc = ildap_modify(ildb->ldap, msg->dn, mods);
303         if (!NT_STATUS_IS_OK(ildb->last_rc)) {
304                 ret = -1;
305         }
306
307         talloc_free(mods);
308
309         return ret;
310 }
311
312 static int ildb_lock(struct ldb_module *module, const char *lockname)
313 {
314         int ret = 0;
315
316         if (lockname == NULL) {
317                 return -1;
318         }
319
320         /* TODO implement a local locking mechanism here */
321
322         return ret;
323 }
324
325 static int ildb_unlock(struct ldb_module *module, const char *lockname)
326 {
327         int ret = 0;
328
329         if (lockname == NULL) {
330                 return -1;
331         }
332
333         /* TODO implement a local unlocking mechanism here */
334
335         return ret;
336 }
337
338 /*
339   return extended error information
340 */
341 static const char *ildb_errstring(struct ldb_module *module)
342 {
343         struct ildb_private *ildb = talloc_get_type(module->private_data, 
344                                                     struct ildb_private);
345         if (ildb == NULL) {
346                 return "ildap not connected";
347         }
348         return ldap_errstr(ildb->ldap, ildb->last_rc);
349 }
350
351
352 static const struct ldb_module_ops ildb_ops = {
353         .name          = "ldap",
354         .search        = ildb_search,
355         .search_bytree = ildb_search_bytree,
356         .add_record    = ildb_add,
357         .modify_record = ildb_modify,
358         .delete_record = ildb_delete,
359         .rename_record = ildb_rename,
360         .named_lock    = ildb_lock,
361         .named_unlock  = ildb_unlock,
362         .errstring     = ildb_errstring
363 };
364
365
366 /*
367   fetch the rootDSE
368 */
369 static void ildb_rootdse(struct ldb_module *module)
370 {
371         struct ildb_private *ildb = module->private_data;
372         struct ldb_message **res = NULL;
373         int ret;
374         ret = ildb_search(module, "", LDB_SCOPE_BASE, "dn=dc=rootDSE", NULL, &res);
375         if (ret == 1) {
376                 ildb->rootDSE = talloc_steal(ildb, res[0]);
377         }
378         talloc_free(res);
379 }
380
381
382 /*
383   connect to the database
384 */
385 int ildb_connect(struct ldb_context *ldb, const char *url, 
386                  unsigned int flags, const char *options[])
387 {
388         struct ildb_private *ildb = NULL;
389         NTSTATUS status;
390
391         ildb = talloc(ldb, struct ildb_private);
392         if (!ildb) {
393                 ldb_oom(ldb);
394                 goto failed;
395         }
396
397         ildb->rootDSE = NULL;
398
399         ildb->ldap = ldap_new_connection(ildb, NULL);
400         if (!ildb->ldap) {
401                 ldb_oom(ldb);
402                 goto failed;
403         }
404
405         status = ldap_connect(ildb->ldap, url);
406         if (!NT_STATUS_IS_OK(status)) {
407                 ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to connect to ldap URL '%s' - %s\n",
408                           url, ldap_errstr(ildb->ldap, status));
409                 goto failed;
410         }
411
412         ldb->modules = talloc(ldb, struct ldb_module);
413         if (!ldb->modules) {
414                 ldb_oom(ldb);
415                 goto failed;
416         }
417         ldb->modules->ldb = ldb;
418         ldb->modules->prev = ldb->modules->next = NULL;
419         ldb->modules->private_data = ildb;
420         ldb->modules->ops = &ildb_ops;
421
422         if (cmdline_credentials->username_obtained > CRED_GUESSED) {
423                 status = ldap_bind_sasl(ildb->ldap, cmdline_credentials);
424                 if (!NT_STATUS_IS_OK(status)) {
425                         ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s\n",
426                                   ldap_errstr(ildb->ldap, status));
427                         goto failed;
428                 }
429         }
430
431         return 0;
432
433 failed:
434         if (ldb->modules) {
435                 ldb->modules->private_data = NULL;
436         }
437         talloc_free(ildb);
438         return -1;
439 }
440