r12323: fixeed the use of options.get_credentials() for ldb
[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 #include "lib/ldb/include/ldb_errors.h"
29 #include "lib/cmdline/popt_common.h"
30
31 /*
32   get the connected db
33  */
34 static struct ldb_context *ejs_get_ldb_context(int eid)
35 {
36         struct ldb_context *ldb = mprGetThisPtr(eid, "db");
37         if (ldb == NULL) {
38                 ejsSetErrorMsg(eid, "invalid ldb connection");
39         }
40         return ldb;
41 }
42
43 /*
44   perform an ldb search, returning an array of results
45
46   syntax:
47      res = ldb.search("expression");
48      var attrs = new Array("attr1", "attr2", "attr3");
49      ldb.search("expression", attrs);
50      var basedn = "cn=this,dc=is,dc=a,dc=test";
51      ldb.search("expression", attrs, ldb.SCOPE_SUBTREE, basedn);
52 */
53 static int ejs_ldbSearch(MprVarHandle eid, int argc, struct MprVar **argv)
54 {
55         const char **attrs = NULL;
56         const char *expression;
57         const char *base = NULL;
58         struct ldb_dn *basedn = NULL;
59         int scope = LDB_SCOPE_DEFAULT;
60         TALLOC_CTX *tmp_ctx = talloc_new(mprMemCtx());
61         struct ldb_context *ldb;
62         int ret;
63         struct ldb_result *res;
64
65         /* validate arguments */
66         if (argc < 1 || argc > 4) {
67                 ejsSetErrorMsg(eid, "ldb.search invalid number of arguments");
68                 goto failed;
69         }
70         if (argc > 3 && argv[3]->type != MPR_TYPE_OBJECT) {
71                 ejsSetErrorMsg(eid, "ldb.search attributes must be an object");
72                 goto failed;
73         }
74
75         ldb = ejs_get_ldb_context(eid);
76         if (ldb == NULL) {
77                 return -1;
78         }
79         
80         expression = mprToString(argv[0]);
81         if (argc > 1) {
82                 base = mprToString(argv[1]);
83                 /* a null basedn is valid */
84         }
85         if (base != NULL) {
86                 basedn = ldb_dn_explode(tmp_ctx, base);
87                 if (basedn == NULL) {
88                         ejsSetErrorMsg(eid, "ldb.search malformed base dn");
89                         goto failed;
90                 }
91         }
92         if (argc > 2) {
93                 scope = mprToInt(argv[2]);
94                 switch (scope) {
95                         case LDB_SCOPE_DEFAULT:
96                         case LDB_SCOPE_BASE:
97                         case LDB_SCOPE_ONELEVEL:
98                         case LDB_SCOPE_SUBTREE:
99                                 break; /* ok */
100                         default:
101                                 ejsSetErrorMsg(eid, "ldb.search invalid scope");
102                                 goto failed;
103                 }
104         }
105         if (argc > 3) {
106                 attrs = mprToList(tmp_ctx, argv[3]);
107         }
108         ret = ldb_search(ldb, basedn, scope, expression, attrs, &res);
109         if (ret != LDB_SUCCESS) {
110                 ejsSetErrorMsg(eid, "ldb.search failed - %s", ldb_errstring(ldb));
111                 mpr_Return(eid, mprCreateUndefinedVar());
112         } else {
113                 mpr_Return(eid, mprLdbArray(ldb, res->msgs, res->count, "ldb_message"));
114         }
115
116         talloc_free(tmp_ctx);
117         return 0;
118
119 failed:
120         talloc_free(tmp_ctx);
121         return -1;
122 }
123
124
125 /*
126   perform an ldb add or modify
127 */
128 static int ejs_ldbAddModify(MprVarHandle eid, int argc, struct MprVar **argv,
129                             int fn(struct ldb_context *, const struct ldb_message *))
130 {
131         const char *ldifstring;
132         struct ldb_context *ldb;
133         struct ldb_ldif *ldif;
134         int ret = 0, count=0;
135
136         if (argc != 1) {
137                 ejsSetErrorMsg(eid, "ldb.add/modify invalid arguments");
138                 return -1;
139         }
140
141         ldifstring = mprToString(argv[0]);
142         if (ldifstring == NULL) {
143                 ejsSetErrorMsg(eid, "ldb.add/modify invalid arguments");
144                 return -1;
145         }
146
147         ldb = ejs_get_ldb_context(eid);
148         if (ldb == NULL) {
149                 return -1;
150         }
151
152         while ((ldif = ldb_ldif_read_string(ldb, &ldifstring))) {
153                 count++;
154                 ret = fn(ldb, ldif->msg);
155                 talloc_free(ldif);
156                 if (ret != 0) break;
157         }
158
159         if (count == 0) {
160                 ejsSetErrorMsg(eid, "ldb.add/modify invalid ldif");
161                 return -1;
162         }
163
164         mpr_Return(eid, mprCreateBoolVar(ret == 0));
165         return 0;
166 }
167
168
169 /*
170   perform an ldb delete
171   usage:
172    ok = ldb.delete(dn);
173 */
174 static int ejs_ldbDelete(MprVarHandle eid, int argc, struct MprVar **argv)
175 {
176         struct ldb_dn *dn;
177         struct ldb_context *ldb;
178         int ret;
179
180         if (argc != 1) {
181                 ejsSetErrorMsg(eid, "ldb.delete invalid arguments");
182                 return -1;
183         }
184
185         ldb = ejs_get_ldb_context(eid);
186         if (ldb == NULL) {
187                 return -1;
188         }
189
190         dn = ldb_dn_explode(ldb, mprToString(argv[0]));
191         if (dn == NULL) {
192                 ejsSetErrorMsg(eid, "ldb.delete malformed dn");
193                 return -1;
194         }
195
196         ret = ldb_delete(ldb, dn);
197
198         talloc_free(dn);
199
200         mpr_Return(eid, mprCreateBoolVar(ret == 0));
201         return 0;
202 }
203
204 /*
205   perform an ldb rename
206   usage:
207    ok = ldb.rename(dn1, dn2);
208 */
209 static int ejs_ldbRename(MprVarHandle eid, int argc, struct MprVar **argv)
210 {
211         struct ldb_dn *dn1, *dn2;
212         struct ldb_context *ldb;
213         int ret;
214
215         if (argc != 2) {
216                 ejsSetErrorMsg(eid, "ldb.rename invalid arguments");
217                 return -1;
218         }
219
220         ldb = ejs_get_ldb_context(eid);
221         if (ldb == NULL) {
222                 return -1;
223         }
224
225         dn1 = ldb_dn_explode(ldb, mprToString(argv[0]));
226         dn2 = ldb_dn_explode(ldb, mprToString(argv[1]));
227         if (dn1 == NULL || dn2 == NULL) {
228                 ejsSetErrorMsg(eid, "ldb.rename invalid or malformed arguments");
229                 return -1;
230         }
231
232         ret = ldb_rename(ldb, dn1, dn2);
233
234         talloc_free(dn1);
235         talloc_free(dn2);
236
237         mpr_Return(eid, mprCreateBoolVar(ret == 0));
238         return 0;
239 }
240
241 /*
242   get last error message
243   usage:
244    ok = ldb.errstring();
245 */
246 static int ejs_ldbErrstring(MprVarHandle eid, int argc, struct MprVar **argv)
247 {
248         struct ldb_context *ldb;
249
250         ldb = ejs_get_ldb_context(eid);
251         if (ldb == NULL) {
252                 return -1;
253         }
254
255         mpr_Return(eid, mprString(ldb_errstring(ldb)));
256         return 0;
257 }
258
259 /* 
260    base64 encode 
261    usage: 
262     dataout = ldb.encode(datain)
263  */
264 static int ejs_base64encode(MprVarHandle eid, int argc, struct MprVar **argv)
265 {
266         char *ret;
267
268         if (argc != 1) {
269                 ejsSetErrorMsg(eid, "ldb.base64encode invalid argument count");
270                 return -1;
271         }
272
273         if (argv[0]->type == MPR_TYPE_STRING) {
274                 const char *orig = mprToString(argv[0]);
275                 ret = ldb_base64_encode(mprMemCtx(), orig, strlen(orig));
276         } else {
277                 DATA_BLOB *blob;
278
279                 blob = mprToDataBlob(argv[0]);
280                 mprAssert(blob);
281                 ret = ldb_base64_encode(mprMemCtx(), (char *)blob->data, blob->length);
282         }
283                 
284         if (!ret) {
285                 mpr_Return(eid, mprCreateUndefinedVar());
286         } else {
287                 mpr_Return(eid, mprString(ret));
288         }
289
290         talloc_free(ret);
291
292         return 0;
293 }
294
295 /* 
296    base64 decode
297    usage:
298      dataout = ldb.decode(datain)
299  */
300 static int ejs_base64decode(MprVarHandle eid, int argc, struct MprVar **argv)
301 {
302         char *tmp;
303         int ret;
304         
305         if (argc != 1) {
306                 ejsSetErrorMsg(eid, "ldb.base64encode invalid argument count");
307                 return -1;
308         }
309
310         tmp = talloc_strdup(mprMemCtx(), mprToString(argv[0]));
311         ret = ldb_base64_decode(tmp);
312         if (ret == -1) {
313                 mpr_Return(eid, mprCreateUndefinedVar());
314         } else {
315                 DATA_BLOB blob;
316                 blob.data = (uint8_t *)tmp;
317                 blob.length = ret;
318                 mpr_Return(eid, mprDataBlob(blob));
319         }
320
321         talloc_free(tmp);
322
323         return 0;
324 }
325   
326
327 /*
328   perform an ldb add 
329
330   syntax:
331     ok = ldb.add(ldifstring);
332 */
333 static int ejs_ldbAdd(MprVarHandle eid, int argc, struct MprVar **argv)
334 {
335         return ejs_ldbAddModify(eid, argc, argv, ldb_add);
336 }
337
338 /*
339   perform an ldb modify
340
341   syntax:
342     ok = ldb.modify(ldifstring);
343 */
344 static int ejs_ldbModify(MprVarHandle eid, int argc, struct MprVar **argv)
345 {
346         return ejs_ldbAddModify(eid, argc, argv, ldb_modify);
347 }
348
349 /*
350   connect to a database
351   usage:
352    ok = ldb.connect(dbfile);
353    ok = ldb.connect(dbfile, "modules:modlist");
354
355   ldb.credentials or ldb.session_info may be setup first
356
357 */
358 static int ejs_ldbConnect(MprVarHandle eid, int argc, char **argv)
359 {
360         struct ldb_context *ldb;
361         struct auth_session_info *session_info;
362         struct cli_credentials *creds;
363         struct MprVar *credentials;
364         struct MprVar *this = mprGetProperty(ejsGetLocalObject(eid), "this", 0);
365
366         const char *dbfile;
367
368         if (argc < 1) {
369                 ejsSetErrorMsg(eid, "ldb.connect invalid arguments");
370                 return -1;
371         }
372
373         session_info = mprGetThisPtr(eid, "session_info");
374
375         credentials = mprGetProperty(this, "credentials", NULL);
376         if (credentials) {
377                 creds = mprGetPtr(credentials, "creds");
378         } else {
379                 creds = cmdline_credentials;
380         }
381
382         dbfile = argv[0];
383
384         ldb = ldb_wrap_connect(mprMemCtx(), dbfile, 
385                                session_info, creds,
386                                0, (const char **)(argv+1));
387         if (ldb == NULL) {
388                 ejsSetErrorMsg(eid, "ldb.connect failed to open %s", dbfile);
389         }
390
391         mprSetThisPtr(eid, "db", ldb);
392         mpr_Return(eid, mprCreateBoolVar(ldb != NULL));
393         return 0;
394 }
395
396
397 /*
398   close a db connection
399 */
400 static int ejs_ldbClose(MprVarHandle eid, int argc, struct MprVar **argv)
401 {
402         struct ldb_context *ldb;
403
404         if (argc != 0) {
405                 ejsSetErrorMsg(eid, "ldb.close invalid arguments");
406                 return -1;
407         }
408
409         ldb = ejs_get_ldb_context(eid);
410         if (ldb == NULL) {
411                 return -1;
412         }
413
414         mprSetThisPtr(eid, "db", NULL);
415         mpr_Return(eid, mprCreateBoolVar(True));
416         return 0;
417 }
418
419
420 /*
421   start a ldb transaction
422   usage:
423    ok = ldb.transaction_start();
424 */
425 static int ejs_ldbTransactionStart(MprVarHandle eid, int argc, struct MprVar **argv)
426 {
427         struct ldb_context *ldb;
428         int ret;
429
430         if (argc != 0) {
431                 ejsSetErrorMsg(eid, "ldb.transaction_start invalid arguments");
432                 return -1;
433         }
434
435         ldb = ejs_get_ldb_context(eid);
436         if (ldb == NULL) {
437                 return -1;
438         }
439
440         ret = ldb_transaction_start(ldb);
441
442         mpr_Return(eid, mprCreateBoolVar(ret == 0));
443         return 0;
444 }
445
446 /*
447   cancel a ldb transaction
448   usage:
449    ok = ldb.transaction_cancel();
450 */
451 static int ejs_ldbTransactionCancel(MprVarHandle eid, int argc, struct MprVar **argv)
452 {
453         struct ldb_context *ldb;
454         int ret;
455
456         if (argc != 0) {
457                 ejsSetErrorMsg(eid, "ldb.transaction_cancel invalid arguments");
458                 return -1;
459         }
460
461         ldb = ejs_get_ldb_context(eid);
462         if (ldb == NULL) {
463                 return -1;
464         }
465
466         ret = ldb_transaction_cancel(ldb);
467
468         mpr_Return(eid, mprCreateBoolVar(ret == 0));
469         return 0;
470 }
471
472 /*
473   commit a ldb transaction
474   usage:
475    ok = ldb.transaction_commit();
476 */
477 static int ejs_ldbTransactionCommit(MprVarHandle eid, int argc, struct MprVar **argv)
478 {
479         struct ldb_context *ldb;
480         int ret;
481
482         if (argc != 0) {
483                 ejsSetErrorMsg(eid, "ldb.transaction_commit invalid arguments");
484                 return -1;
485         }
486
487         ldb = ejs_get_ldb_context(eid);
488         if (ldb == NULL) {
489                 return -1;
490         }
491
492         ret = ldb_transaction_commit(ldb);
493
494         mpr_Return(eid, mprCreateBoolVar(ret == 0));
495         return 0;
496 }
497
498 /*
499   initialise ldb ejs subsystem
500 */
501 static int ejs_ldb_init(MprVarHandle eid, int argc, struct MprVar **argv)
502 {
503         struct MprVar *ldb = mprInitObject(eid, "ldb", argc, argv);
504
505         mprSetStringCFunction(ldb, "connect", ejs_ldbConnect);
506         mprSetCFunction(ldb, "search", ejs_ldbSearch);
507         mprSetCFunction(ldb, "add", ejs_ldbAdd);
508         mprSetCFunction(ldb, "modify", ejs_ldbModify);
509         mprSetCFunction(ldb, "del", ejs_ldbDelete);
510         mprSetCFunction(ldb, "rename", ejs_ldbRename);
511         mprSetCFunction(ldb, "errstring", ejs_ldbErrstring);
512         mprSetCFunction(ldb, "encode", ejs_base64encode);
513         mprSetCFunction(ldb, "decode", ejs_base64decode);
514         mprSetCFunction(ldb, "close", ejs_ldbClose);
515         mprSetCFunction(ldb, "transaction_start", ejs_ldbTransactionStart);
516         mprSetCFunction(ldb, "transaction_cancel", ejs_ldbTransactionCancel);
517         mprSetCFunction(ldb, "transaction_commit", ejs_ldbTransactionCommit);
518         mprSetVar(ldb, "SCOPE_BASE", mprCreateNumberVar(LDB_SCOPE_BASE));
519         mprSetVar(ldb, "SCOPE_ONE", mprCreateNumberVar(LDB_SCOPE_ONELEVEL));
520         mprSetVar(ldb, "SCOPE_SUBTREE", mprCreateNumberVar(LDB_SCOPE_SUBTREE));
521         mprSetVar(ldb, "SCOPE_DEFAULT", mprCreateNumberVar(LDB_SCOPE_DEFAULT));
522
523         return 0;
524 }
525
526
527 /*
528   setup C functions that be called from ejs
529 */
530 void smb_setup_ejs_ldb(void)
531 {
532         ejsDefineCFunction(-1, "ldb_init", ejs_ldb_init, NULL, MPR_VAR_SCRIPT_HANDLE);
533 }