diff options
Diffstat (limited to 'source4/scripting/ejs')
-rw-r--r-- | source4/scripting/ejs/config.mk | 63 | ||||
-rw-r--r-- | source4/scripting/ejs/mprutil.c | 494 | ||||
-rw-r--r-- | source4/scripting/ejs/smbcalls.c | 220 | ||||
-rw-r--r-- | source4/scripting/ejs/smbcalls.h | 42 | ||||
-rw-r--r-- | source4/scripting/ejs/smbcalls_auth.c | 243 | ||||
-rw-r--r-- | source4/scripting/ejs/smbcalls_config.c | 228 | ||||
-rw-r--r-- | source4/scripting/ejs/smbcalls_creds.c | 275 | ||||
-rw-r--r-- | source4/scripting/ejs/smbcalls_ldb.c | 772 | ||||
-rw-r--r-- | source4/scripting/ejs/smbcalls_options.c | 193 | ||||
-rw-r--r-- | source4/scripting/ejs/smbcalls_string.c | 529 | ||||
-rw-r--r-- | source4/scripting/ejs/smbcalls_sys.c | 494 | ||||
-rw-r--r-- | source4/scripting/ejs/smbscript.c | 129 |
12 files changed, 3682 insertions, 0 deletions
diff --git a/source4/scripting/ejs/config.mk b/source4/scripting/ejs/config.mk new file mode 100644 index 0000000000..34c0a9678e --- /dev/null +++ b/source4/scripting/ejs/config.mk @@ -0,0 +1,63 @@ +[MODULE::smbcalls_config] +OUTPUT_TYPE = MERGED_OBJ +SUBSYSTEM = smbcalls +INIT_FUNCTION = smb_setup_ejs_config + +smbcalls_config_OBJ_FILES = $(ejsscriptsrcdir)/smbcalls_config.o + +[MODULE::smbcalls_ldb] +OUTPUT_TYPE = MERGED_OBJ +SUBSYSTEM = smbcalls +INIT_FUNCTION = smb_setup_ejs_ldb +PRIVATE_DEPENDENCIES = LIBLDB SAMDB LIBNDR + +smbcalls_ldb_OBJ_FILES = $(ejsscriptsrcdir)/smbcalls_ldb.o + +[MODULE::smbcalls_auth] +OUTPUT_TYPE = MERGED_OBJ +SUBSYSTEM = smbcalls +INIT_FUNCTION = smb_setup_ejs_auth +PRIVATE_DEPENDENCIES = service_auth + +smbcalls_auth_OBJ_FILES = $(ejsscriptsrcdir)/smbcalls_auth.o + +smbcalls_auth_OBJ_FILES = $(ejsscriptsrcdir)/smbcalls_auth.o + +[MODULE::smbcalls_string] +SUBSYSTEM = smbcalls +OUTPUT_TYPE = MERGED_OBJ +INIT_FUNCTION = smb_setup_ejs_string + +smbcalls_string_OBJ_FILES = $(ejsscriptsrcdir)/smbcalls_string.o + +[MODULE::smbcalls_sys] +SUBSYSTEM = smbcalls +OUTPUT_TYPE = MERGED_OBJ +INIT_FUNCTION = smb_setup_ejs_system + +smbcalls_sys_OBJ_FILES = $(ejsscriptsrcdir)/smbcalls_sys.o + +[SUBSYSTEM::smbcalls] +PRIVATE_DEPENDENCIES = \ + EJS LIBSAMBA-UTIL \ + MESSAGING \ + LIBSAMBA-NET LIBCLI_SMB LIBPOPT \ + CREDENTIALS POPT_CREDENTIALS POPT_SAMBA \ + NDR_TABLE + +smbcalls_OBJ_FILES = $(addprefix $(ejsscriptsrcdir)/, \ + smbcalls.o \ + smbcalls_options.o \ + smbcalls_creds.o \ + mprutil.o) + +$(eval $(call proto_header_template,$(ejsscriptsrcdir)/proto.h,$(smbcalls_OBJ_FILES:.o=.c))) + +####################### +# Start BINARY SMBSCRIPT +[BINARY::smbscript] +PRIVATE_DEPENDENCIES = EJS LIBSAMBA-UTIL smbcalls LIBSAMBA-HOSTCONFIG +# End BINARY SMBSCRIPT +####################### + +smbscript_OBJ_FILES = $(ejsscriptsrcdir)/smbscript.o diff --git a/source4/scripting/ejs/mprutil.c b/source4/scripting/ejs/mprutil.c new file mode 100644 index 0000000000..9143947fb8 --- /dev/null +++ b/source4/scripting/ejs/mprutil.c @@ -0,0 +1,494 @@ +/* + Unix SMB/CIFS implementation. + + utility functions for manipulating mpr variables in ejs calls + + Copyright (C) Andrew Tridgell 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/appweb/ejs/ejs.h" +#include "lib/ldb/include/ldb.h" +#include "scripting/ejs/smbcalls.h" + +/* + return a default mpr object +*/ +struct MprVar mprObject(const char *name) +{ + return ejsCreateObj(name && *name?name:"(NULL)", MPR_DEFAULT_HASH_SIZE); +} + +/* + return a empty mpr array +*/ +struct MprVar mprArray(const char *name) +{ + return ejsCreateArray(name && *name?name:"(NULL)", 0); +} + +/* + find a mpr component, allowing for sub objects, using the '.' convention +*/ + NTSTATUS mprGetVar(struct MprVar **v, const char *name) +{ + const char *p = strchr(name, '.'); + char *objname; + NTSTATUS status; + if (p == NULL) { + *v = mprGetProperty(*v, name, NULL); + if (*v == NULL) { + DEBUG(1,("mprGetVar unable to find '%s'\n", name)); + return NT_STATUS_INVALID_PARAMETER; + } + return NT_STATUS_OK; + } + objname = talloc_strndup(mprMemCtx(), name, p-name); + NT_STATUS_HAVE_NO_MEMORY(objname); + *v = mprGetProperty(*v, objname, NULL); + NT_STATUS_HAVE_NO_MEMORY(*v); + status = mprGetVar(v, p+1); + talloc_free(objname); + return status; +} + + +/* + set a mpr component, allowing for sub objects, using the '.' convention + destroys 'val' after setting +*/ + NTSTATUS mprSetVar(struct MprVar *v, const char *name, struct MprVar val) +{ + const char *p = strchr(name, '.'); + char *objname; + struct MprVar *v2; + NTSTATUS status; + if (p == NULL) { + v2 = mprSetProperty(v, name, &val); + if (v2 == NULL) { + DEBUG(1,("mprSetVar unable to set '%s'\n", name)); + return NT_STATUS_INVALID_PARAMETER_MIX; + } + mprDestroyVar(&val); + return NT_STATUS_OK; + } + objname = talloc_strndup(mprMemCtx(), name, p-name); + if (objname == NULL) { + return NT_STATUS_NO_MEMORY; + } + v2 = mprGetProperty(v, objname, NULL); + if (v2 == NULL) { + mprSetVar(v, objname, mprObject(objname)); + v2 = mprGetProperty(v, objname, NULL); + } + status = mprSetVar(v2, p+1, val); + talloc_free(objname); + return status; +} + + + +/* + add an indexed array element to a property +*/ + void mprAddArray(struct MprVar *var, int i, struct MprVar v) +{ + char idx[16]; + mprItoa(i, idx, sizeof(idx)); + mprSetVar(var, idx, v); +} + +/* + construct a MprVar from a list +*/ +struct MprVar mprList(const char *name, const char **list) +{ + struct MprVar var; + int i; + + var = mprArray(name); + for (i=0;list && list[i];i++) { + mprAddArray(&var, i, mprString(list[i])); + } + return var; +} + +/* + construct a MprVar from a string, using NULL if needed +*/ +struct MprVar mprString(const char *s) +{ + if (s == NULL) { + return mprCreatePtrVar(NULL); + } + return mprCreateStringVar(s, true); +} + +/* + construct a string MprVar from a lump of data +*/ +struct MprVar mprData(const uint8_t *p, size_t length) +{ + struct MprVar var; + char *s = talloc_strndup(mprMemCtx(), (const char *)p, length); + if (s == NULL) { + return mprCreateUndefinedVar(); + } + var = mprString(s); + talloc_free(s); + return var; +} + +/* + turn a ldb_message into a ejs object variable +*/ +static struct MprVar mprLdbMessage(struct ldb_context *ldb, struct ldb_message *msg) +{ + struct MprVar var; + int i; + /* we force some attributes to always be an array in the + returned structure. This makes the scripting easier, as you don't + need a special case for the single value case */ + const char *multivalued[] = { "objectClass", "memberOf", "privilege", + "member", NULL }; + + var = mprObject(ldb_dn_alloc_linearized(msg, msg->dn)); + + for (i=0;i<msg->num_elements;i++) { + struct ldb_message_element *el = &msg->elements[i]; + struct MprVar val; + const struct ldb_schema_attribute *a; + struct ldb_val v; + + a = ldb_schema_attribute_by_name(ldb, el->name); + if (a == NULL) { + goto failed; + } + + if (el->num_values == 1 && + !str_list_check_ci(multivalued, el->name)) { + if (a->syntax->ldif_write_fn(ldb, msg, &el->values[0], &v) != 0) { + goto failed; + } + /* FIXME: nasty hack, remove me when ejs will support + * arbitrary string and does not truncate on \0 */ + if (strlen((char *)v.data) != v.length) { + val = mprDataBlob(v); + } else { + val = mprData(v.data, v.length); + } + } else { + int j; + val = mprArray(el->name); + for (j=0;j<el->num_values;j++) { + if (a->syntax->ldif_write_fn(ldb, msg, + &el->values[j], &v) != 0) { + goto failed; + } + /* FIXME: nasty hack, remove me when ejs will support + * arbitrary string and does not truncate on \0 */ + if (strlen((char *)v.data) != v.length) { + mprAddArray(&val, j, mprDataBlob(v)); + } else { + mprAddArray(&val, j, mprData(v.data, v.length)); + } + } + } + mprSetVar(&var, el->name, val); + } + + /* add the dn if it is not already specified */ + if (mprGetProperty(&var, "dn", 0) == 0) { + mprSetVar(&var, "dn", mprString(ldb_dn_alloc_linearized(msg, msg->dn))); + } + + return var; +failed: + return mprCreateUndefinedVar(); +} + + +/* + build a MprVar result object for ldb operations with lots of funky properties +*/ +struct MprVar mprLdbResult(struct ldb_context *ldb, int err, struct ldb_result *result) +{ + struct MprVar ret; + struct MprVar ary; + + ret = mprObject("ldbret"); + + mprSetVar(&ret, "error", mprCreateIntegerVar(err)); + mprSetVar(&ret, "errstr", mprString(ldb_errstring(ldb))); + + ary = mprArray("ldb_message"); + if (result) { + int i; + + for (i = 0; i < result->count; i++) { + mprAddArray(&ary, i, mprLdbMessage(ldb, result->msgs[i])); + } + } + + mprSetVar(&ret, "msgs", ary); + + /* TODO: add referrals, exteded ops, and controls */ + + return ret; +} + + +/* + turn a MprVar string variable into a const char * + */ +const char *mprToString(struct MprVar *v) +{ + if (v->trigger) { + mprReadProperty(v, 0); + } + if (!mprVarIsString(v->type)) return NULL; + return v->string; +} + +/* + turn a MprVar integer variable into an int + */ +int mprToInt(struct MprVar *v) +{ + if (v->trigger) { + mprReadProperty(v, 0); + } + if (!mprVarIsNumber(v->type)) return 0; + return mprVarToNumber(v); +} + +/* + turn a MprVar object variable into a string list + this assumes the object variable consists only of strings +*/ +const char **mprToList(TALLOC_CTX *mem_ctx, struct MprVar *v) +{ + const char **list = NULL; + struct MprVar *el; + + if (v->type != MPR_TYPE_OBJECT || + v->properties == NULL) { + return NULL; + } + for (el=mprGetFirstProperty(v, MPR_ENUM_DATA); + el; + el=mprGetNextProperty(v, el, MPR_ENUM_DATA)) { + const char *s = mprToString(el); + if (s) { + list = str_list_add(list, s); + } + } + talloc_steal(mem_ctx, list); + return list; +} + + +/* + turn a MprVar object variable into a string list + this assumes the object variable is an array of strings +*/ +const char **mprToArray(TALLOC_CTX *mem_ctx, struct MprVar *v) +{ + const char **list = NULL; + struct MprVar *len; + int length, i; + + len = mprGetProperty(v, "length", NULL); + if (len == NULL) { + return NULL; + } + length = mprToInt(len); + + for (i=0;i<length;i++) { + char idx[16]; + struct MprVar *vs; + mprItoa(i, idx, sizeof(idx)); + vs = mprGetProperty(v, idx, NULL); + if (vs == NULL || vs->type != MPR_TYPE_STRING) { + talloc_free(list); + return NULL; + } + list = str_list_add(list, mprToString(vs)); + } + talloc_steal(mem_ctx, list); + return list; +} + +/* + turn a NTSTATUS into a MprVar object with lots of funky properties +*/ +struct MprVar mprNTSTATUS(NTSTATUS status) +{ + struct MprVar res; + + res = mprObject("ntstatus"); + + mprSetVar(&res, "errstr", mprString(nt_errstr(status))); + mprSetVar(&res, "v", mprCreateIntegerVar(NT_STATUS_V(status))); + mprSetVar(&res, "is_ok", mprCreateBoolVar(NT_STATUS_IS_OK(status))); + mprSetVar(&res, "is_err", mprCreateBoolVar(NT_STATUS_IS_ERR(status))); + + return res; +} + +/* + create a data-blob in a mpr variable +*/ +struct MprVar mprDataBlob(DATA_BLOB blob) +{ + struct MprVar res; + struct datablob *pblob = talloc(mprMemCtx(), struct datablob); + *pblob = data_blob_talloc(pblob, blob.data, blob.length); + + res = mprObject("DATA_BLOB"); + + mprSetVar(&res, "size", mprCreateIntegerVar(blob.length)); + mprSetPtrChild(&res, "blob", pblob); + + return res; +} + +/* + return a data blob from a mpr var created using mprDataBlob +*/ +struct datablob *mprToDataBlob(struct MprVar *v) +{ + return talloc_get_type(mprGetPtr(v, "blob"), struct datablob); +} + +/* + turn a WERROR into a MprVar object with lots of funky properties +*/ +struct MprVar mprWERROR(WERROR status) +{ + struct MprVar res; + + res = mprObject("werror"); + + mprSetVar(&res, "errstr", mprString(win_errstr(status))); + mprSetVar(&res, "v", mprCreateIntegerVar(W_ERROR_V(status))); + mprSetVar(&res, "is_ok", mprCreateBoolVar(W_ERROR_IS_OK(status))); + mprSetVar(&res, "is_err", mprCreateBoolVar(!W_ERROR_IS_OK(status))); + + return res; +} + + +/* + set a pointer in a existing MprVar +*/ +void mprSetPtr(struct MprVar *v, const char *propname, const void *p) +{ + mprSetVar(v, propname, mprCreatePtrVar(discard_const(p))); +} + +/* + set a pointer in a existing MprVar, freeing it when the property goes away +*/ +void mprSetPtrChild(struct MprVar *v, const char *propname, const void *p) +{ + mprSetVar(v, propname, mprCreatePtrVar(discard_const(p))); + v = mprGetProperty(v, propname, NULL); + v->allocatedData = 1; + talloc_steal(mprMemCtx(), p); +} + +/* + get a pointer from a MprVar +*/ +void *mprGetPtr(struct MprVar *v, const char *propname) +{ + struct MprVar *val; + val = mprGetProperty(v, propname, NULL); + if (val == NULL) { + return NULL; + } + if (val->type != MPR_TYPE_PTR) { + return NULL; + } + return val->ptr; +} + +/* + set the return value then free the variable +*/ + void mpr_Return(int eid, struct MprVar v) +{ + ejsSetReturnValue(eid, v); + mprDestroyVar(&v); +} + +/* + set the return value then free the variable +*/ +void mpr_ReturnString(int eid, const char *s) +{ + mpr_Return(eid, mprString(s)); +} + + +/* + set a C function in a variable +*/ + void mprSetCFunction(struct MprVar *obj, const char *name, MprCFunction fn) +{ + mprSetVar(obj, name, mprCreateCFunctionVar(fn, obj, MPR_VAR_SCRIPT_HANDLE)); +} + +/* + set a string C function in a variable +*/ + void mprSetStringCFunction(struct MprVar *obj, const char *name, MprStringCFunction fn) +{ + mprSetVar(obj, name, mprCreateStringCFunctionVar(fn, obj, MPR_VAR_SCRIPT_HANDLE)); +} + +/* + get a pointer in the current object +*/ +void *mprGetThisPtr(int eid, const char *name) +{ + struct MprVar *this = mprGetProperty(ejsGetLocalObject(eid), "this", 0); + return mprGetPtr(this, name); +} + +/* + set a pointer as a child of the local object +*/ +void mprSetThisPtr(int eid, const char *name, void *ptr) +{ + struct MprVar *this = mprGetProperty(ejsGetLocalObject(eid), "this", 0); + mprSetPtrChild(this, name, ptr); +} + +/* + used by object xxx_init() routines to allow for the caller + to supply a pre-existing object to add properties to, + or create a new object. This makes inheritance easy +*/ +struct MprVar *mprInitObject(int eid, const char *name, int argc, struct MprVar **argv) +{ + if (argc > 0 && mprVarIsObject(argv[0]->type)) { + return argv[0]; + } + mpr_Return(eid, mprObject(name)); + return ejsGetReturnValue(eid); +} diff --git a/source4/scripting/ejs/smbcalls.c b/source4/scripting/ejs/smbcalls.c new file mode 100644 index 0000000000..4314b51455 --- /dev/null +++ b/source4/scripting/ejs/smbcalls.c @@ -0,0 +1,220 @@ +/* + Unix SMB/CIFS implementation. + + provide hooks into smbd C calls from ejs scripts + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Tim Potter 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "param/param.h" +#include "scripting/ejs/smbcalls.h" +#include "version.h" + +/* + return the type of a variable +*/ +static int ejs_typeof(MprVarHandle eid, int argc, struct MprVar **argv) +{ + const struct { + MprType type; + const char *name; + } types[] = { + { MPR_TYPE_UNDEFINED, "undefined" }, + { MPR_TYPE_NULL, "object" }, + { MPR_TYPE_BOOL, "boolean" }, + { MPR_TYPE_CFUNCTION, "function" }, + { MPR_TYPE_FLOAT, "number" }, + { MPR_TYPE_INT, "number" }, + { MPR_TYPE_INT64, "number" }, + { MPR_TYPE_OBJECT, "object" }, + { MPR_TYPE_FUNCTION, "function" }, + { MPR_TYPE_STRING, "string" }, + { MPR_TYPE_STRING_CFUNCTION, "function" }, + { MPR_TYPE_PTR, "pointer" } + }; + int i; + const char *type = NULL; + + if (argc != 1) return -1; + + for (i=0;i<ARRAY_SIZE(types);i++) { + if (argv[0]->type == types[i].type) { + type = types[i].name; + break; + } + } + if (type == NULL) return -1; + + mpr_ReturnString(eid, type); + return 0; +} + +/* + return the native type of a variable +*/ +static int ejs_typeof_native(MprVarHandle eid, int argc, struct MprVar **argv) +{ + const struct { + MprType type; + const char *name; + } types[] = { + { MPR_TYPE_UNDEFINED, "undefined" }, + { MPR_TYPE_NULL, "null" }, + { MPR_TYPE_BOOL, "boolean" }, + { MPR_TYPE_CFUNCTION, "c_function" }, + { MPR_TYPE_FLOAT, "float" }, + { MPR_TYPE_INT, "integer" }, + { MPR_TYPE_INT64, "integer64" }, + { MPR_TYPE_OBJECT, "object" }, + { MPR_TYPE_FUNCTION, "js_function" }, + { MPR_TYPE_STRING, "string" }, + { MPR_TYPE_STRING_CFUNCTION, "string_c_function" }, + { MPR_TYPE_PTR, "pointer" } + }; + int i; + const char *type = NULL; + + if (argc != 1) return -1; + + for (i=0;i<ARRAY_SIZE(types);i++) { + if (argv[0]->type == types[i].type) { + type = types[i].name; + break; + } + } + if (type == NULL) return -1; + + mpr_ReturnString(eid, type); + return 0; +} + +/* + libinclude() allows you to include js files using a search path specified + in "js include =" in smb.conf. +*/ +static int ejs_libinclude(int eid, int argc, char **argv) +{ + int i, j; + const char **js_include = lp_js_include(mprLpCtx()); + + if (js_include == NULL || js_include[0] == NULL) { + ejsSetErrorMsg(eid, "js include path not set"); + return -1; + } + + for (i = 0; i < argc; i++) { + const char *script = argv[i]; + struct MprVar result; + char *path, *emsg; + int ret; + + /* use specfied path to search for requested file */ + for (j=0;js_include[j];j++) { + path = talloc_asprintf(mprMemCtx(), "%s/%s", js_include[j], script); + if (path == NULL) { + return -1; + } + if (file_exist(path)) { + + ret = ejsEvalFile(eid, path, &result, &emsg); + talloc_free(path); + if (ret < 0) { + ejsSetErrorMsg(eid, "%s: %s", script, emsg); + return -1; + } + break; + } + talloc_free(path); + } + + if (js_include[j] == NULL) { + ejsSetErrorMsg(eid, "unable to include '%s'", script); + return -1; + } + } + return 0; +} + +/* + return the current version +*/ +static int ejs_version(MprVarHandle eid, int argc, struct MprVar **argv) +{ + mpr_ReturnString(eid, SAMBA_VERSION_STRING); + return 0; +} + + +static void (*ejs_exception_handler) (const char *) = NULL; + +_PUBLIC_ void ejs_exception(const char *reason) +{ + ejs_exception_handler(reason); +} + +/* + setup C functions that be called from ejs +*/ +void smb_setup_ejs_functions(void (*exception_handler)(const char *)) +{ + extern NTSTATUS ejs_init_security(void); + extern NTSTATUS ejs_init_initshutdown(void); + extern NTSTATUS smb_setup_ejs_reg(void); + extern NTSTATUS smb_setup_ejs_string(void); + extern NTSTATUS ejs_init_lsarpc(void); + extern NTSTATUS ejs_init_rpcecho(void); + extern NTSTATUS ejs_init_winreg(void); + extern NTSTATUS smb_setup_ejs_random(void); + extern NTSTATUS smb_setup_ejs_config(void); + extern NTSTATUS ejs_init_misc(void); + extern NTSTATUS ejs_init_netdfs(void); + extern NTSTATUS smb_setup_ejs_datablob(void); + extern NTSTATUS smb_setup_ejs_auth(void); + extern NTSTATUS smb_setup_ejs_nss(void); + extern NTSTATUS ejs_init_samr(void); + extern NTSTATUS ejs_init_wkssvc(void); + extern NTSTATUS smb_setup_ejs_system(void); + extern NTSTATUS smb_setup_ejs_ldb(void); + extern NTSTATUS ejs_init_svcctl(void); + extern NTSTATUS smb_setup_ejs_net(void); + extern NTSTATUS ejs_init_srvsvc(void); + extern NTSTATUS ejs_init_netlogon(void); + extern NTSTATUS ejs_init_drsuapi(void); + extern NTSTATUS ejs_init_irpc(void); + extern NTSTATUS ejs_init_eventlog(void); + init_module_fn static_init[] = { STATIC_smbcalls_MODULES }; + init_module_fn *shared_init; + + ejs_exception_handler = exception_handler; + + smb_setup_ejs_options(); + smb_setup_ejs_credentials(); + + shared_init = load_samba_modules(NULL, mprLpCtx(), "smbcalls"); + + run_init_functions(static_init); + run_init_functions(shared_init); + + talloc_free(shared_init); + + ejsDefineCFunction(-1, "typeof", ejs_typeof, NULL, MPR_VAR_SCRIPT_HANDLE); + ejsDefineCFunction(-1, "nativeTypeOf", ejs_typeof_native, NULL, MPR_VAR_SCRIPT_HANDLE); + ejsDefineStringCFunction(-1, "libinclude", ejs_libinclude, NULL, MPR_VAR_SCRIPT_HANDLE); + ejsDefineCFunction(-1, "version", ejs_version, NULL, MPR_VAR_SCRIPT_HANDLE); +} + diff --git a/source4/scripting/ejs/smbcalls.h b/source4/scripting/ejs/smbcalls.h new file mode 100644 index 0000000000..3aaf324b6e --- /dev/null +++ b/source4/scripting/ejs/smbcalls.h @@ -0,0 +1,42 @@ +/* + Unix SMB/CIFS implementation. + + provide hooks into smbd C calls from ejs scripts + + Copyright (C) Andrew Tridgell 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "lib/appweb/ejs/ejs.h" +#include "lib/ldb/include/ldb.h" + +void mpr_Return(int eid, struct MprVar); +NTSTATUS mprSetVar(struct MprVar *v, const char *name, struct MprVar val); +NTSTATUS mprGetVar(struct MprVar **v, const char *name); +void mprAddArray(struct MprVar *var, int i, struct MprVar v); +void mprSetCFunction(struct MprVar *obj, const char *name, MprCFunction fn); +void mprSetStringCFunction(struct MprVar *obj, const char *name, MprStringCFunction fn); + +struct smbcalls_context { + struct event_context *event_ctx; + struct messaging_context *msg_ctx; +}; + +struct ldb_context; +struct ldb_message; +struct cli_credentials; + +#include "param/param.h" +#include "scripting/ejs/proto.h" diff --git a/source4/scripting/ejs/smbcalls_auth.c b/source4/scripting/ejs/smbcalls_auth.c new file mode 100644 index 0000000000..b67bb7ed5b --- /dev/null +++ b/source4/scripting/ejs/smbcalls_auth.c @@ -0,0 +1,243 @@ +/* + Unix SMB/CIFS implementation. + + ejs auth functions + + Copyright (C) Simo Sorce 2005 + Copyright (C) Andrew Tridgell 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/appweb/ejs/ejs.h" +#include "auth/auth.h" +#include "auth/credentials/credentials.h" +#include "scripting/ejs/smbcalls.h" +#include "lib/events/events.h" +#include "lib/messaging/irpc.h" +#include "libcli/security/security.h" + +static int ejs_doauth(MprVarHandle eid, + TALLOC_CTX *tmp_ctx, struct MprVar *auth, + const char *username, const char *password, + const char *domain, const char *workstation, + struct socket_address *remote_host, + const char **auth_types) +{ + struct auth_usersupplied_info *user_info = NULL; + struct auth_serversupplied_info *server_info = NULL; + struct auth_session_info *session_info = NULL; + struct auth_context *auth_context; + struct MprVar *session_info_obj; + NTSTATUS nt_status; + bool set; + + struct smbcalls_context *c; + struct event_context *ev; + struct messaging_context *msg; + + /* Hope we can find an smbcalls_context somewhere up there... */ + c = talloc_find_parent_bytype(tmp_ctx, struct smbcalls_context); + if (c) { + ev = c->event_ctx; + msg = c->msg_ctx; + } else { + /* Hope we can find the event context somewhere up there... */ + ev = mprEventCtx(); + msg = messaging_client_init(tmp_ctx, lp_messaging_path(tmp_ctx, mprLpCtx()), + lp_iconv_convenience(mprLpCtx()), ev); + } + + if (auth_types) { + nt_status = auth_context_create_methods(tmp_ctx, auth_types, ev, msg, mprLpCtx(), &auth_context); + } else { + nt_status = auth_context_create(tmp_ctx, ev, msg, mprLpCtx(), &auth_context); + } + if (!NT_STATUS_IS_OK(nt_status)) { + mprSetPropertyValue(auth, "result", mprCreateBoolVar(false)); + mprSetPropertyValue(auth, "report", mprString("Auth System Failure")); + goto done; + } + + user_info = talloc(tmp_ctx, struct auth_usersupplied_info); + if (!user_info) { + mprSetPropertyValue(auth, "result", mprCreateBoolVar(false)); + mprSetPropertyValue(auth, "report", mprString("talloc failed")); + goto done; + } + + user_info->mapped_state = true; + user_info->client.account_name = username; + user_info->mapped.account_name = username; + user_info->client.domain_name = domain; + user_info->mapped.domain_name = domain; + + user_info->workstation_name = workstation; + + user_info->remote_host = remote_host; + + user_info->password_state = AUTH_PASSWORD_PLAIN; + user_info->password.plaintext = talloc_strdup(user_info, password); + + user_info->flags = USER_INFO_CASE_INSENSITIVE_USERNAME | + USER_INFO_DONT_CHECK_UNIX_ACCOUNT; + + user_info->logon_parameters = 0; + + nt_status = auth_check_password(auth_context, tmp_ctx, user_info, &server_info); + + /* Don't give the game away (any difference between no such + * user and wrong password) */ + nt_status = auth_nt_status_squash(nt_status); + + if (!NT_STATUS_IS_OK(nt_status)) { + mprSetPropertyValue(auth, "report", + mprString(talloc_strdup(mprMemCtx(), get_friendly_nt_error_msg(nt_status)))); + mprSetPropertyValue(auth, "result", mprCreateBoolVar(false)); + goto done; + } + + nt_status = auth_generate_session_info(tmp_ctx, mprEventCtx(), mprLpCtx(), server_info, &session_info); + if (!NT_STATUS_IS_OK(nt_status)) { + mprSetPropertyValue(auth, "report", mprString("Session Info generation failed")); + mprSetPropertyValue(auth, "result", mprCreateBoolVar(false)); + goto done; + } + + if (security_token_has_nt_authenticated_users(session_info->security_token)) { + mprSetPropertyValue(auth, "user_class", mprString("USER")); + set = true; + } + + if (security_token_has_builtin_administrators(session_info->security_token)) { + mprSetPropertyValue(auth, "user_class", mprString("ADMINISTRATOR")); + set = true; + } + + if (security_token_is_system(session_info->security_token)) { + mprSetPropertyValue(auth, "user_class", mprString("SYSTEM")); + set = true; + } + + if (security_token_is_anonymous(session_info->security_token)) { + mprSetPropertyValue(auth, "report", mprString("Anonymous login not permitted")); + mprSetPropertyValue(auth, "result", mprCreateBoolVar(false)); + goto done; + } + + if (!set) { + mprSetPropertyValue(auth, "report", mprString("Session Info generation failed")); + mprSetPropertyValue(auth, "result", mprCreateBoolVar(false)); + } + + session_info_obj = mprInitObject(eid, "session_info", 0, NULL); + + mprSetPtrChild(session_info_obj, "session_info", session_info); + talloc_steal(mprMemCtx(), session_info); + + mprSetProperty(auth, "session_info", session_info_obj); + mprSetPropertyValue(auth, "result", mprCreateBoolVar(server_info->authenticated)); + mprSetPropertyValue(auth, "username", mprString(server_info->account_name)); + mprSetPropertyValue(auth, "domain", mprString(server_info->domain_name)); + +done: + return 0; +} + +/* + perform user authentication, returning an array of results + +*/ +static int ejs_userAuth(MprVarHandle eid, int argc, struct MprVar **argv) +{ + TALLOC_CTX *tmp_ctx; + const char *username; + const char *password; + const char *domain; + const char *workstation; + struct MprVar auth; + struct cli_credentials *creds; + struct socket_address *remote_host; + const char *auth_types_unix[] = { "unix", NULL }; + + if (argc != 2 || argv[0]->type != MPR_TYPE_OBJECT || argv[1]->type != MPR_TYPE_OBJECT) { + ejsSetErrorMsg(eid, "userAuth invalid arguments, this function requires an object."); + return -1; + } + + /* get credential values from credentials object */ + creds = mprGetPtr(argv[0], "creds"); + if (creds == NULL) { + ejsSetErrorMsg(eid, "userAuth requires a 'creds' first parameter"); + return -1; + } + + remote_host = (struct socket_address *)mprGetPtr(argv[1], "socket_address"); + if (remote_host == NULL) { + ejsSetErrorMsg(eid, "userAuth requires a socket address second parameter"); + return -1; + } + + tmp_ctx = talloc_new(mprMemCtx()); + + username = cli_credentials_get_username(creds); + password = cli_credentials_get_password(creds); + domain = cli_credentials_get_domain(creds); + workstation = cli_credentials_get_workstation(creds); + + if (username == NULL || password == NULL || domain == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + talloc_free(tmp_ctx); + return 0; + } + + auth = mprObject("auth"); + + if (domain && (strcmp("SYSTEM USER", domain) == 0)) { + ejs_doauth(eid, tmp_ctx, &auth, username, password, domain, workstation, remote_host, auth_types_unix); + } else { + ejs_doauth(eid, tmp_ctx, &auth, username, password, domain, workstation, remote_host, NULL); + } + + mpr_Return(eid, auth); + talloc_free(tmp_ctx); + return 0; +} + +/* + initialise credentials ejs object +*/ +static int ejs_system_session(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct MprVar *obj = mprInitObject(eid, "session_info", argc, argv); + struct auth_session_info *session_info = system_session(mprMemCtx(), mprLpCtx()); + + if (session_info == NULL) { + return -1; + } + + mprSetPtrChild(obj, "session_info", session_info); + return 0; +} + +/* + setup C functions that be called from ejs +*/ +NTSTATUS smb_setup_ejs_auth(void) +{ + ejsDefineCFunction(-1, "userAuth", ejs_userAuth, NULL, MPR_VAR_SCRIPT_HANDLE); + ejsDefineCFunction(-1, "system_session", ejs_system_session, NULL, MPR_VAR_SCRIPT_HANDLE); + return NT_STATUS_OK; +} diff --git a/source4/scripting/ejs/smbcalls_config.c b/source4/scripting/ejs/smbcalls_config.c new file mode 100644 index 0000000000..eb673b3a23 --- /dev/null +++ b/source4/scripting/ejs/smbcalls_config.c @@ -0,0 +1,228 @@ +/* + Unix SMB/CIFS implementation. + + provide hooks into smbd C calls from ejs scripts + + Copyright (C) Andrew Tridgell 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "scripting/ejs/smbcalls.h" +#include "lib/appweb/ejs/ejs.h" +#include "param/loadparm.h" +#include "system/network.h" +#include "lib/socket/netif.h" +#include "param/param.h" + +/* + return a list of defined services +*/ +static int ejs_lpServices(MprVarHandle eid, int argc, char **argv) +{ + int i; + const char **list = NULL; + if (argc != 0) return -1; + + for (i=0;i<lp_numservices(mprLpCtx());i++) { + list = str_list_add(list, lp_servicename(lp_servicebynum(mprLpCtx(), i))); + } + talloc_steal(mprMemCtx(), list); + mpr_Return(eid, mprList("services", list)); + return 0; +} + + +/* + allow access to loadparm variables from inside ejs scripts in web apps + + can be called in 4 ways: + + v = lp.get("type:parm"); gets a parametric variable + v = lp.get("share", "type:parm"); gets a parametric variable on a share + v = lp.get("parm"); gets a global variable + v = lp.get("share", "parm"); gets a share variable + + the returned variable is a ejs object. It is an array object for lists. +*/ +static int ejs_lpGet(MprVarHandle eid, int argc, char **argv) +{ + struct parm_struct *parm = NULL; + void *parm_ptr = NULL; + int i; + + if (argc < 1) return -1; + + if (argc == 2) { + struct loadparm_service *service; + /* its a share parameter */ + service = lp_service(mprLpCtx(), argv[0]); + if (service == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + if (strchr(argv[1], ':')) { + /* its a parametric option on a share */ + const char *type = talloc_strndup(mprMemCtx(), + argv[1], + strcspn(argv[1], ":")); + const char *option = strchr(argv[1], ':') + 1; + const char *value; + if (type == NULL || option == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + value = lp_get_parametric(mprLpCtx(), service, type, option); + if (value == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + mpr_ReturnString(eid, value); + return 0; + } + + parm = lp_parm_struct(argv[1]); + if (parm == NULL || parm->class == P_GLOBAL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + parm_ptr = lp_parm_ptr(mprLpCtx(), service, parm); + } else if (strchr(argv[0], ':')) { + /* its a global parametric option */ + const char *type = talloc_strndup(mprMemCtx(), + argv[0], strcspn(argv[0], ":")); + const char *option = strchr(argv[0], ':') + 1; + const char *value; + if (type == NULL || option == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + value = lp_get_parametric(mprLpCtx(), NULL, type, option); + if (value == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + mpr_ReturnString(eid, value); + return 0; + } else { + /* its a global parameter */ + parm = lp_parm_struct(argv[0]); + if (parm == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + parm_ptr = lp_parm_ptr(mprLpCtx(), NULL, parm); + } + + if (parm == NULL || parm_ptr == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + + /* construct and return the right type of ejs object */ + switch (parm->type) { + case P_STRING: + case P_USTRING: + mpr_ReturnString(eid, *(char **)parm_ptr); + break; + case P_BOOL: + mpr_Return(eid, mprCreateBoolVar(*(bool *)parm_ptr)); + break; + case P_INTEGER: + case P_OCTAL: + case P_BYTES: + mpr_Return(eid, mprCreateIntegerVar(*(int *)parm_ptr)); + break; + case P_ENUM: + for (i=0; parm->enum_list[i].name; i++) { + if (*(int *)parm_ptr == parm->enum_list[i].value) { + mpr_ReturnString(eid, parm->enum_list[i].name); + return 0; + } + } + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + case P_LIST: + mpr_Return(eid, mprList(parm->label, *(const char ***)parm_ptr)); + break; + } + return 0; +} + +/* + v = lp.filename(); obtain filename +*/ +static int ejs_lpFilename(MprVarHandle eid, int argc, char **argv) +{ + mpr_ReturnString(eid, lp_configfile(mprLpCtx())); + return 0; +} + +/* + set a smb.conf parameter. Only sets in memory, not permanent + + can be called in 4 ways: + + ok = lp.set("parm", "value"); +*/ +static int ejs_lpSet(MprVarHandle eid, int argc, char **argv) +{ + if (argc != 2) { + ejsSetErrorMsg(eid, "lp.set invalid arguments"); + return -1; + } + + mpr_Return(eid, mprCreateBoolVar(lp_set_cmdline(mprLpCtx(), argv[0], argv[1]))); + return 0; +} + +/* + reload smb.conf + + ok = lp.reload(); +*/ +static int ejs_lpReload(MprVarHandle eid, int argc, char **argv) +{ + bool ret; + const char *filename = lp_configfile(mprLpCtx()); + + ret = lp_load(mprLpCtx(), filename); + mpr_Return(eid, mprCreateBoolVar(ret)); + return 0; +} + +/* + initialise loadparm ejs subsystem +*/ +static int ejs_loadparm_init(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct MprVar *obj = mprInitObject(eid, "loadparm", argc, argv); + + mprSetStringCFunction(obj, "get", ejs_lpGet); + mprSetStringCFunction(obj, "set", ejs_lpSet); + mprSetStringCFunction(obj, "reload", ejs_lpReload); + mprSetStringCFunction(obj, "services", ejs_lpServices); + mprSetStringCFunction(obj, "filename", ejs_lpFilename); + return 0; +} + +/* + setup C functions that be called from ejs +*/ +NTSTATUS smb_setup_ejs_config(void) +{ + ejsDefineCFunction(-1, "loadparm_init", ejs_loadparm_init, NULL, MPR_VAR_SCRIPT_HANDLE); + return NT_STATUS_OK; +} diff --git a/source4/scripting/ejs/smbcalls_creds.c b/source4/scripting/ejs/smbcalls_creds.c new file mode 100644 index 0000000000..fd73f0751f --- /dev/null +++ b/source4/scripting/ejs/smbcalls_creds.c @@ -0,0 +1,275 @@ +/* + Unix SMB/CIFS implementation. + + provide hooks credentials calls + + Copyright (C) Andrew Tridgell 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "scripting/ejs/smbcalls.h" +#include "lib/appweb/ejs/ejs.h" +#include "lib/cmdline/popt_common.h" +#include "auth/credentials/credentials.h" + +/* + helper function to get the local objects credentials ptr +*/ +static struct cli_credentials *ejs_creds_get_credentials(int eid) +{ + struct cli_credentials *creds = (struct cli_credentials *)mprGetThisPtr(eid, "creds"); + if (creds == NULL) { + ejsSetErrorMsg(eid, "NULL ejs credentials"); + } + return creds; +} + +/* + get a domain +*/ +static int ejs_creds_get_domain(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + + mpr_Return(eid, mprString(cli_credentials_get_domain(creds))); + return 0; +} + + +/* + set a domain +*/ +static int ejs_creds_set_domain(MprVarHandle eid, int argc, char **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + if (argc != 1) { + ejsSetErrorMsg(eid, "bad arguments to set_domain"); + return -1; + } + + cli_credentials_set_domain(creds, argv[0], CRED_SPECIFIED); + mpr_Return(eid, mprCreateBoolVar(true)); + return 0; +} + + +/* + get a username +*/ +static int ejs_creds_get_username(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + + mpr_Return(eid, mprString(cli_credentials_get_username(creds))); + return 0; +} + + +/* + set a username +*/ +static int ejs_creds_set_username(MprVarHandle eid, int argc, char **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + if (argc != 1) { + ejsSetErrorMsg(eid, "bad arguments to set_username"); + return -1; + } + + cli_credentials_set_username(creds, argv[0], CRED_SPECIFIED); + mpr_Return(eid, mprCreateBoolVar(true)); + return 0; +} + + +/* + get user password +*/ +static int ejs_creds_get_password(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + + mpr_Return(eid, mprString(cli_credentials_get_password(creds))); + return 0; +} + + +/* + set user password +*/ +static int ejs_creds_set_password(MprVarHandle eid, int argc, char **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + if (argc != 1) { + ejsSetErrorMsg(eid, "bad arguments to set_password"); + return -1; + } + + cli_credentials_set_password(creds, argv[0], CRED_SPECIFIED); + mpr_Return(eid, mprCreateBoolVar(true)); + return 0; +} + + +/* + set realm +*/ +static int ejs_creds_set_realm(MprVarHandle eid, int argc, char **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + if (argc != 1) { + ejsSetErrorMsg(eid, "bad arguments to set_realm"); + return -1; + } + + cli_credentials_set_realm(creds, argv[0], CRED_SPECIFIED); + mpr_Return(eid, mprCreateBoolVar(true)); + return 0; +} + + +/* + get realm +*/ +static int ejs_creds_get_realm(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + + mpr_Return(eid, mprString(cli_credentials_get_realm(creds))); + return 0; +} + + +/* + set workstation +*/ +static int ejs_creds_set_workstation(MprVarHandle eid, int argc, char **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + if (argc != 1) { + ejsSetErrorMsg(eid, "bad arguments to set_workstation"); + return -1; + } + + cli_credentials_set_workstation(creds, argv[0], CRED_SPECIFIED); + mpr_Return(eid, mprCreateBoolVar(true)); + return 0; +} + + +/* + get workstation +*/ +static int ejs_creds_get_workstation(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + + mpr_Return(eid, mprString(cli_credentials_get_workstation(creds))); + return 0; +} + +/* + set machine account +*/ +static int ejs_creds_set_machine_account(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct cli_credentials *creds = ejs_creds_get_credentials(eid); + if (argc != 0) { + ejsSetErrorMsg(eid, "bad arguments to set_machine_account"); + return -1; + } + + if (NT_STATUS_IS_OK(cli_credentials_set_machine_account(creds, mprLpCtx()))) { + mpr_Return(eid, mprCreateBoolVar(true)); + } else { + mpr_Return(eid, mprCreateBoolVar(false)); + } + return 0; +} + + +/* + initialise credentials ejs object +*/ +static int ejs_credentials_obj(struct MprVar *obj, struct cli_credentials *creds) +{ + mprSetPtrChild(obj, "creds", creds); + + /* setup our object methods */ + mprSetCFunction(obj, "get_domain", ejs_creds_get_domain); + mprSetStringCFunction(obj, "set_domain", ejs_creds_set_domain); + mprSetCFunction(obj, "get_username", ejs_creds_get_username); + mprSetStringCFunction(obj, "set_username", ejs_creds_set_username); + mprSetCFunction(obj, "get_password", ejs_creds_get_password); + mprSetStringCFunction(obj, "set_password", ejs_creds_set_password); + mprSetCFunction(obj, "get_realm", ejs_creds_get_realm); + mprSetStringCFunction(obj, "set_realm", ejs_creds_set_realm); + mprSetCFunction(obj, "get_workstation", ejs_creds_get_workstation); + mprSetStringCFunction(obj, "set_workstation", ejs_creds_set_workstation); + mprSetCFunction(obj, "set_machine_account", ejs_creds_set_machine_account); + + return 0; +} + + +struct MprVar mprCredentials(struct cli_credentials *creds) +{ + struct MprVar mpv = mprObject("credentials"); + + ejs_credentials_obj(&mpv, creds); + + return mpv; +} + + +/* + initialise credentials ejs object +*/ +static int ejs_credentials_init(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct cli_credentials *creds; + struct MprVar *obj = mprInitObject(eid, "credentials", argc, argv); + + creds = cli_credentials_init(mprMemCtx()); + if (creds == NULL) { + return -1; + } + + cli_credentials_set_conf(creds, mprLpCtx()); + + return ejs_credentials_obj(obj, creds); +} + +/* + initialise cmdline credentials ejs object +*/ +int ejs_credentials_cmdline(int eid, int argc, struct MprVar **argv) +{ + struct MprVar *obj = mprInitObject(eid, "credentials", argc, argv); + if (talloc_reference(mprMemCtx(), cmdline_credentials) == NULL) { + return -1; + } + return ejs_credentials_obj(obj, cmdline_credentials); +} + +/* + setup C functions that be called from ejs +*/ +void smb_setup_ejs_credentials(void) +{ + ejsDefineCFunction(-1, "credentials_init", ejs_credentials_init, NULL, MPR_VAR_SCRIPT_HANDLE); +} + diff --git a/source4/scripting/ejs/smbcalls_ldb.c b/source4/scripting/ejs/smbcalls_ldb.c new file mode 100644 index 0000000000..4a157945af --- /dev/null +++ b/source4/scripting/ejs/smbcalls_ldb.c @@ -0,0 +1,772 @@ +/* + Unix SMB/CIFS implementation. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 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 "ldb_wrap.h" +#include "dsdb/samdb/samdb.h" +#include "librpc/ndr/libndr.h" +#include "libcli/security/security.h" + +/* + get the connected db + */ +static struct ldb_context *ejs_get_ldb_context(int eid) +{ + struct ldb_context *ldb = (struct ldb_context *)mprGetThisPtr(eid, "db"); + if (ldb == NULL) { + ejsSetErrorMsg(eid, "invalid ldb connection"); + } + return ldb; +} + +/* + perform an ldb search, returning an array of results + + syntax: + res = ldb.search("expression"); + var attrs = new Array("attr1", "attr2", "attr3"); + ldb.search("expression", attrs); + var basedn = "cn=this,dc=is,dc=a,dc=test"; + 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) +{ + const char **attrs = NULL; + const char *expression; + const char *base = NULL; + struct ldb_dn *basedn = NULL; + int scope = LDB_SCOPE_DEFAULT; + TALLOC_CTX *tmp_ctx = talloc_new(mprMemCtx()); + struct ldb_context *ldb; + int ret; + struct ldb_control **parsed_controls = NULL; + struct ldb_result *res=NULL; + struct ldb_request *req; + + /* validate arguments */ + if (argc < 1 || argc > 5) { + ejsSetErrorMsg(eid, "ldb.search invalid number of arguments"); + goto failed; + } + if (argc > 3 && argv[3]->type != MPR_TYPE_OBJECT) { + ejsSetErrorMsg(eid, "ldb.search attributes must be an object"); + goto failed; + } + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + expression = mprToString(argv[0]); + if (argc > 1) { + base = mprToString(argv[1]); + /* a null basedn is valid */ + } + if (base != 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]); + switch (scope) { + case LDB_SCOPE_DEFAULT: + case LDB_SCOPE_BASE: + case LDB_SCOPE_ONELEVEL: + case LDB_SCOPE_SUBTREE: + break; /* ok */ + default: + ejsSetErrorMsg(eid, "ldb.search invalid scope"); + goto failed; + } + } + if (argc > 3) { + attrs = mprToList(tmp_ctx, argv[3]); + } + 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, mprLdbResult(ldb, ret, NULL)); + } else { + mpr_Return(eid, mprLdbResult(ldb, ret, res)); + } + + talloc_free(tmp_ctx); + return 0; + +failed: + talloc_free(tmp_ctx); + return -1; +} + + +/* + perform an ldb add or modify +*/ +static int ejs_ldbAddModify(MprVarHandle eid, int argc, struct MprVar **argv, + int fn(struct ldb_context *, const struct ldb_message *)) +{ + const char *ldifstring; + struct ldb_context *ldb; + struct ldb_ldif *ldif; + int ret = 0, count=0; + + if (argc != 1) { + ejsSetErrorMsg(eid, "ldb.add/modify invalid arguments"); + return -1; + } + + ldifstring = mprToString(argv[0]); + if (ldifstring == NULL) { + ejsSetErrorMsg(eid, "ldb.add/modify invalid arguments"); + return -1; + } + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + while ((ldif = ldb_ldif_read_string(ldb, &ldifstring))) { + count++; + ret = fn(ldb, ldif->msg); + talloc_free(ldif); + if (ret != 0) break; + } + + if (count == 0) { + ejsSetErrorMsg(eid, "ldb.add/modify invalid ldif"); + return -1; + } + + mpr_Return(eid, mprLdbResult(ldb, ret, NULL)); + return 0; +} + + +/* + perform an ldb delete + usage: + ok = ldb.delete(dn); +*/ +static int ejs_ldbDelete(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct ldb_dn *dn; + struct ldb_context *ldb; + int ret; + + if (argc != 1) { + ejsSetErrorMsg(eid, "ldb.delete invalid arguments"); + return -1; + } + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + dn = ldb_dn_new(ldb, ldb, mprToString(argv[0])); + if ( ! ldb_dn_validate(dn)) { + ejsSetErrorMsg(eid, "ldb.delete malformed dn"); + return -1; + } + + ret = ldb_delete(ldb, dn); + + talloc_free(dn); + + mpr_Return(eid, mprLdbResult(ldb, ret, NULL)); + return 0; +} + +/* + perform an ldb rename + usage: + ok = ldb.rename(dn1, dn2); +*/ +static int ejs_ldbRename(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct ldb_dn *dn1, *dn2; + struct ldb_context *ldb; + int ret; + + if (argc != 2) { + ejsSetErrorMsg(eid, "ldb.rename invalid arguments"); + return -1; + } + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + 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; + } + + ret = ldb_rename(ldb, dn1, dn2); + + talloc_free(dn1); + talloc_free(dn2); + + mpr_Return(eid, mprLdbResult(ldb, ret, NULL)); + return 0; +} + +/* + get last error message + usage: + ok = ldb.errstring(); +*/ +static int ejs_ldbErrstring(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct ldb_context *ldb; + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + mpr_Return(eid, mprString(ldb_errstring(ldb))); + 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 add + + syntax: + ok = ldb.add(ldifstring); +*/ +static int ejs_ldbAdd(MprVarHandle eid, int argc, struct MprVar **argv) +{ + return ejs_ldbAddModify(eid, argc, argv, ldb_add); +} + +/* + perform an ldb modify + + syntax: + ok = ldb.modify(ldifstring); +*/ +static int ejs_ldbModify(MprVarHandle eid, int argc, struct MprVar **argv) +{ + return ejs_ldbAddModify(eid, argc, argv, ldb_modify); +} + +/* + connect to a database + 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) { + ejsSetErrorMsg(eid, "ldb.connect invalid arguments"); + 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(), mprEventCtx(), mprLpCtx(), dbfile, + session_info, creds, + 0, (const char **)(argv+1)); + if (ldb == NULL) { + ejsSetErrorMsg(eid, "ldb.connect failed to open %s", dbfile); + } + + mprSetThisPtr(eid, "db", ldb); + mpr_Return(eid, mprCreateBoolVar(ldb != NULL)); + return 0; +} + + +/* + 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; +} + +/* + set a particular invocationId against the running LDB + 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; +} + +/* + attach a particular ntds objectGUID against the current ldb + usage: + ok = ldb.set_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; +} + +/* + attach a particular domain SID against the current ldb + usage: + ok = ldb.set_domain_sid("S-S-1-5-21-3065342217-3567412576-2214182334"); +*/ +static int ejs_ldb_set_domain_sid(MprVarHandle eid, int argc, char **argv) +{ + struct ldb_context *ldb; + struct dom_sid *dom_sid; + char *dom_sid_str; + bool ok; + + if (argc != 1) { + ejsSetErrorMsg(eid, "ldb.set_domain_sid invalid arguments"); + return -1; + } + + ldb = ejs_get_ldb_context(eid); + if (ldb == NULL) { + return -1; + } + + dom_sid_str = argv[0]; + + dom_sid = dom_sid_parse_talloc(NULL, dom_sid_str); + if (!dom_sid) { + ejsSetErrorMsg(eid, "ldb.set_domain_sid - failed to parse domain sid '%s'\n", + dom_sid_str); + return -1; + } + + ok = samdb_set_domain_sid(ldb, dom_sid); + talloc_free(dom_sid); + if (!ok) { + ejsSetErrorMsg(eid, "ldb.set_domain_sid - failed to set cached ntds invocationId\n"); + return -1; + } + + mpr_Return(eid, mprCreateBoolVar(ok)); + return 0; +} + +/* + initialise ldb ejs subsystem +*/ +static int ejs_ldb_init(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct MprVar *ldb = mprInitObject(eid, "ldb", argc, argv); + + mprSetStringCFunction(ldb, "connect", ejs_ldbConnect); + mprSetCFunction(ldb, "search", ejs_ldbSearch); + mprSetCFunction(ldb, "add", ejs_ldbAdd); + mprSetCFunction(ldb, "modify", ejs_ldbModify); + 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); + mprSetStringCFunction(ldb, "set_domain_sid", + ejs_ldb_set_domain_sid); + 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; +} + + +/* + setup C functions that be called from ejs +*/ +NTSTATUS smb_setup_ejs_ldb(void) +{ + ejsDefineCFunction(-1, "ldb_init", ejs_ldb_init, NULL, MPR_VAR_SCRIPT_HANDLE); + return NT_STATUS_OK; +} diff --git a/source4/scripting/ejs/smbcalls_options.c b/source4/scripting/ejs/smbcalls_options.c new file mode 100644 index 0000000000..93872baa40 --- /dev/null +++ b/source4/scripting/ejs/smbcalls_options.c @@ -0,0 +1,193 @@ +/* + Unix SMB/CIFS implementation. + + provide a command line options parsing function for ejs + + Copyright (C) Andrew Tridgell 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/cmdline/popt_common.h" +#include "scripting/ejs/smbcalls.h" + + +/* + usage: + options = GetOptions(argv, + "realm=s", + "enablexx", + "myint=i"); + + the special options POPT_COMMON_* options are recognised and replaced + with the Samba internal options + + resulting parsed options are placed in the options object + + additional command line arguments are placed in options.ARGV +*/ + +static int ejs_GetOptions(MprVarHandle eid, int argc, struct MprVar **argv) +{ + poptContext pc; + int opt; + struct { + const char *name; + struct poptOption *table; + const char *description; + } tables[] = { + { "POPT_AUTOHELP", poptHelpOptions, "Help options:" }, + { "POPT_COMMON_SAMBA", popt_common_samba, "Common Samba options:" }, + { "POPT_COMMON_CONNECTION", popt_common_connection, "Connection options:" }, + { "POPT_COMMON_CREDENTIALS", popt_common_credentials, "Authentication options:" }, + { "POPT_COMMON_VERSION", popt_common_version, "Common Samba options:" } + }; + + struct MprVar *options = mprInitObject(eid, "options", 0, NULL); + + TALLOC_CTX *tmp_ctx = talloc_new(mprMemCtx()); + struct poptOption *long_options = NULL; + int i, num_options = 0; + int opt_argc; + const char **opt_argv; + const char **opt_names = NULL; + const int BASE_OPTNUM = 0x100000; + + /* validate arguments */ + if (argc < 1 || argv[0]->type != MPR_TYPE_OBJECT) { + ejsSetErrorMsg(eid, "GetOptions invalid arguments"); + return -1; + } + + opt_argv = mprToArray(tmp_ctx, argv[0]); + opt_argc = str_list_length(opt_argv); + + long_options = talloc_array(tmp_ctx, struct poptOption, 1); + if (long_options == NULL) { + return -1; + } + + /* create the long_options array */ + for (i=1;i<argc;i++) { + const char *optstr = mprToString(argv[i]); + int t, opt_type = POPT_ARG_NONE; + const char *s; + if (argv[i]->type != MPR_TYPE_STRING) { + ejsSetErrorMsg(eid, "GetOptions string argument"); + return -1; + } + + long_options = talloc_realloc(tmp_ctx, long_options, + struct poptOption, num_options+2); + if (long_options == NULL) { + return -1; + } + ZERO_STRUCT(long_options[num_options]); + + /* see if its one of the special samba option tables */ + for (t=0;t<ARRAY_SIZE(tables);t++) { + if (strcmp(tables[t].name, optstr) == 0) { + break; + } + } + if (t < ARRAY_SIZE(tables)) { + opt_names = str_list_add(opt_names, optstr); + talloc_steal(tmp_ctx, opt_names); + long_options[num_options].argInfo = POPT_ARG_INCLUDE_TABLE; + long_options[num_options].arg = tables[t].table; + long_options[num_options].descrip = tables[t].description; + num_options++; + continue; + } + + s = strchr(optstr, '='); + if (s) { + char *name = talloc_strndup(tmp_ctx, optstr, (int)(s-optstr)); + opt_names = str_list_add(opt_names, name); + if (s[1] == 's') { + opt_type = POPT_ARG_STRING; + } else if (s[1] == 'i') { + opt_type = POPT_ARG_INT; + } else { + ejsSetErrorMsg(eid, "GetOptions invalid option type"); + return -1; + } + talloc_free(name); + } else { + opt_names = str_list_add(opt_names, optstr); + } + talloc_steal(tmp_ctx, opt_names); + if (strlen(opt_names[num_options]) == 1) { + long_options[num_options].shortName = opt_names[num_options][0]; + } else { + long_options[num_options].longName = opt_names[num_options]; + } + long_options[num_options].argInfo = opt_type; + long_options[num_options].val = num_options + BASE_OPTNUM; + num_options++; + } + + ZERO_STRUCT(long_options[num_options]); + + pc = poptGetContext("smbscript", opt_argc, opt_argv, long_options, 0); + + /* parse the options */ + while((opt = poptGetNextOpt(pc)) != -1) { + const char *arg; + + if (opt < BASE_OPTNUM || opt >= num_options + BASE_OPTNUM) { + char *err; + err = talloc_asprintf(tmp_ctx, "%s: %s", + poptBadOption(pc, POPT_BADOPTION_NOALIAS), + poptStrerror(opt)); + mprSetVar(options, "ERROR", mprString(err)); + talloc_free(tmp_ctx); + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + opt -= BASE_OPTNUM; + arg = poptGetOptArg(pc); + if (arg == NULL) { + mprSetVar(options, opt_names[opt], mprCreateBoolVar(1)); + } else if (long_options[opt].argInfo == POPT_ARG_INT) { + int v = strtol(arg, NULL, 0); + mprSetVar(options, opt_names[opt], mprCreateIntegerVar(v)); + } else { + mprSetVar(options, opt_names[opt], mprString(arg)); + } + } + + /* setup options.argv list */ + mprSetVar(options, "ARGV", mprList("ARGV", poptGetArgs(pc))); + + poptFreeContext(pc); + + talloc_free(tmp_ctx); + + /* setup methods */ + mprSetCFunction(options, "get_credentials", ejs_credentials_cmdline); + + return 0; +} + + + +/* + setup C functions that be called from ejs +*/ +void smb_setup_ejs_options(void) +{ + ejsDefineCFunction(-1, "GetOptions", ejs_GetOptions, NULL, MPR_VAR_SCRIPT_HANDLE); +} diff --git a/source4/scripting/ejs/smbcalls_string.c b/source4/scripting/ejs/smbcalls_string.c new file mode 100644 index 0000000000..541303ff2d --- /dev/null +++ b/source4/scripting/ejs/smbcalls_string.c @@ -0,0 +1,529 @@ +/* + Unix SMB/CIFS implementation. + + provide access to string functions + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Jelmer Vernooij 2005 (substr) + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "scripting/ejs/smbcalls.h" +#include "lib/appweb/ejs/ejs.h" + +/* + usage: + var len = strlen(str); +*/ +static int ejs_strlen(MprVarHandle eid, int argc, char **argv) +{ + if (argc != 1) { + ejsSetErrorMsg(eid, "strlen invalid arguments"); + return -1; + } + mpr_Return(eid, mprCreateIntegerVar(strlen_m(argv[0]))); + return 0; +} + +/* + usage: + var s = strlower("UPPER"); +*/ +static int ejs_strlower(MprVarHandle eid, int argc, char **argv) +{ + char *s; + if (argc != 1) { + ejsSetErrorMsg(eid, "strlower invalid arguments"); + return -1; + } + s = strlower_talloc(mprMemCtx(), argv[0]); + mpr_Return(eid, mprString(s)); + talloc_free(s); + return 0; +} + +/* + usage: + var s = strupper("lower"); +*/ +static int ejs_strupper(MprVarHandle eid, int argc, char **argv) +{ + char *s; + if (argc != 1) { + ejsSetErrorMsg(eid, "strupper invalid arguments"); + return -1; + } + s = strupper_talloc(mprMemCtx(), argv[0]); + mpr_Return(eid, mprString(s)); + talloc_free(s); + return 0; +} + +/* + usage: + var s = strstr(string, substring); +*/ +static int ejs_strstr(MprVarHandle eid, int argc, char **argv) +{ + char *s; + if (argc != 2) { + ejsSetErrorMsg(eid, "strstr invalid arguments"); + return -1; + } + s = strstr(argv[0], argv[1]); + mpr_Return(eid, mprString(s)); + return 0; +} + +/* + usage: + var s = strspn(string, legal_chars_string); +*/ +static int ejs_strspn(MprVarHandle eid, int argc, char **argv) +{ + int len; + if (argc != 2) { + ejsSetErrorMsg(eid, "strspn invalid arguments"); + return -1; + } + len = strspn(argv[0], argv[1]); + mpr_Return(eid, mprCreateIntegerVar(len)); + return 0; +} + +/* + usage: + list = split(".", "a.foo.bar"); + list = split(".", "a.foo.bar", count); + + count is an optional count of how many splits to make + + NOTE: does not take a regular expression, unlike perl split() +*/ +static int ejs_split(MprVarHandle eid, int argc, struct MprVar **argv) +{ + const char *separator, *s; + char *p; + struct MprVar ret; + int count = 0, maxcount=0; + TALLOC_CTX *tmp_ctx = talloc_new(mprMemCtx()); + if (argc < 2 || + argv[0]->type != MPR_TYPE_STRING || + argv[1]->type != MPR_TYPE_STRING) { + ejsSetErrorMsg(eid, "split invalid arguments"); + return -1; + } + separator = mprToString(argv[0]); + s = mprToString(argv[1]); + if (argc == 3) { + maxcount = mprToInt(argv[2]); + } + + ret = mprArray("list"); + + while ((p = strstr(s, separator))) { + char *s2 = talloc_strndup(tmp_ctx, s, (int)(p-s)); + mprAddArray(&ret, count++, mprString(s2)); + talloc_free(s2); + s = p + strlen(separator); + if (maxcount != 0 && count >= maxcount) { + break; + } + } + if (*s) { + mprAddArray(&ret, count++, mprString(s)); + } + talloc_free(tmp_ctx); + mpr_Return(eid, ret); + return 0; +} + +/* + usage: + str = substr(orig[, start_offset[, length]]); + + special cases: + if start_offset < 0 then start_offset+=strlen(orig) + if length < 0 then length+=strlen(orig)-start_offset + + (as found in many other languages) +*/ +static int ejs_substr(MprVarHandle eid, int argc, struct MprVar **argv) +{ + int start_offset = 0; + int length = 0; + const char *orig; + char *target; + + if (argc < 1 || argc > 3 || + argv[0]->type != MPR_TYPE_STRING) { + ejsSetErrorMsg(eid, "substr invalid arguments"); + return -1; + } + + if (argc == 1) { + mpr_Return(eid, *argv[0]); + return 0; + } + + orig = mprToString(argv[0]); + start_offset = mprToInt(argv[1]); + length = strlen(orig); + if (start_offset < 0) start_offset += strlen(orig); + if (start_offset < 0 || start_offset > strlen(orig)) { + ejsSetErrorMsg(eid, "substr arg 2 out of bounds ([%s], %d)", orig, start_offset); + return -1; + } + + if (argc == 3) { + length = mprToInt(argv[2]); + if (length < 0) length += strlen(orig) - start_offset; + if (length < 0 || length+start_offset > strlen(orig)) { + ejsSetErrorMsg(eid, "substr arg 3 out of bounds ([%s], %d, %d)", orig, start_offset, length); + return -1; + } + } + + target = talloc_strndup(mprMemCtx(), orig+start_offset, length); + + mpr_Return(eid, mprString(target)); + + talloc_free(target); + + return 0; +} + +/* + usage: + str = join("DC=", list); +*/ +static int ejs_join(MprVarHandle eid, int argc, struct MprVar **argv) +{ + int i; + const char *separator; + char *ret = NULL; + const char **list; + TALLOC_CTX *tmp_ctx = talloc_new(mprMemCtx()); + if (argc != 2 || + argv[0]->type != MPR_TYPE_STRING || + argv[1]->type != MPR_TYPE_OBJECT) { + ejsSetErrorMsg(eid, "join invalid arguments"); + return -1; + } + + separator = mprToString(argv[0]); + list = mprToArray(tmp_ctx, argv[1]); + + if (list == NULL || list[0] == NULL) { + talloc_free(tmp_ctx); + mpr_Return(eid, mprString(NULL)); + return 0; + } + + ret = talloc_strdup(tmp_ctx, list[0]); + if (ret == NULL) { + goto failed; + } + for (i=1;list[i];i++) { + ret = talloc_asprintf_append_buffer(ret, "%s%s", separator, list[i]); + if (ret == NULL) { + goto failed; + } + } + mpr_Return(eid, mprString(ret)); + talloc_free(tmp_ctx); + return 0; +failed: + ejsSetErrorMsg(eid, "out of memory"); + return -1; +} + + +/* + blergh, C certainly makes this hard! + usage: + str = sprintf("i=%d s=%7s", 7, "foo"); +*/ +typedef char *(*_asprintf_append_t)(char *, const char *, ...); +static int ejs_sprintf(MprVarHandle eid, int argc, struct MprVar **argv) +{ + const char *format; + const char *p; + char *ret; + int a = 1; + _asprintf_append_t _asprintf_append; + TALLOC_CTX *tmp_ctx; + if (argc < 1 || argv[0]->type != MPR_TYPE_STRING) { + ejsSetErrorMsg(eid, "sprintf invalid arguments"); + return -1; + } + format = mprToString(argv[0]); + tmp_ctx = talloc_new(mprMemCtx()); + ret = talloc_strdup(tmp_ctx, ""); + + /* avoid all the format string warnings */ + _asprintf_append = (_asprintf_append_t)talloc_asprintf_append_buffer; + + /* + hackity hack ... + */ + while ((p = strchr(format, '%'))) { + char *fmt2; + int len, len_count=0; + char *tstr; + ret = talloc_asprintf_append_buffer(ret, "%*.*s", + (int)(p-format), (int)(p-format), + format); + if (ret == NULL) goto failed; + format += (int)(p-format); + len = strcspn(p+1, "dxuiofgGpXeEFcs%") + 1; + fmt2 = talloc_strndup(tmp_ctx, p, len+1); + if (fmt2 == NULL) goto failed; + len_count = count_chars(fmt2, '*'); + /* find the type string */ + tstr = &fmt2[len]; + while (tstr > fmt2 && isalpha((unsigned char)tstr[-1])) { + tstr--; + } + if (strcmp(tstr, "%") == 0) { + ret = talloc_asprintf_append_buffer(ret, "%%"); + if (ret == NULL) { + goto failed; + } + format += len+1; + continue; + } + if (len_count > 2 || + argc < a + len_count + 1) { + ejsSetErrorMsg(eid, "sprintf: not enough arguments for format"); + goto failed; + } +#define FMT_ARG(fn, type) do { \ + switch (len_count) { \ + case 0: \ + ret = _asprintf_append(ret, fmt2, \ + (type)fn(argv[a])); \ + break; \ + case 1: \ + ret = _asprintf_append(ret, fmt2, \ + (int)mprVarToNumber(argv[a]), \ + (type)fn(argv[a+1])); \ + break; \ + case 2: \ + ret = _asprintf_append(ret, fmt2, \ + (int)mprVarToNumber(argv[a]), \ + (int)mprVarToNumber(argv[a+1]), \ + (type)fn(argv[a+2])); \ + break; \ + } \ + a += len_count + 1; \ + if (ret == NULL) { \ + goto failed; \ + } \ +} while (0) + + if (strcmp(tstr, "s")==0) FMT_ARG(mprToString, const char *); + else if (strcmp(tstr, "c")==0) FMT_ARG(*mprToString, char); + else if (strcmp(tstr, "d")==0) FMT_ARG(mprVarToNumber, int); + else if (strcmp(tstr, "ld")==0) FMT_ARG(mprVarToNumber, long); + else if (strcmp(tstr, "lld")==0) FMT_ARG(mprVarToNumber, long long); + else if (strcmp(tstr, "x")==0) FMT_ARG(mprVarToNumber, int); + else if (strcmp(tstr, "lx")==0) FMT_ARG(mprVarToNumber, long); + else if (strcmp(tstr, "llx")==0) FMT_ARG(mprVarToNumber, long long); + else if (strcmp(tstr, "X")==0) FMT_ARG(mprVarToNumber, int); + else if (strcmp(tstr, "lX")==0) FMT_ARG(mprVarToNumber, long); + else if (strcmp(tstr, "llX")==0) FMT_ARG(mprVarToNumber, long long); + else if (strcmp(tstr, "u")==0) FMT_ARG(mprVarToNumber, int); + else if (strcmp(tstr, "lu")==0) FMT_ARG(mprVarToNumber, long); + else if (strcmp(tstr, "llu")==0) FMT_ARG(mprVarToNumber, long long); + else if (strcmp(tstr, "i")==0) FMT_ARG(mprVarToNumber, int); + else if (strcmp(tstr, "li")==0) FMT_ARG(mprVarToNumber, long); + else if (strcmp(tstr, "lli")==0) FMT_ARG(mprVarToNumber, long long); + else if (strcmp(tstr, "o")==0) FMT_ARG(mprVarToNumber, int); + else if (strcmp(tstr, "lo")==0) FMT_ARG(mprVarToNumber, long); + else if (strcmp(tstr, "llo")==0) FMT_ARG(mprVarToNumber, long long); + else if (strcmp(tstr, "f")==0) FMT_ARG(mprVarToFloat, double); + else if (strcmp(tstr, "lf")==0) FMT_ARG(mprVarToFloat, double); + else if (strcmp(tstr, "g")==0) FMT_ARG(mprVarToFloat, double); + else if (strcmp(tstr, "lg")==0) FMT_ARG(mprVarToFloat, double); + else if (strcmp(tstr, "e")==0) FMT_ARG(mprVarToFloat, double); + else if (strcmp(tstr, "le")==0) FMT_ARG(mprVarToFloat, double); + else if (strcmp(tstr, "E")==0) FMT_ARG(mprVarToFloat, double); + else if (strcmp(tstr, "lE")==0) FMT_ARG(mprVarToFloat, double); + else if (strcmp(tstr, "F")==0) FMT_ARG(mprVarToFloat, double); + else if (strcmp(tstr, "lF")==0) FMT_ARG(mprVarToFloat, double); + else { + ejsSetErrorMsg(eid, "sprintf: unknown format string '%s'", fmt2); + goto failed; + } + format += len+1; + } + + ret = talloc_asprintf_append_buffer(ret, "%s", format); + mpr_Return(eid, mprString(ret)); + talloc_free(tmp_ctx); + return 0; + +failed: + talloc_free(tmp_ctx); + return -1; +} + +/* + used to build your own print function + str = vsprintf(args); +*/ +static int ejs_vsprintf(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct MprVar **args, *len, *v; + int i, ret, length; + if (argc != 1 || argv[0]->type != MPR_TYPE_OBJECT) { + ejsSetErrorMsg(eid, "vsprintf invalid arguments"); + return -1; + } + v = argv[0]; + len = mprGetProperty(v, "length", NULL); + if (len == NULL) { + ejsSetErrorMsg(eid, "vsprintf takes an array"); + return -1; + } + length = mprToInt(len); + args = talloc_array(mprMemCtx(), struct MprVar *, length); + if (args == NULL) { + return -1; + } + + for (i=0;i<length;i++) { + char idx[16]; + mprItoa(i, idx, sizeof(idx)); + args[i] = mprGetProperty(v, idx, NULL); + } + + ret = ejs_sprintf(eid, length, args); + talloc_free(args); + return ret; +} + + +/* + encode a string, replacing all non-alpha with %02x form +*/ +static int ejs_encodeURIComponent(MprVarHandle eid, int argc, char **argv) +{ + int i, j, count=0; + const char *s; + char *ret; + if (argc != 1) { + ejsSetErrorMsg(eid, "encodeURIComponent invalid arguments"); + return -1; + } + + s = argv[0]; + + for (i=0;s[i];i++) { + if (!isalnum(s[i])) count++; + } + + ret = talloc_array(mprMemCtx(), char, i + count*2 + 1); + if (ret == NULL) { + return -1; + } + for (i=j=0;s[i];i++,j++) { + if (!isalnum(s[i])) { + snprintf(ret+j, 4, "%%%02X", (unsigned)s[i]); + j += 2; + } else { + ret[j] = s[i]; + } + } + ret[j] = 0; + mpr_Return(eid, mprString(ret)); + talloc_free(ret); + return 0; +} + +/* + encode a string, replacing all non-alpha of %02x form +*/ +static int ejs_decodeURIComponent(MprVarHandle eid, int argc, char **argv) +{ + int i, j, count=0; + const char *s; + char *ret; + if (argc != 1) { + ejsSetErrorMsg(eid, "decodeURIComponent invalid arguments"); + return -1; + } + + s = argv[0]; + + ret = talloc_array(mprMemCtx(), char, strlen(s) + 1); + if (ret == NULL) { + return -1; + } + + for (i=j=0;s[i];i++,j++) { + if (s[i] == '%') { + unsigned c; + if (sscanf(s+i+1, "%02X", &c) != 1) { + ejsSetErrorMsg(eid, "decodeURIComponent bad format"); + return -1; + } + ret[j] = c; + i += 2; + } else { + ret[j] = s[i]; + } + if (!isalnum(s[i])) count++; + } + + ret[j] = 0; + mpr_Return(eid, mprString(ret)); + talloc_free(ret); + return 0; +} + +/* + initialise string ejs subsystem +*/ +static int ejs_string_init(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct MprVar *obj = mprInitObject(eid, "string", argc, argv); + + mprSetCFunction(obj, "substr", ejs_substr); + mprSetStringCFunction(obj, "strlen", ejs_strlen); + mprSetStringCFunction(obj, "strlower", ejs_strlower); + mprSetStringCFunction(obj, "strupper", ejs_strupper); + mprSetStringCFunction(obj, "strstr", ejs_strstr); + mprSetStringCFunction(obj, "strspn", ejs_strspn); + mprSetCFunction(obj, "split", ejs_split); + mprSetCFunction(obj, "join", ejs_join); + mprSetCFunction(obj, "sprintf", ejs_sprintf); + mprSetCFunction(obj, "vsprintf", ejs_vsprintf); + mprSetStringCFunction(obj, "encodeURIComponent", ejs_encodeURIComponent); + mprSetStringCFunction(obj, "decodeURIComponent", ejs_decodeURIComponent); + + return 0; +} + +/* + setup C functions that be called from ejs +*/ +NTSTATUS smb_setup_ejs_string(void) +{ + ejsDefineCFunction(-1, "string_init", ejs_string_init, NULL, MPR_VAR_SCRIPT_HANDLE); + return NT_STATUS_OK; +} diff --git a/source4/scripting/ejs/smbcalls_sys.c b/source4/scripting/ejs/smbcalls_sys.c new file mode 100644 index 0000000000..00599a55bc --- /dev/null +++ b/source4/scripting/ejs/smbcalls_sys.c @@ -0,0 +1,494 @@ +/* + Unix SMB/CIFS implementation. + + provide access to system functions + + Copyright (C) Andrew Tridgell 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 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 "system/time.h" +#include "system/network.h" +#include "lib/socket/netif.h" + +/* + return the list of configured network interfaces +*/ +static int ejs_sys_interfaces(MprVarHandle eid, int argc, struct MprVar **argv) +{ + int i, count; + struct MprVar ret = mprArray("interfaces"); + struct interface *ifaces; + + load_interfaces(NULL, lp_interfaces(mprLpCtx()), &ifaces); + + count = iface_count(ifaces); + for (i=0;i<count;i++) { + mprAddArray(&ret, i, mprString(iface_n_ip(ifaces, i))); + } + + talloc_free(ifaces); + mpr_Return(eid, ret); + return 0; +} + +/* + return the hostname from gethostname() +*/ +static int ejs_sys_hostname(MprVarHandle eid, int argc, struct MprVar **argv) +{ + char name[200]; + if (gethostname(name, sizeof(name)-1) == -1) { + ejsSetErrorMsg(eid, "gethostname failed - %s", strerror(errno)); + return -1; + } + mpr_Return(eid, mprString(name)); + return 0; +} + + +/* + return current time as seconds and microseconds +*/ +static int ejs_sys_gettimeofday(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct timeval tv = timeval_current(); + struct MprVar v = mprObject("timeval"); + struct MprVar sec = mprCreateIntegerVar(tv.tv_sec); + struct MprVar usec = mprCreateIntegerVar(tv.tv_usec); + + mprCreateProperty(&v, "sec", &sec); + mprCreateProperty(&v, "usec", &usec); + mpr_Return(eid, v); + return 0; +} + +/* + return current time as a 64 bit nttime value +*/ +static int ejs_sys_nttime(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct timeval tv = timeval_current(); + struct MprVar v = mprCreateNumberVar(timeval_to_nttime(&tv)); + mpr_Return(eid, v); + return 0; +} + +/* + return time as a 64 bit nttime value from a 32 bit time_t value +*/ +static int ejs_sys_unix2nttime(MprVarHandle eid, int argc, struct MprVar **argv) +{ + NTTIME nt; + struct MprVar v; + if (argc != 1 || !mprVarIsNumber(argv[0]->type)) { + ejsSetErrorMsg(eid, "sys_unix2nttime invalid arguments"); + return -1; + } + unix_to_nt_time(&nt, mprVarToNumber(argv[0])); + v = mprCreateNumberVar(nt); + mpr_Return(eid, v); + return 0; +} + +/* + return the GMT time represented by the struct tm argument, as a time_t value +*/ +static int ejs_sys_gmmktime(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct MprVar *o; + struct tm tm; + if (argc != 1 || !mprVarIsObject(argv[0]->type)) { + ejsSetErrorMsg(eid, "sys_gmmktime invalid arguments"); + return -1; + } + + o = argv[0]; +#define TM_EL(n) tm.n = mprVarToNumber(mprGetProperty(o, #n, NULL)) + TM_EL(tm_sec); + TM_EL(tm_min); + TM_EL(tm_hour); + TM_EL(tm_mday); + TM_EL(tm_mon); + TM_EL(tm_year); + TM_EL(tm_wday); + TM_EL(tm_yday); + TM_EL(tm_isdst); +#undef TM_EL + + mpr_Return(eid, mprCreateIntegerVar(mktime(&tm))); + return 0; +} + +/* + return the given time as a gmtime structure +*/ +static int ejs_sys_gmtime(MprVarHandle eid, int argc, struct MprVar **argv) +{ + time_t t; + struct MprVar ret; + struct tm *tm; + if (argc != 1 || !mprVarIsNumber(argv[0]->type)) { + ejsSetErrorMsg(eid, "sys_gmtime invalid arguments"); + return -1; + } + t = (time_t) mprVarToNumber(argv[0]); + tm = gmtime(&t); + if (tm == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + ret = mprObject("gmtime"); +#define TM_EL(n) mprSetVar(&ret, #n, mprCreateIntegerVar(tm->n)) + TM_EL(tm_sec); + TM_EL(tm_min); + TM_EL(tm_hour); + TM_EL(tm_mday); + TM_EL(tm_mon); + TM_EL(tm_year); + TM_EL(tm_wday); + TM_EL(tm_yday); + TM_EL(tm_isdst); +#undef TM_EL + + mpr_Return(eid, ret); + return 0; +} + +/* + return the given NT time as a time_t value +*/ +static int ejs_sys_nttime2unix(MprVarHandle eid, int argc, struct MprVar **argv) +{ + time_t t; + struct MprVar v; + if (argc != 1 || !mprVarIsNumber(argv[0]->type)) { + ejsSetErrorMsg(eid, "sys_ntgmtime invalid arguments"); + return -1; + } + t = nt_time_to_unix(mprVarToNumber(argv[0])); + v = mprCreateNumberVar(t); + mpr_Return(eid, v); + return 0; +} + +/* + return the given NT time as a gmtime structure +*/ +static int ejs_sys_ntgmtime(MprVarHandle eid, int argc, struct MprVar **argv) +{ + time_t t; + struct MprVar ret; + struct tm *tm; + if (argc != 1 || !mprVarIsNumber(argv[0]->type)) { + ejsSetErrorMsg(eid, "sys_ntgmtime invalid arguments"); + return -1; + } + t = nt_time_to_unix(mprVarToNumber(argv[0])); + tm = gmtime(&t); + if (tm == NULL) { + mpr_Return(eid, mprCreateUndefinedVar()); + return 0; + } + ret = mprObject("gmtime"); +#define TM_EL(n) mprSetVar(&ret, #n, mprCreateIntegerVar(tm->n)) + TM_EL(tm_sec); + TM_EL(tm_min); + TM_EL(tm_hour); + TM_EL(tm_mday); + TM_EL(tm_mon); + TM_EL(tm_year); + TM_EL(tm_wday); + TM_EL(tm_yday); + TM_EL(tm_isdst); +#undef TM_EL + + mpr_Return(eid, ret); + return 0; +} + +/* + return a ldap time string from a nttime +*/ +static int ejs_sys_ldaptime(MprVarHandle eid, int argc, struct MprVar **argv) +{ + char *s; + time_t t; + if (argc != 1 || !mprVarIsNumber(argv[0]->type)) { + ejsSetErrorMsg(eid, "sys_ldaptime invalid arguments"); + return -1; + } + t = nt_time_to_unix(mprVarToNumber(argv[0])); + s = ldb_timestring(mprMemCtx(), t); + mpr_Return(eid, mprString(s)); + talloc_free(s); + return 0; +} + +/* + return a http time string from a nttime +*/ +static int ejs_sys_httptime(MprVarHandle eid, int argc, struct MprVar **argv) +{ + char *s; + time_t t; + if (argc != 1 || !mprVarIsNumber(argv[0]->type)) { + ejsSetErrorMsg(eid, "sys_httptime invalid arguments"); + return -1; + } + t = nt_time_to_unix(mprVarToNumber(argv[0])); + s = http_timestring(mprMemCtx(), t); + mpr_Return(eid, mprString(s)); + talloc_free(s); + return 0; +} + +/* + unlink a file + ok = sys.unlink(fname); +*/ +static int ejs_sys_unlink(MprVarHandle eid, int argc, char **argv) +{ + int ret; + if (argc != 1) { + ejsSetErrorMsg(eid, "sys_unlink invalid arguments"); + return -1; + } + ret = unlink(argv[0]); + mpr_Return(eid, mprCreateBoolVar(ret == 0)); + return 0; +} + +/* + load a file as a string + usage: + string = sys.file_load(filename); +*/ +static int ejs_sys_file_load(MprVarHandle eid, int argc, char **argv) +{ + char *s; + if (argc != 1) { + ejsSetErrorMsg(eid, "sys_file_load invalid arguments"); + return -1; + } + + s = file_load(argv[0], NULL, mprMemCtx()); + mpr_Return(eid, mprString(s)); + talloc_free(s); + return 0; +} + +/* + save a file from a string + usage: + ok = sys.file_save(filename, str); +*/ +static int ejs_sys_file_save(MprVarHandle eid, int argc, char **argv) +{ + bool ret; + if (argc != 2) { + ejsSetErrorMsg(eid, "sys_file_save invalid arguments"); + return -1; + } + ret = file_save(argv[0], argv[1], strlen(argv[1])); + mpr_Return(eid, mprCreateBoolVar(ret)); + return 0; +} + +/* + mkdir() + usage: + ok = sys.mkdir(dirname, mode); +*/ +static int ejs_sys_mkdir(MprVarHandle eid, int argc, struct MprVar **argv) +{ + bool ret; + char *name; + if (argc != 2) { + ejsSetErrorMsg(eid, "sys_mkdir invalid arguments, need mkdir(dirname, mode)"); + return -1; + } + if (!mprVarIsString(argv[0]->type)) { + ejsSetErrorMsg(eid, "sys_mkdir dirname not a string"); + return -1; + } + if (!mprVarIsNumber(argv[1]->type)) { + ejsSetErrorMsg(eid, "sys_mkdir mode not a number"); + return -1; + } + mprVarToString(&name, 0, NULL, argv[0]); + ret = mkdir(name, mprVarToNumber(argv[1])); + mpr_Return(eid, mprCreateBoolVar(ret == 0)); + return 0; +} + + +/* + return fields of a stat() call +*/ +static struct MprVar mpr_stat(struct stat *st) +{ + struct MprVar ret; + ret = mprObject("stat"); + +#define ST_EL(n) mprSetVar(&ret, #n, mprCreateNumberVar(st->n)) + ST_EL(st_dev); + ST_EL(st_ino); + ST_EL(st_mode); + ST_EL(st_nlink); + ST_EL(st_uid); + ST_EL(st_gid); + ST_EL(st_rdev); + ST_EL(st_size); + ST_EL(st_blksize); + ST_EL(st_blocks); + ST_EL(st_atime); + ST_EL(st_mtime); + ST_EL(st_ctime); + + return ret; +} + +/* + usage: + var st = sys.stat(filename); + returns an object containing struct stat elements +*/ +static int ejs_sys_stat(MprVarHandle eid, int argc, char **argv) +{ + struct stat st; + /* validate arguments */ + if (argc != 1) { + ejsSetErrorMsg(eid, "sys.stat invalid arguments"); + return -1; + } + if (stat(argv[0], &st) != 0) { + mpr_Return(eid, mprCreateUndefinedVar()); + } else { + mpr_Return(eid, mpr_stat(&st)); + } + return 0; +} + +/* + usage: + var st = sys.lstat(filename); + returns an object containing struct stat elements +*/ +static int ejs_sys_lstat(MprVarHandle eid, int argc, char **argv) +{ + struct stat st; + /* validate arguments */ + if (argc != 1) { + ejsSetErrorMsg(eid, "sys.stat invalid arguments"); + return -1; + } + if (lstat(argv[0], &st) != 0) { + mpr_Return(eid, mprCreateUndefinedVar()); + } else { + mpr_Return(eid, mpr_stat(&st)); + } + return 0; +} + +/* + bitwise AND + usage: + var z = sys.bitAND(x, 0x70); +*/ +static int ejs_sys_bitAND(MprVarHandle eid, int argc, struct MprVar **argv) +{ + int x, y, z; + + if (argc != 2 || + !mprVarIsNumber(argv[0]->type) || + !mprVarIsNumber(argv[1]->type)) { + ejsSetErrorMsg(eid, "bitand invalid arguments"); + return -1; + } + x = mprToInt(argv[0]); + y = mprToInt(argv[1]); + z = x & y; + + mpr_Return(eid, mprCreateIntegerVar(z)); + return 0; +} + +/* + bitwise OR + usage: + var z = sys.bitOR(x, 0x70); +*/ +static int ejs_sys_bitOR(MprVarHandle eid, int argc, struct MprVar **argv) +{ + int x, y, z; + + if (argc != 2 || + !mprVarIsNumber(argv[0]->type) || + !mprVarIsNumber(argv[1]->type)) { + ejsSetErrorMsg(eid, "bitand invalid arguments"); + return -1; + } + x = mprToInt(argv[0]); + y = mprToInt(argv[1]); + z = x | y; + + mpr_Return(eid, mprCreateIntegerVar(z)); + return 0; +} + +/* + initialise sys ejs subsystem +*/ +static int ejs_sys_init(MprVarHandle eid, int argc, struct MprVar **argv) +{ + struct MprVar *obj = mprInitObject(eid, "sys", argc, argv); + + mprSetCFunction(obj, "interfaces", ejs_sys_interfaces); + mprSetCFunction(obj, "hostname", ejs_sys_hostname); + mprSetCFunction(obj, "nttime", ejs_sys_nttime); + mprSetCFunction(obj, "gettimeofday", ejs_sys_gettimeofday); + mprSetCFunction(obj, "unix2nttime", ejs_sys_unix2nttime); + mprSetCFunction(obj, "gmmktime", ejs_sys_gmmktime); + mprSetCFunction(obj, "gmtime", ejs_sys_gmtime); + mprSetCFunction(obj, "nttime2unix", ejs_sys_nttime2unix); + mprSetCFunction(obj, "ntgmtime", ejs_sys_ntgmtime); + mprSetCFunction(obj, "ldaptime", ejs_sys_ldaptime); + mprSetCFunction(obj, "httptime", ejs_sys_httptime); + mprSetCFunction(obj, "mkdir", ejs_sys_mkdir); + mprSetStringCFunction(obj, "unlink", ejs_sys_unlink); + mprSetStringCFunction(obj, "file_load", ejs_sys_file_load); + mprSetStringCFunction(obj, "file_save", ejs_sys_file_save); + mprSetStringCFunction(obj, "stat", ejs_sys_stat); + mprSetStringCFunction(obj, "lstat", ejs_sys_lstat); + mprSetCFunction(obj, "bitAND", ejs_sys_bitAND); + mprSetCFunction(obj, "bitOR", ejs_sys_bitOR); + + return 0; +} + + +/* + setup C functions that be called from ejs +*/ +NTSTATUS smb_setup_ejs_system(void) +{ + ejsDefineCFunction(-1, "sys_init", ejs_sys_init, NULL, MPR_VAR_SCRIPT_HANDLE); + return NT_STATUS_OK; +} diff --git a/source4/scripting/ejs/smbscript.c b/source4/scripting/ejs/smbscript.c new file mode 100644 index 0000000000..db9fc9affa --- /dev/null +++ b/source4/scripting/ejs/smbscript.c @@ -0,0 +1,129 @@ +/* + Unix SMB/CIFS implementation. + + Standalone client for ejs scripting. + + Copyright (C) Tim Potter <tpot@samba.org> 2005 + Copyright (C) Andrew Tridgell 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/appweb/ejs/ejs.h" +#include "lib/appweb/ejs/ejsInternal.h" +#include "scripting/ejs/smbcalls.h" +#include "auth/gensec/gensec.h" +#include "ldb/include/ldb.h" +#include "dynconfig/dynconfig.h" + +static EjsId eid; + +_NORETURN_ static void smbscript_ejs_exception(const char *reason) +{ + Ejs *ep = ejsPtr(eid); + ejsSetErrorMsg(eid, "%s", reason); + fprintf(stderr, "%s", ep->error); + exit(127); +} + +int main(int argc, const char **argv) +{ + EjsHandle handle = 0; + MprVar result; + char *emsg, *script; + size_t script_size; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + const char **argv_list = NULL; + const char *fname; + struct MprVar *return_var; + int exit_status, i; + struct loadparm_context *lp_ctx; + + fault_setup(argv[0]); + + global_loadparm = lp_ctx = loadparm_init(talloc_autofree_context()); + + if (getenv("SMB_CONF_PATH")) { + lp_load(lp_ctx, getenv("SMB_CONF_PATH")); + } else { + lp_load(lp_ctx, dyn_CONFIGFILE); + } + + gensec_init(lp_ctx); + mprSetCtx(mem_ctx); + + + if (argc < 2) { + fprintf(stderr, "You must supply a script name\n"); + exit(1); + } + + fname = argv[1]; + + if (ejsOpen(NULL, NULL, NULL) != 0) { + fprintf(stderr, "smbscript: ejsOpen(): unable to initialise " + "EJS subsystem\n"); + exit(127); + } + + smb_setup_ejs_functions(smbscript_ejs_exception); + + if ((eid = ejsOpenEngine(handle, 0)) == (EjsId)-1) { + fprintf(stderr, "smbscript: ejsOpenEngine(): unable to " + "initialise an EJS engine\n"); + exit(127); + } + + /* setup ARGV[] in the ejs environment */ + for (i=1;argv[i];i++) { + argv_list = str_list_add(argv_list, argv[i]); + } + talloc_steal(mem_ctx, argv_list); + mprSetVar(ejsGetGlobalObject(eid), "ARGV", mprList("ARGV", argv_list)); + + /* load the script and advance past interpreter line*/ + script = file_load(fname, &script_size, mem_ctx); + + if (!script) { + fprintf(stderr, "Unable to load script from '%s'\n", fname); + exit(1); + } + + /* allow scriptable js */ + if (strncmp(script, "#!", 2) == 0) { + script += strcspn(script, "\r\n"); + script += strspn(script, "\r\n"); + } + /* and this copes with the ugly exec hack */ + if (strncmp(script, "exec ", 5) == 0) { + script += strcspn(script, "\r\n"); + script += strspn(script, "\r\n"); + } + + /* run the script */ + if (ejsEvalScript(eid, script, &result, &emsg) == -1) { + fprintf(stderr, "smbscript: ejsEvalScript(): %s\n", emsg); + exit(127); + } + + return_var = ejsGetReturnValue(eid); + exit_status = mprVarToNumber(return_var); + + ejsClose(); + + talloc_free(mem_ctx); + + return exit_status; +} |