39698947d7be59905fac8c53e7e6da27aa47d8e8
[kai/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    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    escape a DN
328    usage:
329      dataout = ldb.dn_escape(datain)
330  */
331 static int ejs_dn_escape(MprVarHandle eid, int argc, struct MprVar **argv)
332 {
333         char *ret;
334         struct ldb_val val;
335         
336         if (argc != 1) {
337                 ejsSetErrorMsg(eid, "ldb.dn_escape invalid argument count");
338                 return -1;
339         }
340
341         val = data_blob_string_const(mprToString(argv[0]));
342
343         ret = ldb_dn_escape_value(mprMemCtx(), val);
344         if (ret == NULL) {
345                 mpr_Return(eid, mprCreateUndefinedVar());
346         } else {
347                 mpr_Return(eid, mprString(ret));
348                 talloc_free(ret);
349         }
350
351         return 0;
352 }
353
354 /*
355   perform an ldb add 
356
357   syntax:
358     ok = ldb.add(ldifstring);
359 */
360 static int ejs_ldbAdd(MprVarHandle eid, int argc, struct MprVar **argv)
361 {
362         return ejs_ldbAddModify(eid, argc, argv, ldb_add);
363 }
364
365 /*
366   perform an ldb modify
367
368   syntax:
369     ok = ldb.modify(ldifstring);
370 */
371 static int ejs_ldbModify(MprVarHandle eid, int argc, struct MprVar **argv)
372 {
373         return ejs_ldbAddModify(eid, argc, argv, ldb_modify);
374 }
375
376 /*
377   connect to a database
378   usage:
379    ok = ldb.connect(dbfile);
380    ok = ldb.connect(dbfile, "modules:modlist");
381
382   ldb.credentials or ldb.session_info may be setup first
383
384 */
385 static int ejs_ldbConnect(MprVarHandle eid, int argc, char **argv)
386 {
387         struct ldb_context *ldb;
388         struct auth_session_info *session_info = NULL;
389         struct cli_credentials *creds = NULL;
390         struct MprVar *credentials, *session;
391         struct MprVar *this = mprGetProperty(ejsGetLocalObject(eid), "this", 0);
392
393         const char *dbfile;
394
395         if (argc < 1) {
396                 ejsSetErrorMsg(eid, "ldb.connect invalid arguments");
397                 return -1;
398         }
399
400         credentials = mprGetProperty(this, "credentials", NULL);
401         if (credentials) {
402                 creds = mprGetPtr(credentials, "creds");
403         }
404
405         session = mprGetProperty(this, "session_info", NULL);
406         if (session) {
407                 session_info = mprGetPtr(session, "session_info");
408         }
409
410         dbfile = argv[0];
411
412         ldb = ldb_wrap_connect(mprMemCtx(), dbfile, 
413                                session_info, creds,
414                                0, (const char **)(argv+1));
415         if (ldb == NULL) {
416                 ejsSetErrorMsg(eid, "ldb.connect failed to open %s", dbfile);
417         }
418
419         mprSetThisPtr(eid, "db", ldb);
420         mpr_Return(eid, mprCreateBoolVar(ldb != NULL));
421         return 0;
422 }
423
424
425 /*
426   close a db connection
427 */
428 static int ejs_ldbClose(MprVarHandle eid, int argc, struct MprVar **argv)
429 {
430         struct ldb_context *ldb;
431
432         if (argc != 0) {
433                 ejsSetErrorMsg(eid, "ldb.close invalid arguments");
434                 return -1;
435         }
436
437         ldb = ejs_get_ldb_context(eid);
438         if (ldb == NULL) {
439                 return -1;
440         }
441
442         mprSetThisPtr(eid, "db", NULL);
443         mpr_Return(eid, mprCreateBoolVar(True));
444         return 0;
445 }
446
447
448 /*
449   start a ldb transaction
450   usage:
451    ok = ldb.transaction_start();
452 */
453 static int ejs_ldbTransactionStart(MprVarHandle eid, int argc, struct MprVar **argv)
454 {
455         struct ldb_context *ldb;
456         int ret;
457
458         if (argc != 0) {
459                 ejsSetErrorMsg(eid, "ldb.transaction_start invalid arguments");
460                 return -1;
461         }
462
463         ldb = ejs_get_ldb_context(eid);
464         if (ldb == NULL) {
465                 return -1;
466         }
467
468         ret = ldb_transaction_start(ldb);
469
470         mpr_Return(eid, mprCreateBoolVar(ret == 0));
471         return 0;
472 }
473
474 /*
475   cancel a ldb transaction
476   usage:
477    ok = ldb.transaction_cancel();
478 */
479 static int ejs_ldbTransactionCancel(MprVarHandle eid, int argc, struct MprVar **argv)
480 {
481         struct ldb_context *ldb;
482         int ret;
483
484         if (argc != 0) {
485                 ejsSetErrorMsg(eid, "ldb.transaction_cancel invalid arguments");
486                 return -1;
487         }
488
489         ldb = ejs_get_ldb_context(eid);
490         if (ldb == NULL) {
491                 return -1;
492         }
493
494         ret = ldb_transaction_cancel(ldb);
495
496         mpr_Return(eid, mprCreateBoolVar(ret == 0));
497         return 0;
498 }
499
500 /*
501   commit a ldb transaction
502   usage:
503    ok = ldb.transaction_commit();
504 */
505 static int ejs_ldbTransactionCommit(MprVarHandle eid, int argc, struct MprVar **argv)
506 {
507         struct ldb_context *ldb;
508         int ret;
509
510         if (argc != 0) {
511                 ejsSetErrorMsg(eid, "ldb.transaction_commit invalid arguments");
512                 return -1;
513         }
514
515         ldb = ejs_get_ldb_context(eid);
516         if (ldb == NULL) {
517                 return -1;
518         }
519
520         ret = ldb_transaction_commit(ldb);
521
522         mpr_Return(eid, mprCreateBoolVar(ret == 0));
523         return 0;
524 }
525
526 /*
527   initialise ldb ejs subsystem
528 */
529 static int ejs_ldb_init(MprVarHandle eid, int argc, struct MprVar **argv)
530 {
531         struct MprVar *ldb = mprInitObject(eid, "ldb", argc, argv);
532
533         mprSetStringCFunction(ldb, "connect", ejs_ldbConnect);
534         mprSetCFunction(ldb, "search", ejs_ldbSearch);
535         mprSetCFunction(ldb, "add", ejs_ldbAdd);
536         mprSetCFunction(ldb, "modify", ejs_ldbModify);
537         mprSetCFunction(ldb, "del", ejs_ldbDelete);
538         mprSetCFunction(ldb, "rename", ejs_ldbRename);
539         mprSetCFunction(ldb, "errstring", ejs_ldbErrstring);
540         mprSetCFunction(ldb, "encode", ejs_base64encode);
541         mprSetCFunction(ldb, "decode", ejs_base64decode);
542         mprSetCFunction(ldb, "dn_escape", ejs_dn_escape);
543         mprSetCFunction(ldb, "close", ejs_ldbClose);
544         mprSetCFunction(ldb, "transaction_start", ejs_ldbTransactionStart);
545         mprSetCFunction(ldb, "transaction_cancel", ejs_ldbTransactionCancel);
546         mprSetCFunction(ldb, "transaction_commit", ejs_ldbTransactionCommit);
547         mprSetVar(ldb, "SCOPE_BASE", mprCreateNumberVar(LDB_SCOPE_BASE));
548         mprSetVar(ldb, "SCOPE_ONE", mprCreateNumberVar(LDB_SCOPE_ONELEVEL));
549         mprSetVar(ldb, "SCOPE_SUBTREE", mprCreateNumberVar(LDB_SCOPE_SUBTREE));
550         mprSetVar(ldb, "SCOPE_DEFAULT", mprCreateNumberVar(LDB_SCOPE_DEFAULT));
551
552         return 0;
553 }
554
555
556 /*
557   setup C functions that be called from ejs
558 */
559 void smb_setup_ejs_ldb(void)
560 {
561         ejsDefineCFunction(-1, "ldb_init", ejs_ldb_init, NULL, MPR_VAR_SCRIPT_HANDLE);
562 }