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