r9762: Add support for reading good old smbpasswd files
[sfrench/samba-autobuild/.git] / source4 / scripting / ejs / smbcalls_ldb.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    provide hooks into smbd C calls from ejs scripts
5
6    Copyright (C) Andrew Tridgell 2005
7    Copyright (C) Jelmer Vernooij 2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "scripting/ejs/smbcalls.h"
26 #include "lib/appweb/ejs/ejs.h"
27 #include "lib/ldb/include/ldb.h"
28
29 /*
30   get the connected db
31  */
32 static struct ldb_context *ejs_get_ldb_context(int eid)
33 {
34         struct ldb_context *ldb = mprGetThisPtr(eid, "db");
35         if (ldb == NULL) {
36                 ejsSetErrorMsg(eid, "invalid ldb connection");
37         }
38         return ldb;
39 }
40
41 /*
42   perform an ldb search, returning an array of results
43
44   syntax:
45      res = ldb.search("expression");
46      var attrs = new Array("attr1", "attr2", "attr3");
47      ldb.search("expression", attrs);
48      var basedn = "cn=this,dc=is,dc=a,dc=test";
49      ldb.search("expression", attrs, ldb.SCOPE_SUBTREE, basedn);
50 */
51 static int ejs_ldbSearch(MprVarHandle eid, int argc, struct MprVar **argv)
52 {
53         const char **attrs = NULL;
54         const char *expression;
55         const char *base = NULL;
56         struct ldb_dn *basedn = NULL;
57         int scope = LDB_SCOPE_DEFAULT;
58         TALLOC_CTX *tmp_ctx = talloc_new(mprMemCtx());
59         struct ldb_context *ldb;
60         int ret;
61         struct ldb_message **res;
62
63         /* validate arguments */
64         if (argc < 1 || argc > 4) {
65                 ejsSetErrorMsg(eid, "ldb.search invalid number of arguments");
66                 goto failed;
67         }
68         if (argc > 3 && argv[3]->type != MPR_TYPE_OBJECT) {
69                 ejsSetErrorMsg(eid, "ldb.search attributes must be an object");
70                 goto failed;
71         }
72
73         ldb = ejs_get_ldb_context(eid);
74         if (ldb == NULL) {
75                 return -1;
76         }
77         
78         expression = mprToString(argv[0]);
79         if (argc > 1) {
80                 base = mprToString(argv[1]);
81                 /* a null basedn is valid */
82         }
83         if (base != NULL) {
84                 basedn = ldb_dn_explode(tmp_ctx, base);
85                 if (basedn == NULL) {
86                         ejsSetErrorMsg(eid, "ldb.search malformed base dn");
87                         goto failed;
88                 }
89         }
90         if (argc > 2) {
91                 scope = mprToInt(argv[2]);
92                 switch (scope) {
93                         case LDB_SCOPE_DEFAULT:
94                         case LDB_SCOPE_BASE:
95                         case LDB_SCOPE_ONELEVEL:
96                         case LDB_SCOPE_SUBTREE:
97                                 break; /* ok */
98                         default:
99                                 ejsSetErrorMsg(eid, "ldb.search invalid scope");
100                                 goto failed;
101                 }
102         }
103         if (argc > 3) {
104                 attrs = mprToList(tmp_ctx, argv[3]);
105         }
106         ret = ldb_search(ldb, basedn, scope, expression, attrs, &res);
107         if (ret == -1) {
108                 ejsSetErrorMsg(eid, "ldb.search failed - %s", ldb_errstring(ldb));
109                 mpr_Return(eid, mprCreateUndefinedVar());
110         } else {
111                 mpr_Return(eid, mprLdbArray(ldb, res, ret, "ldb_message"));
112         }
113
114         talloc_free(tmp_ctx);
115         return 0;
116
117 failed:
118         talloc_free(tmp_ctx);
119         return -1;
120 }
121
122
123 /*
124   perform an ldb add or modify
125 */
126 static int ejs_ldbAddModify(MprVarHandle eid, int argc, struct MprVar **argv,
127                             int fn(struct ldb_context *, const struct ldb_message *))
128 {
129         const char *ldifstring;
130         struct ldb_context *ldb;
131         struct ldb_ldif *ldif;
132         int ret = 0;
133
134         if (argc != 1) {
135                 ejsSetErrorMsg(eid, "ldb.add/modify invalid arguments");
136                 return -1;
137         }
138
139         ldifstring = mprToString(argv[0]);
140         if (ldifstring == NULL) {
141                 ejsSetErrorMsg(eid, "ldb.add/modify invalid arguments");
142                 return -1;
143         }
144
145         ldb = ejs_get_ldb_context(eid);
146         if (ldb == NULL) {
147                 return -1;
148         }
149
150         while ((ldif = ldb_ldif_read_string(ldb, &ldifstring))) {
151                 ret = fn(ldb, ldif->msg);
152                 talloc_free(ldif);
153                 if (ret != 0) break;
154         }
155
156         mpr_Return(eid, mprCreateBoolVar(ret == 0));
157         return 0;
158 }
159
160
161 /*
162   perform an ldb delete
163   usage:
164    ok = ldb.delete(dn);
165 */
166 static int ejs_ldbDelete(MprVarHandle eid, int argc, struct MprVar **argv)
167 {
168         struct ldb_dn *dn;
169         struct ldb_context *ldb;
170         int ret;
171
172         if (argc != 1) {
173                 ejsSetErrorMsg(eid, "ldb.delete invalid arguments");
174                 return -1;
175         }
176
177         ldb = ejs_get_ldb_context(eid);
178         if (ldb == NULL) {
179                 return -1;
180         }
181
182         dn = ldb_dn_explode(ldb, mprToString(argv[0]));
183         if (dn == NULL) {
184                 ejsSetErrorMsg(eid, "ldb.delete malformed dn");
185                 return -1;
186         }
187
188         ret = ldb_delete(ldb, dn);
189
190         talloc_free(dn);
191
192         mpr_Return(eid, mprCreateBoolVar(ret == 0));
193         return 0;
194 }
195
196 /*
197   perform an ldb rename
198   usage:
199    ok = ldb.rename(dn1, dn2);
200 */
201 static int ejs_ldbRename(MprVarHandle eid, int argc, struct MprVar **argv)
202 {
203         struct ldb_dn *dn1, *dn2;
204         struct ldb_context *ldb;
205         int ret;
206
207         if (argc != 2) {
208                 ejsSetErrorMsg(eid, "ldb.rename invalid arguments");
209                 return -1;
210         }
211
212         ldb = ejs_get_ldb_context(eid);
213         if (ldb == NULL) {
214                 return -1;
215         }
216
217         dn1 = ldb_dn_explode(ldb, mprToString(argv[0]));
218         dn2 = ldb_dn_explode(ldb, mprToString(argv[1]));
219         if (dn1 == NULL || dn2 == NULL) {
220                 ejsSetErrorMsg(eid, "ldb.rename invalid or malformed arguments");
221                 return -1;
222         }
223
224         ret = ldb_rename(ldb, dn1, dn2);
225
226         talloc_free(dn1);
227         talloc_free(dn2);
228
229         mpr_Return(eid, mprCreateBoolVar(ret == 0));
230         return 0;
231 }
232
233 /*
234   get last error message
235   usage:
236    ok = ldb.errstring();
237 */
238 static int ejs_ldbErrstring(MprVarHandle eid, int argc, struct MprVar **argv)
239 {
240         struct ldb_context *ldb;
241
242         ldb = ejs_get_ldb_context(eid);
243         if (ldb == NULL) {
244                 return -1;
245         }
246
247         mpr_Return(eid, mprString(ldb_errstring(ldb)));
248         return 0;
249 }
250
251 /* 
252    base64 encode 
253    usage: 
254     dataout = ldb.encode(datain)
255  */
256 static int ejs_base64encode(MprVarHandle eid, int argc, struct MprVar **argv)
257 {
258         char *ret;
259         DATA_BLOB *blob;
260
261         if (argc != 1) {
262                 ejsSetErrorMsg(eid, "ldb.base64encode invalid argument count");
263                 return -1;
264         }
265
266         blob = mprToDataBlob(argv[0]);
267         ret = ldb_base64_encode(mprMemCtx(), (char *)blob->data, blob->length);
268
269         if (!ret) {
270                 mpr_Return(eid, mprCreateUndefinedVar());
271         } else {
272                 mpr_Return(eid, mprString(ret));
273         }
274
275         talloc_free(ret);
276
277         return 0;
278 }
279
280 /* 
281    base64 decode
282    usage:
283      dataout = ldb.decode(datain)
284  */
285 static int ejs_base64decode(MprVarHandle eid, int argc, struct MprVar **argv)
286 {
287         char *tmp;
288         int ret;
289         
290         if (argc != 1) {
291                 ejsSetErrorMsg(eid, "ldb.base64encode invalid argument count");
292                 return -1;
293         }
294
295         tmp = talloc_strdup(mprMemCtx(), mprToString(argv[0]));
296         ret = ldb_base64_decode(tmp);
297         if (ret == -1) {
298                 mpr_Return(eid, mprCreateUndefinedVar());
299         } else {
300                 mpr_Return(eid, mprData((uint8_t *)tmp, ret));
301         }
302
303         talloc_free(tmp);
304
305         return 0;
306 }
307   
308
309 /*
310   perform an ldb modify
311
312   syntax:
313     ok = ldb.modify(ldifstring);
314 */
315 static int ejs_ldbAdd(MprVarHandle eid, int argc, struct MprVar **argv)
316 {
317         return ejs_ldbAddModify(eid, argc, argv, ldb_add);
318 }
319
320 /*
321   perform an ldb add
322
323   syntax:
324     ok = ldb.add(ldifstring);
325 */
326 static int ejs_ldbModify(MprVarHandle eid, int argc, struct MprVar **argv)
327 {
328         return ejs_ldbAddModify(eid, argc, argv, ldb_modify);
329 }
330
331 /*
332   connect to a database
333   usage:
334    ok = ldb.connect(dbfile);
335    ok = ldb.connect(dbfile, "modules:modlist");
336 */
337 static int ejs_ldbConnect(MprVarHandle eid, int argc, char **argv)
338 {
339         struct ldb_context *ldb;
340         const char *dbfile;
341
342         if (argc < 1) {
343                 ejsSetErrorMsg(eid, "ldb.connect invalid arguments");
344                 return -1;
345         }
346
347         dbfile = argv[0];
348
349         ldb = ldb_wrap_connect(mprMemCtx(), dbfile, 0, (const char **)(argv+1));
350         if (ldb == NULL) {
351                 ejsSetErrorMsg(eid, "ldb.connect failed to open %s", dbfile);
352         }
353
354         mprSetThisPtr(eid, "db", ldb);
355         mpr_Return(eid, mprCreateBoolVar(ldb != NULL));
356         return 0;
357 }
358
359
360 /*
361   initialise ldb ejs subsystem
362 */
363 static int ejs_ldb_init(MprVarHandle eid, int argc, struct MprVar **argv)
364 {
365         struct MprVar *ldb = mprInitObject(eid, "ldb", argc, argv);
366
367         mprSetStringCFunction(ldb, "connect", ejs_ldbConnect);
368         mprSetCFunction(ldb, "search", ejs_ldbSearch);
369         mprSetCFunction(ldb, "add", ejs_ldbAdd);
370         mprSetCFunction(ldb, "modify", ejs_ldbModify);
371         mprSetCFunction(ldb, "del", ejs_ldbDelete);
372         mprSetCFunction(ldb, "rename", ejs_ldbRename);
373         mprSetCFunction(ldb, "errstring", ejs_ldbErrstring);
374         mprSetCFunction(ldb, "encode", ejs_base64encode);
375         mprSetCFunction(ldb, "decode", ejs_base64decode);
376         mprSetVar(ldb, "SCOPE_BASE", mprCreateNumberVar(LDB_SCOPE_BASE));
377         mprSetVar(ldb, "SCOPE_ONE", mprCreateNumberVar(LDB_SCOPE_ONELEVEL));
378         mprSetVar(ldb, "SCOPE_SUBTREE", mprCreateNumberVar(LDB_SCOPE_SUBTREE));
379
380         return 0;
381 }
382
383
384 /*
385   setup C functions that be called from ejs
386 */
387 void smb_setup_ejs_ldb(void)
388 {
389         ejsDefineCFunction(-1, "ldb_init", ejs_ldb_init, NULL, MPR_VAR_SCRIPT_HANDLE);
390 }