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