diff options
author | Derrell Lipman <derrell@samba.org> | 2006-10-07 20:35:59 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 14:20:48 -0500 |
commit | 9ee311c39fdefc8d723e8ea718f06df9c6159621 (patch) | |
tree | d6607561bedb1086f6054996a7f8675d2c93493c | |
parent | 7bdfbd608c86b89ab6c7e98f8a01285acec53efb (diff) | |
download | samba-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.esp | 161 | ||||
-rw-r--r-- | services/samba/ldb.esp | 610 | ||||
-rw-r--r-- | services/samba/system.esp | 34 |
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: + */ +%> |