summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDerrell Lipman <derrell@samba.org>2006-10-07 20:35:59 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 14:20:48 -0500
commit9ee311c39fdefc8d723e8ea718f06df9c6159621 (patch)
treed6607561bedb1086f6054996a7f8675d2c93493c
parent7bdfbd608c86b89ab6c7e98f8a01285acec53efb (diff)
downloadsamba-9ee311c39fdefc8d723e8ea718f06df9c6159621.tar.gz
samba-9ee311c39fdefc8d723e8ea718f06df9c6159621.tar.bz2
samba-9ee311c39fdefc8d723e8ea718f06df9c6159621.zip
r19167: - Various JSON-RPC facilities will desire to keep resources open in a
session. Provide a common method of doing this, which allows limiting, somewhat (at least on a per-session basis) the possibility of DOS attacks. - Add bindings for LDB functions, so they can be called via JSON-RPC (This used to be commit 38d64118d17e20dc625c8262b2f667927daeac0d)
-rw-r--r--services/resources.esp161
-rw-r--r--services/samba/ldb.esp610
-rw-r--r--services/samba/system.esp34
3 files changed, 805 insertions, 0 deletions
diff --git a/services/resources.esp b/services/resources.esp
new file mode 100644
index 0000000000..d4a77f7907
--- /dev/null
+++ b/services/resources.esp
@@ -0,0 +1,161 @@
+<%
+
+/*
+ * Various JSON-RPC calls will want to maintain open resources within a
+ * session, across multiple calls. We'll provide a standardized way to
+ * maintain those open resources here, with some protection against rogue
+ * scripts.
+ */
+
+function _resourcesCreate()
+{
+ /* The being-created resources object */
+ var o = new Object();
+
+ /*
+ * The maximum number of resources available to a single session. This
+ * should be more than is ever needed (even by reasonable recursive
+ * functions) but limits rogue scripts ability to generate DOS attacks.
+ */
+ o.RESOURCE_LIMIT = 100;
+
+ /* List of current resources */
+ o.resourceList = new Object();
+
+ /* Resource id values will be constantly incrementing; never reset. */
+ o.resourceList.id = 0;
+
+ /* We'll maintain our own count of the number of open resources */
+ o.resourceList.count = 0;
+
+ /*
+ * Resource types
+ */
+ o.Type = new Object();
+ o.Type.ldb = 1; /* database handle */
+ o.Type.tid = 2; /* tree id */
+ o.Type.fid = 3; /* file id */
+ /* etc., etc., etc. */
+
+
+ /*
+ * Set a new saved resource.
+ */
+ function _set(resource, type, error)
+ {
+ /* Do they already have the maximum number of resources allocated? */
+ if (this.resourceList.count >= this.RESOURCE_LIMIT)
+ {
+ /* Yup. */
+ error.setOrigin(jsonrpc.Constant.ErrorOrigin.Server);
+ error.setError(JsonRpcError_ResourceError,
+ "Session limit on resources (" +
+ RESOURCE_LIMIT +
+ ") exceeded.");
+ return error;
+ }
+
+ /* Allocate an object to hold the new resource and its type */
+ var r = new Object();
+
+ /* Save the resource and its type */
+ r.resource = resource;
+ r.type = type;
+
+ /* Add this resource to the list */
+ this.resourceList[this.resourceList.id] = r;
+
+ /* There's a new resource in the list! */
+ this.resourceList.count++;
+
+ /*
+ * Return the index of the resource, its resource id, and advance to
+ * the next resource id for next time.
+ */
+ var id = this.resourceList.id;
+ this.resourceList.id++;
+ return id;
+ }
+ o.set = _set;
+
+ /*
+ * Get a previously-saved resource
+ */
+ function _get(resourceId, type, error)
+ {
+ /* Does the specified resource id exist? */
+ if (! this.resourceList[resourceId])
+ {
+ /* Nope. */
+ error.setOrigin(jsonrpc.Constant.ErrorOrigin.Server);
+ error.setError(jsonrpc.Constant.ErrorCode.ResourceError,
+ "Resource not found.");
+ return error;
+ }
+
+ /* Retrieve the resource */
+ var r = this.resourceList[resourceId];
+
+ /* Is the specified resource the correct type? */
+ if (r.type != type)
+ {
+ /* Nope. */
+ error.setOrigin(jsonrpc.Constant.ErrorOrigin.Server);
+ error.setError(jsonrpc.Constant.ErrorCode.ResourceError,
+ "Incorrect type for specified resource id.");
+ return error;
+ }
+
+ /* Give 'em what they came for! */
+ return r.resource;
+ }
+ o.get = _get;
+
+ /*
+ * Release a previously-saved resource, allowing it to be freed
+ */
+ function _release(resourceId, error)
+ {
+ /* Does the specified resource id exist? */
+ if (! this.resourceList[resourceId])
+ {
+ /* Nope. */
+ error.setOrigin(jsonrpc.Constant.ErrorOrigin.Server);
+ error.setError(jsonrpc.Constant.ErrorCode.ResourceError,
+ "Resource not found.");
+ return error;
+ }
+
+ /* It exists. Delete it. */
+ delete this.resourceList[resourceId];
+
+ /* There's now one fewer resources in the list */
+ this.resourceList.count--;
+ }
+ o.release = _release;
+
+ /*
+ * Retrieve the list of resources (for debugging) */
+ */
+ function _getList(error)
+ {
+ return this.resourceList;
+ }
+ o.getList = _getList;
+
+ return o;
+}
+
+/* singleton: create session resources list */
+if (! session.resources)
+{
+ session.resources = _resourcesCreate();
+}
+
+
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+%>
diff --git a/services/samba/ldb.esp b/services/samba/ldb.esp
new file mode 100644
index 0000000000..2eff5ba57d
--- /dev/null
+++ b/services/samba/ldb.esp
@@ -0,0 +1,610 @@
+<%
+/*
+ * Copyright:
+ * (C) 2006 by Derrell Lipman
+ * All rights reserved
+ *
+ * License:
+ * LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/
+ */
+
+/*
+ * JSON-RPC mappings to the ldb ejs functions
+ */
+
+/* We'll be saving resources in the session */
+jsonrpc_include("resources.esp");
+
+
+/**
+ * Connect to a database
+ *
+ * @param params[0]
+ * Database name
+ *
+ * @param params[1..n]
+ * Option (e.g. "modules:modlist")
+ *
+ * @param error
+ * An object of class JsonRpcError.
+ *
+ * @return
+ * Success: The resource id to be used for future access to the database
+ * Failure: -1
+ *
+ * @note
+ * Credentials or session_info may be set up first.
+ */
+function _connect(params, error)
+{
+ if (params.length < 1)
+ {
+ error.setError(JsonRpcError_ParameterMismatch,
+ "usage: <db_name> [<option> ...]");
+ return error;
+ }
+
+ ldb = ldb_init();
+ var ret = ldb.connect(params[0]);
+ if (ret && ldb.db)
+ {
+ return session.resources.set(ldb,
+ session.resources.Type.ldb,
+ error);
+ }
+ else
+ {
+ error.setError(-1, "ldb.connect failed");
+ return error;
+ }
+}
+jsonrpc.method.connect = _connect;
+
+
+/**
+ * Close a database
+ *
+ * @param params[0]
+ * The resource id of the open database, previously returned by connect()
+ *
+ * @param error
+ * An object of class JsonRpcError.
+ *
+ * @return
+ * Success: True
+ * Failure: Will only fail with invalid parameters, and throws an error
+ */
+function _close(params, error)
+{
+ if (params.length != 1)
+ {
+ error.setError(JsonRpcError_ParameterMismatch,
+ "usage: <resource_id>");
+ return error;
+ }
+
+ ldb = session.resources.get(params[0],
+ session.resources.Type.ldb,
+ error);
+ if (ldb["__type"] == "_JsonRpcError")
+ {
+ return ldb;
+ }
+
+ var ret = ldb.close();
+
+ /* If close succeeded, release the stored resource */
+ if (ret)
+ {
+ session.resources.release(params[0], error);
+ }
+
+ return ret;
+}
+jsonrpc.method.close = _close;
+
+
+/**
+ * Begin a transaction
+ *
+ * @param params[0]
+ * The resource id of the open database, previously returned by connect()
+ *
+ * @param error
+ * An object of class JsonRpcError.
+ *
+ * @return
+ * Success: True
+ * Failure: False
+ */
+function _transaction_start(params, error)
+{
+ if (params.length != 1)
+ {
+ error.setError(JsonRpcError_ParameterMismatch,
+ "usage: <resource_id>");
+ return error;
+ }
+
+ ldb = session.resources.get(params[0],
+ session.resources.Type.ldb,
+ error);
+ if (ldb["__type"] == "_JsonRpcError")
+ {
+ return ldb;
+ }
+
+ return ldb.transaction_start();
+}
+jsonrpc.method.transaction_start = _transaction_start;
+
+
+/**
+ * Cancel a transaction
+ *
+ * @param params[0]
+ * The resource id of the open database, previously returned by connect()
+ *
+ * @param error
+ * An object of class JsonRpcError.
+ *
+ * @return
+ * Success: True
+ * Failure: False
+ */
+function _transaction_cancel(params, error)
+{
+ if (params.length != 1)
+ {
+ error.setError(JsonRpcError_ParameterMismatch,
+ "usage: <resource_id>");
+ return error;
+ }
+
+ ldb = session.resources.get(params[0],
+ session.resources.Type.ldb,
+ error);
+ if (ldb["__type"] == "_JsonRpcError")
+ {
+ return ldb;
+ }
+
+ return ldb.transaction_cancel();
+}
+jsonrpc.method.transaction_cancel = _transaction_cancel;
+
+
+/**
+ * Commit a transaction
+ *
+ * @param params[0]
+ * The resource id of the open database, previously returned by connect()
+ *
+ * @param error
+ * An object of class JsonRpcError.
+ *
+ * @return
+ * Success: True
+ * Failure: False
+ */
+function _transaction_commit(params, error)
+{
+ if (params.length != 1)
+ {
+ error.setError(JsonRpcError_ParameterMismatch,
+ "usage: <resource_id>");
+ return error;
+ }
+
+ ldb = session.resources.get(params[0],
+ session.resources.Type.ldb,
+ error);
+ if (ldb["__type"] == "_JsonRpcError")
+ {
+ return ldb;
+ }
+
+ return ldb.transaction_commit();
+}
+jsonrpc.method.transaction_commit = _transaction_commit;
+
+
+/**
+ * Issue a Search request
+ *
+ * @param params[0]
+ * The resource id of the open database, previously returned by connect()
+ *
+ * @param params[1]
+ * Search expression
+ *
+ * @param params[2]
+ * Base DN
+ *
+ * @param params[3]
+ * Scope: "default", "base", "one" or "subtree"
+ *
+ * @param params[4]
+ * Attributes: an array object
+ *
+ * @param error
+ * An object of class JsonRpcError.
+ *
+ * @return
+ * Success: found object
+ * Failure: `undefined`
+ *
+ * @note
+ * If params[4] is missing, assume no attributes
+ * If params[3..4] are missing, also assume "default" scope
+ * If params[2..4] are missing, also assume null base DN
+ */
+function _search(params, error)
+{
+ if (params.length < 2 || params.length > 5)
+ {
+ error.setError(JsonRpcError_ParameterMismatch,
+ "usage: " +
+ "<resource_id> <expr> [<baseDN> [<scope> [<attrs>]]]");
+ return error;
+ }
+
+ ldb = session.resources.get(params[0],
+ session.resources.Type.ldb,
+ error);
+ if (ldb["__type"] == "_JsonRpcError")
+ {
+ return ldb;
+ }
+
+ /* Retrieve parameters */
+ var expr = params[1];
+ var baseDN = params[2];
+ var scope = params[3];
+ var attrs = params[4];
+
+ /* Fill in optional parameters */
+ if (params.length < 3) baseDN = null;
+ if (params.length < 4) scope = "one";
+ if (params.length < 5) attrs = null;
+
+ /* Determine scope value */
+ if (scope == "base")
+ {
+ scope = ldb.SCOPE_BASE;
+ }
+ else if (scope == "one")
+ {
+ scope = ldb.SCOPE_ONE;
+ }
+ else if (scope == "subtree")
+ {
+ scope = ldb.SCOPE_SUBTREE;
+ }
+ else if (scope == "default")
+ {
+ scope = ldb.SCOPE_DEFAULT;
+ }
+ else
+ {
+ error.setError(JsonRpcError_ParameterMismatch,
+ "invalid scope");
+ return error;
+ }
+
+ return ldb.transaction_search(expr, baseDN, scope, attrs);
+}
+jsonrpc.method.search = _search;
+
+
+/**
+ * Add data to the database
+ *
+ * @param params[0]
+ * The resource id of the open database, previously returned by connect()
+ *
+ * @param params[1]
+ * An LDIF string representing the data to be added
+ *
+ * @param error
+ * An object of class JsonRpcError.
+ *
+ * @return
+ * Success: True
+ * Failure: False
+ */
+function _add(params, error)
+{
+ if (params.length != 2)
+ {
+ error.setError(JsonRpcError_ParameterMismatch,
+ "usage: <resource_id> <ldif>");
+ return error;
+ }
+
+ ldb = session.resources.get(params[0],
+ session.resources.Type.ldb,
+ error);
+ if (ldb["__type"] == "_JsonRpcError")
+ {
+ return ldb;
+ }
+
+ return ldb.add(params[1]);
+}
+jsonrpc.method.add = _add;
+
+
+/**
+ * Modify data in the database
+ *
+ * @param params[0]
+ * The resource id of the open database, previously returned by connect()
+ *
+ * @param params[1]
+ * An LDIF string representing the data to be modified
+ *
+ * @param error
+ * An object of class JsonRpcError.
+ *
+ * @return
+ * Success: True
+ * Failure: False
+ */
+function _modify(params, error)
+{
+ if (params.length != 2)
+ {
+ error.setError(JsonRpcError_ParameterMismatch,
+ "usage: <resource_id> <ldif>");
+ return error;
+ }
+
+ ldb = session.resources.get(params[0],
+ session.resources.Type.ldb,
+ error);
+ if (ldb["__type"] == "_JsonRpcError")
+ {
+ return ldb;
+ }
+
+ return ldb.modify(params[1]);
+}
+jsonrpc.method.modify = _modify;
+
+
+/**
+ * Delete data from the database
+ *
+ * @param params[0]
+ * The resource id of the open database, previously returned by connect()
+ *
+ * @param params[1]
+ * The DN to be located and deleted
+ *
+ * @param error
+ * An object of class JsonRpcError.
+ *
+ * @return
+ * Success: True
+ * Failure: False
+ */
+function _del(params, error)
+{
+ if (params.length != 2)
+ {
+ error.setError(JsonRpcError_ParameterMismatch,
+ "usage: <resource_id> <dn>");
+ return error;
+ }
+
+ ldb = session.resources.get(params[0],
+ session.resources.Type.ldb,
+ error);
+ if (ldb["__type"] == "_JsonRpcError")
+ {
+ return ldb;
+ }
+
+ return ldb.del(params[1]);
+}
+jsonrpc.method.del = _del;
+
+
+/**
+ * Rename data in the database
+ *
+ * @param params[0]
+ * The resource id of the open database, previously returned by connect()
+ *
+ * @param params[1]
+ * The DN to be renamed
+ *
+ * @param params[2]
+ * The new name for the DN being renamed
+ *
+ * @param error
+ * An object of class JsonRpcError.
+ *
+ * @return
+ * Success: True
+ * Failure: False
+ */
+function _rename(params, error)
+{
+ if (params.length != 3)
+ {
+ error.setError(JsonRpcError_ParameterMismatch,
+ "usage: <resource_id> <old_dn> <new_dn>");
+ return error;
+ }
+
+ ldb = session.resources.get(params[0],
+ session.resources.Type.ldb,
+ error);
+ if (ldb["__type"] == "_JsonRpcError")
+ {
+ return ldb;
+ }
+
+ return ldb.rename(params[1], params[2]);
+}
+jsonrpc.method.rename = _rename;
+
+
+/**
+ * Base64-encode a string
+ *
+ * @param params[0]
+ * The resource id of the open database, previously returned by connect()
+ *
+ * @param params[1]
+ * The string to be base64 encoded
+ *
+ * @param error
+ * An object of class JsonRpcError.
+ *
+ * @return
+ * Success: encoded string
+ * Failure: `undefined`
+ */
+function _base64encode(params, error)
+{
+ if (params.length != 2)
+ {
+ error.setError(JsonRpcError_ParameterMismatch,
+ "usage: <resource_id> <string_to_be_encoded>");
+ return error;
+ }
+
+ ldb = session.resources.get(params[0],
+ session.resources.Type.ldb,
+ error);
+ if (ldb["__type"] == "_JsonRpcError")
+ {
+ return ldb;
+ }
+
+ return ldb.base64encode(params[1]);
+}
+jsonrpc.method.base64encode = _base64encode;
+
+
+/**
+ * Base64-decode a string
+ *
+ * @param params[0]
+ * The resource id of the open database, previously returned by connect()
+ *
+ * @param params[1]
+ * The string to be base64 decoded
+ *
+ * @param error
+ * An object of class JsonRpcError.
+ *
+ * @return
+ * Success: decoded string
+ * Failure: `undefined`
+ */
+function _base64decode(params, error)
+{
+ if (params.length != 2)
+ {
+ error.setError(JsonRpcError_ParameterMismatch,
+ "usage: <resource_id> <string_to_be_decoded>");
+ return error;
+ }
+
+ ldb = session.resources.get(params[0],
+ session.resources.Type.ldb,
+ error);
+ if (ldb["__type"] == "_JsonRpcError")
+ {
+ return ldb;
+ }
+
+ return ldb.base64decode(params[1]);
+}
+jsonrpc.method.base64decode = _base64decode;
+
+
+/**
+ * escape a DN
+ *
+ * @param params[0]
+ * The resource id of the open database, previously returned by connect()
+ *
+ * @param params[1]
+ * The DN to be escaped
+ *
+ * @param error
+ * An object of class JsonRpcError.
+ *
+ * @return
+ * Success: escaped string
+ * Failure: undefined
+ */
+function _base64decode(params, error)
+{
+ if (params.length != 2)
+ {
+ error.setError(JsonRpcError_ParameterMismatch,
+ "usage: <resource_id> <string_to_be_decoded>");
+ return error;
+ }
+
+ ldb = session.resources.get(params[0],
+ session.resources.Type.ldb,
+ error);
+ if (ldb["__type"] == "_JsonRpcError")
+ {
+ return ldb;
+ }
+
+ return ldb.base64decode(params[1]);
+}
+jsonrpc.method.base64decode = _base64decode;
+
+
+/**
+ * Retrieve a description of the most recent error
+ *
+ * @param params[0]
+ * The resource id of the open database, previously returned by connect()
+ *
+ * @param error
+ * An object of class JsonRpcError.
+ *
+ * @return
+ * The most recent error string for the ldb specified by the resource id
+ */
+function _errstring(params, error)
+{
+ if (params.length != 1)
+ {
+ error.setError(JsonRpcError_ParameterMismatch,
+ "usage: <resource_id>");
+ return error;
+ }
+
+ ldb = session.resources.get(params[0],
+ session.resources.Type.ldb,
+ error);
+ if (ldb["__type"] == "_JsonRpcError")
+ {
+ return ldb;
+ }
+
+ return ldb.errstring();
+}
+jsonrpc.method.errstring = _errstring;
+
+
+
+
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+%>
diff --git a/services/samba/system.esp b/services/samba/system.esp
new file mode 100644
index 0000000000..e75151e93b
--- /dev/null
+++ b/services/samba/system.esp
@@ -0,0 +1,34 @@
+<%
+/*
+ * Copyright:
+ * (C) 2006 by Derrell Lipman
+ * All rights reserved
+ *
+ * License:
+ * LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/
+ */
+
+/*
+ * JSON-RPC mappings to system facilities
+ */
+
+/* We'll be accessing session resources */
+jsonrpc_include("resources.esp");
+
+
+/**
+ * Retrieve the list of open resources (for debugging)
+ */
+function _get_open_resources(params, error)
+{
+ return session.resources.getList(error);
+}
+jsonrpc.method.get_open_resources = _get_open_resources;
+
+
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+%>