r24667: Finally merge the registry improvements that Wilco Baan Hofman and I have
[sfrench/samba-autobuild/.git] / source4 / scripting / ejs / smbcalls_ldb.c
index aaed14dd8cd408235e9aae1499ebecaa76129eb7..7b143ae4d93c41db8e583419b9ea8c8b7d7fec13 100644 (file)
@@ -4,10 +4,11 @@
    provide hooks into smbd C calls from ejs scripts
 
    Copyright (C) Andrew Tridgell 2005
+   Copyright (C) Jelmer Vernooij 2005
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 #include "scripting/ejs/smbcalls.h"
 #include "lib/appweb/ejs/ejs.h"
 #include "lib/ldb/include/ldb.h"
+#include "lib/ldb/include/ldb_errors.h"
+#include "db_wrap.h"
+#include "dsdb/samdb/samdb.h"
+#include "librpc/ndr/libndr.h"
 
 /*
   get the connected db
@@ -45,7 +49,8 @@ static struct ldb_context *ejs_get_ldb_context(int eid)
      var attrs = new Array("attr1", "attr2", "attr3");
      ldb.search("expression", attrs);
      var basedn = "cn=this,dc=is,dc=a,dc=test";
-     ldb.search("expression", attrs, ldb.SCOPE_SUBTREE, basedn);
+     ldb.search("expression", basedn, ldb.SCOPE_SUBTREE, attrs);
+     ldb.search("expression", basedn, ldb.SCOPE_SUBTREE, attrs, controls);
 */
 static int ejs_ldbSearch(MprVarHandle eid, int argc, struct MprVar **argv)
 {
@@ -57,10 +62,12 @@ static int ejs_ldbSearch(MprVarHandle eid, int argc, struct MprVar **argv)
        TALLOC_CTX *tmp_ctx = talloc_new(mprMemCtx());
        struct ldb_context *ldb;
        int ret;
-       struct ldb_message **res;
+       struct ldb_control **parsed_controls = NULL;
+       struct ldb_result *res=NULL;
+       struct ldb_request *req;
 
        /* validate arguments */
-       if (argc < 1 || argc > 4) {
+       if (argc < 1 || argc > 5) {
                ejsSetErrorMsg(eid, "ldb.search invalid number of arguments");
                goto failed;
        }
@@ -80,11 +87,13 @@ static int ejs_ldbSearch(MprVarHandle eid, int argc, struct MprVar **argv)
                /* a null basedn is valid */
        }
        if (base != NULL) {
-               basedn = ldb_dn_explode(tmp_ctx, base);
-               if (basedn == NULL) {
+               basedn = ldb_dn_new(tmp_ctx, ldb, base);
+               if ( ! ldb_dn_validate(basedn)) {
                        ejsSetErrorMsg(eid, "ldb.search malformed base dn");
                        goto failed;
                }
+       } else {
+               basedn = ldb_get_default_basedn(ldb);
        }
        if (argc > 2) {
                scope = mprToInt(argv[2]);
@@ -102,12 +111,49 @@ static int ejs_ldbSearch(MprVarHandle eid, int argc, struct MprVar **argv)
        if (argc > 3) {
                attrs = mprToList(tmp_ctx, argv[3]);
        }
-       ret = ldb_search(ldb, basedn, scope, expression, attrs, &res);
-       if (ret == -1) {
+       if (argc > 4) {
+               const char **controls;
+               controls = mprToList(tmp_ctx, argv[4]);
+               if (controls) {
+                       parsed_controls = ldb_parse_control_strings(ldb, tmp_ctx, controls);
+                       if (!parsed_controls) {
+                               ejsSetErrorMsg(eid, "ldb.search cannot parse controls: %s", 
+                                              ldb_errstring(ldb));
+                               goto failed;
+                       }
+               }
+       }
+
+       res = talloc_zero(tmp_ctx, struct ldb_result);
+       if (!res) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       ret = ldb_build_search_req(&req, ldb, tmp_ctx,
+                                  basedn,
+                                  scope,
+                                  expression,
+                                  attrs,
+                                  parsed_controls,
+                                  res,
+                                  ldb_search_default_callback);
+
+       if (ret == LDB_SUCCESS) {
+
+               ldb_set_timeout(ldb, req, 0); /* use default timeout */
+               
+               ret = ldb_request(ldb, req);
+               
+               if (ret == LDB_SUCCESS) {
+                       ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+               }
+       }
+
+       if (ret != LDB_SUCCESS) {
                ejsSetErrorMsg(eid, "ldb.search failed - %s", ldb_errstring(ldb));
-               mpr_Return(eid, mprCreateUndefinedVar());
+               mpr_Return(eid, mprLdbResult(ldb, ret, NULL));
        } else {
-               mpr_Return(eid, mprLdbArray(ldb, res, ret, "ldb_message"));
+               mpr_Return(eid, mprLdbResult(ldb, ret, res));
        }
 
        talloc_free(tmp_ctx);
@@ -128,7 +174,7 @@ static int ejs_ldbAddModify(MprVarHandle eid, int argc, struct MprVar **argv,
        const char *ldifstring;
        struct ldb_context *ldb;
        struct ldb_ldif *ldif;
-       int ret = 0;
+       int ret = 0, count=0;
 
        if (argc != 1) {
                ejsSetErrorMsg(eid, "ldb.add/modify invalid arguments");
@@ -147,12 +193,18 @@ static int ejs_ldbAddModify(MprVarHandle eid, int argc, struct MprVar **argv,
        }
 
        while ((ldif = ldb_ldif_read_string(ldb, &ldifstring))) {
+               count++;
                ret = fn(ldb, ldif->msg);
                talloc_free(ldif);
                if (ret != 0) break;
        }
 
-       mpr_Return(eid, mprCreateBoolVar(ret == 0));
+       if (count == 0) {
+               ejsSetErrorMsg(eid, "ldb.add/modify invalid ldif");
+               return -1;
+       }
+
+       mpr_Return(eid, mprLdbResult(ldb, ret, NULL));
        return 0;
 }
 
@@ -178,8 +230,8 @@ static int ejs_ldbDelete(MprVarHandle eid, int argc, struct MprVar **argv)
                return -1;
        }
 
-       dn = ldb_dn_explode(ldb, mprToString(argv[0]));
-       if (dn == NULL) {
+       dn = ldb_dn_new(ldb, ldb, mprToString(argv[0]));
+       if ( ! ldb_dn_validate(dn)) {
                ejsSetErrorMsg(eid, "ldb.delete malformed dn");
                return -1;
        }
@@ -188,7 +240,7 @@ static int ejs_ldbDelete(MprVarHandle eid, int argc, struct MprVar **argv)
 
        talloc_free(dn);
 
-       mpr_Return(eid, mprCreateBoolVar(ret == 0));
+       mpr_Return(eid, mprLdbResult(ldb, ret, NULL));
        return 0;
 }
 
@@ -213,9 +265,9 @@ static int ejs_ldbRename(MprVarHandle eid, int argc, struct MprVar **argv)
                return -1;
        }
 
-       dn1 = ldb_dn_explode(ldb, mprToString(argv[0]));
-       dn2 = ldb_dn_explode(ldb, mprToString(argv[1]));
-       if (dn1 == NULL || dn2 == NULL) {
+       dn1 = ldb_dn_new(ldb, ldb, mprToString(argv[0]));
+       dn2 = ldb_dn_new(ldb, ldb, mprToString(argv[1]));
+       if ( ! ldb_dn_validate(dn1) ||  ! ldb_dn_validate(dn2)) {
                ejsSetErrorMsg(eid, "ldb.rename invalid or malformed arguments");
                return -1;
        }
@@ -225,7 +277,7 @@ static int ejs_ldbRename(MprVarHandle eid, int argc, struct MprVar **argv)
        talloc_free(dn1);
        talloc_free(dn2);
 
-       mpr_Return(eid, mprCreateBoolVar(ret == 0));
+       mpr_Return(eid, mprLdbResult(ldb, ret, NULL));
        return 0;
 }
 
@@ -247,11 +299,106 @@ static int ejs_ldbErrstring(MprVarHandle eid, int argc, struct MprVar **argv)
        return 0;
 }
 
+/* 
+   base64 encode 
+   usage: 
+    dataout = ldb.encode(datain)
+ */
+static int ejs_base64encode(MprVarHandle eid, int argc, struct MprVar **argv)
+{
+       char *ret;
+
+       if (argc != 1) {
+               ejsSetErrorMsg(eid, "ldb.base64encode invalid argument count");
+               return -1;
+       }
+
+       if (argv[0]->type == MPR_TYPE_STRING) {
+               const char *orig = mprToString(argv[0]);
+               ret = ldb_base64_encode(mprMemCtx(), orig, strlen(orig));
+       } else {
+               DATA_BLOB *blob;
+
+               blob = mprToDataBlob(argv[0]);
+               mprAssert(blob);
+               ret = ldb_base64_encode(mprMemCtx(), (char *)blob->data, blob->length);
+       }
+               
+       if (!ret) {
+               mpr_Return(eid, mprCreateUndefinedVar());
+       } else {
+               mpr_Return(eid, mprString(ret));
+       }
+
+       talloc_free(ret);
+
+       return 0;
+}
+
+/* 
+   base64 decode
+   usage:
+     dataout = ldb.decode(datain)
+ */
+static int ejs_base64decode(MprVarHandle eid, int argc, struct MprVar **argv)
+{
+       char *tmp;
+       int ret;
+       
+       if (argc != 1) {
+               ejsSetErrorMsg(eid, "ldb.base64encode invalid argument count");
+               return -1;
+       }
+
+       tmp = talloc_strdup(mprMemCtx(), mprToString(argv[0]));
+       ret = ldb_base64_decode(tmp);
+       if (ret == -1) {
+               mpr_Return(eid, mprCreateUndefinedVar());
+       } else {
+               DATA_BLOB blob;
+               blob.data = (uint8_t *)tmp;
+               blob.length = ret;
+               mpr_Return(eid, mprDataBlob(blob));
+       }
+
+       talloc_free(tmp);
+
+       return 0;
+}
+
+/* 
+   escape a DN
+   usage:
+     dataout = ldb.dn_escape(datain)
+ */
+static int ejs_dn_escape(MprVarHandle eid, int argc, struct MprVar **argv)
+{
+       char *ret;
+       struct ldb_val val;
+       
+       if (argc != 1) {
+               ejsSetErrorMsg(eid, "ldb.dn_escape invalid argument count");
+               return -1;
+       }
+
+       val = data_blob_string_const(mprToString(argv[0]));
+
+       ret = ldb_dn_escape_value(mprMemCtx(), val);
+       if (ret == NULL) {
+               mpr_Return(eid, mprCreateUndefinedVar());
+       } else {
+               mpr_Return(eid, mprString(ret));
+               talloc_free(ret);
+       }
+
+       return 0;
+}
+
 /*
-  perform an ldb modify
+  perform an ldb add 
 
   syntax:
-    ok = ldb.modify(ldifstring);
+    ok = ldb.add(ldifstring);
 */
 static int ejs_ldbAdd(MprVarHandle eid, int argc, struct MprVar **argv)
 {
@@ -259,10 +406,10 @@ static int ejs_ldbAdd(MprVarHandle eid, int argc, struct MprVar **argv)
 }
 
 /*
-  perform an ldb add
+  perform an ldb modify
 
   syntax:
-    ok = ldb.add(ldifstring);
+    ok = ldb.modify(ldifstring);
 */
 static int ejs_ldbModify(MprVarHandle eid, int argc, struct MprVar **argv)
 {
@@ -274,10 +421,18 @@ static int ejs_ldbModify(MprVarHandle eid, int argc, struct MprVar **argv)
   usage:
    ok = ldb.connect(dbfile);
    ok = ldb.connect(dbfile, "modules:modlist");
+
+  ldb.credentials or ldb.session_info may be setup first
+
 */
 static int ejs_ldbConnect(MprVarHandle eid, int argc, char **argv)
 {
        struct ldb_context *ldb;
+       struct auth_session_info *session_info = NULL;
+       struct cli_credentials *creds = NULL;
+       struct MprVar *credentials, *session;
+       struct MprVar *this = mprGetProperty(ejsGetLocalObject(eid), "this", 0);
+
        const char *dbfile;
 
        if (argc < 1) {
@@ -285,9 +440,21 @@ static int ejs_ldbConnect(MprVarHandle eid, int argc, char **argv)
                return -1;
        }
 
+       credentials = mprGetProperty(this, "credentials", NULL);
+       if (credentials) {
+               creds = talloc_get_type(mprGetPtr(credentials, "creds"), struct cli_credentials);
+       }
+
+       session = mprGetProperty(this, "session_info", NULL);
+       if (session) {
+               session_info = talloc_get_type(mprGetPtr(session, "session_info"), struct auth_session_info);
+       }
+
        dbfile = argv[0];
 
-       ldb = ldb_wrap_connect(mprMemCtx(), dbfile, 0, (const char **)(argv+1));
+       ldb = ldb_wrap_connect(mprMemCtx(), dbfile, 
+                              session_info, creds,
+                              0, (const char **)(argv+1));
        if (ldb == NULL) {
                ejsSetErrorMsg(eid, "ldb.connect failed to open %s", dbfile);
        }
@@ -298,6 +465,222 @@ static int ejs_ldbConnect(MprVarHandle eid, int argc, char **argv)
 }
 
 
+/*
+  close a db connection
+*/
+static int ejs_ldbClose(MprVarHandle eid, int argc, struct MprVar **argv)
+{
+       struct ldb_context *ldb;
+
+       if (argc != 0) {
+               ejsSetErrorMsg(eid, "ldb.close invalid arguments");
+               return -1;
+       }
+
+       ldb = ejs_get_ldb_context(eid);
+       if (ldb == NULL) {
+               return -1;
+       }
+
+       mprSetThisPtr(eid, "db", NULL);
+       mpr_Return(eid, mprCreateBoolVar(True));
+       return 0;
+}
+
+
+/*
+  start a ldb transaction
+  usage:
+   ok = ldb.transaction_start();
+*/
+static int ejs_ldbTransactionStart(MprVarHandle eid, int argc, struct MprVar **argv)
+{
+       struct ldb_context *ldb;
+       int ret;
+
+       if (argc != 0) {
+               ejsSetErrorMsg(eid, "ldb.transaction_start invalid arguments");
+               return -1;
+       }
+
+       ldb = ejs_get_ldb_context(eid);
+       if (ldb == NULL) {
+               return -1;
+       }
+
+       ret = ldb_transaction_start(ldb);
+
+       mpr_Return(eid, mprCreateBoolVar(ret == 0));
+       return 0;
+}
+
+/*
+  cancel a ldb transaction
+  usage:
+   ok = ldb.transaction_cancel();
+*/
+static int ejs_ldbTransactionCancel(MprVarHandle eid, int argc, struct MprVar **argv)
+{
+       struct ldb_context *ldb;
+       int ret;
+
+       if (argc != 0) {
+               ejsSetErrorMsg(eid, "ldb.transaction_cancel invalid arguments");
+               return -1;
+       }
+
+       ldb = ejs_get_ldb_context(eid);
+       if (ldb == NULL) {
+               return -1;
+       }
+
+       ret = ldb_transaction_cancel(ldb);
+
+       mpr_Return(eid, mprCreateBoolVar(ret == 0));
+       return 0;
+}
+
+/*
+  commit a ldb transaction
+  usage:
+   ok = ldb.transaction_commit();
+*/
+static int ejs_ldbTransactionCommit(MprVarHandle eid, int argc, struct MprVar **argv)
+{
+       struct ldb_context *ldb;
+       int ret;
+
+       if (argc != 0) {
+               ejsSetErrorMsg(eid, "ldb.transaction_commit invalid arguments");
+               return -1;
+       }
+
+       ldb = ejs_get_ldb_context(eid);
+       if (ldb == NULL) {
+               return -1;
+       }
+
+       ret = ldb_transaction_commit(ldb);
+
+       mpr_Return(eid, mprCreateBoolVar(ret == 0));
+       return 0;
+}
+
+/*
+  commit a ldb attach a dsdb_schema from ldif files
+  usage:
+   ok = ldb.attach_dsdb_schema_from_ldif("prefixMap ldif content", "definition ldif content")
+*/
+static int ejs_ldb_attach_dsdb_schema_from_ldif(MprVarHandle eid, int argc, char **argv)
+{
+       struct ldb_context *ldb;
+       WERROR status;
+       const char *pf;
+       const char *df;
+
+       if (argc != 2) {
+               ejsSetErrorMsg(eid, "ldb.attach_dsdb_schema_from_ldif invalid arguments");
+               return -1;
+       }
+
+       ldb = ejs_get_ldb_context(eid);
+       if (ldb == NULL) {
+               return -1;
+       }
+
+       pf = argv[0];
+       df = argv[1];
+
+       status = dsdb_attach_schema_from_ldif_file(ldb, pf, df);
+
+       mpr_Return(eid, mprWERROR(status));
+       return 0;
+}
+
+/*
+  commit a ldb attach a dsdb_schema from ldif files
+  usage:
+   ok = ldb.set_ntds_invocationId("7729aa4b-f990-41ad-b81a-8b6a14090f41");
+*/
+static int ejs_ldb_set_ntds_invocationId(MprVarHandle eid, int argc, char **argv)
+{
+       struct ldb_context *ldb;
+       NTSTATUS status;
+       struct GUID guid;
+       char *guid_str;
+       bool ok;
+
+       if (argc != 1) {
+               ejsSetErrorMsg(eid, "ldb.set_ntds_invocationId invalid arguments");
+               return -1;
+       }
+
+       ldb = ejs_get_ldb_context(eid);
+       if (ldb == NULL) {
+               return -1;
+       }
+
+       guid_str = argv[0];
+
+       status = GUID_from_string(guid_str, &guid);
+       if (!NT_STATUS_IS_OK(status)) {
+               ejsSetErrorMsg(eid, "ldb.set_ntds_invocationId - failed to parse GUID '%s' %s\n",
+                               guid_str, nt_errstr(status));
+               return -1;
+       }
+
+       ok = samdb_set_ntds_invocation_id(ldb, &guid);
+       if (!ok) {
+               ejsSetErrorMsg(eid, "ldb.set_ntds_invocationId - failed to set cached ntds invocationId\n");
+               return -1;
+       }
+
+       mpr_Return(eid, mprCreateBoolVar(ok));
+       return 0;
+}
+
+/*
+  commit a ldb attach a dsdb_schema from ldif files
+  usage:
+   ok = ldb.get_ntds_objectGUID("7729aa4b-f990-41ad-b81a-8b6a14090f41");
+*/
+static int ejs_ldb_set_ntds_objectGUID(MprVarHandle eid, int argc, char **argv)
+{
+       struct ldb_context *ldb;
+       NTSTATUS status;
+       struct GUID guid;
+       char *guid_str;
+       bool ok;
+
+       if (argc != 1) {
+               ejsSetErrorMsg(eid, "ldb.set_ntds_objectGUID invalid arguments");
+               return -1;
+       }
+
+       ldb = ejs_get_ldb_context(eid);
+       if (ldb == NULL) {
+               return -1;
+       }
+
+       guid_str = argv[0];
+
+       status = GUID_from_string(guid_str, &guid);
+       if (!NT_STATUS_IS_OK(status)) {
+               ejsSetErrorMsg(eid, "ldb.set_ntds_objectGUID - failed to parse GUID '%s' %s\n",
+                               guid_str, nt_errstr(status));
+               return -1;
+       }
+
+       ok = samdb_set_ntds_invocation_id(ldb, &guid);
+       if (!ok) {
+               ejsSetErrorMsg(eid, "ldb.set_ntds_objectGUID - failed to set cached ntds invocationId\n");
+               return -1;
+       }
+
+       mpr_Return(eid, mprCreateBoolVar(ok));
+       return 0;
+}
+
 /*
   initialise ldb ejs subsystem
 */
@@ -312,9 +695,23 @@ static int ejs_ldb_init(MprVarHandle eid, int argc, struct MprVar **argv)
        mprSetCFunction(ldb, "del", ejs_ldbDelete);
        mprSetCFunction(ldb, "rename", ejs_ldbRename);
        mprSetCFunction(ldb, "errstring", ejs_ldbErrstring);
+       mprSetCFunction(ldb, "encode", ejs_base64encode);
+       mprSetCFunction(ldb, "decode", ejs_base64decode);
+       mprSetCFunction(ldb, "dn_escape", ejs_dn_escape);
+       mprSetCFunction(ldb, "close", ejs_ldbClose);
+       mprSetCFunction(ldb, "transaction_start", ejs_ldbTransactionStart);
+       mprSetCFunction(ldb, "transaction_cancel", ejs_ldbTransactionCancel);
+       mprSetCFunction(ldb, "transaction_commit", ejs_ldbTransactionCommit);
+       mprSetStringCFunction(ldb, "attach_dsdb_schema_from_ldif",
+                             ejs_ldb_attach_dsdb_schema_from_ldif);
+       mprSetStringCFunction(ldb, "set_ntds_invocationId",
+                             ejs_ldb_set_ntds_invocationId);
+       mprSetStringCFunction(ldb, "set_ntds_objectGUID",
+                             ejs_ldb_set_ntds_objectGUID);
        mprSetVar(ldb, "SCOPE_BASE", mprCreateNumberVar(LDB_SCOPE_BASE));
        mprSetVar(ldb, "SCOPE_ONE", mprCreateNumberVar(LDB_SCOPE_ONELEVEL));
        mprSetVar(ldb, "SCOPE_SUBTREE", mprCreateNumberVar(LDB_SCOPE_SUBTREE));
+       mprSetVar(ldb, "SCOPE_DEFAULT", mprCreateNumberVar(LDB_SCOPE_DEFAULT));
 
        return 0;
 }
@@ -323,7 +720,8 @@ static int ejs_ldb_init(MprVarHandle eid, int argc, struct MprVar **argv)
 /*
   setup C functions that be called from ejs
 */
-void smb_setup_ejs_ldb(void)
+NTSTATUS smb_setup_ejs_ldb(void)
 {
        ejsDefineCFunction(-1, "ldb_init", ejs_ldb_init, NULL, MPR_VAR_SCRIPT_HANDLE);
+       return NT_STATUS_OK;
 }