2 Unix SMB/CIFS implementation.
4 provide interfaces to rpc calls from ejs scripts
6 Copyright (C) Andrew Tridgell 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "scripting/ejs/smbcalls.h"
25 #include "lib/ejs/ejs.h"
26 #include "librpc/gen_ndr/ndr_echo.h"
27 #include "lib/cmdline/popt_common.h"
28 #include "lib/messaging/irpc.h"
29 #include "scripting/ejs/ejsrpc.h"
30 #include "dlinklist.h"
33 state of a irpc 'connection'
35 struct ejs_irpc_connection {
36 const char *server_name;
38 struct messaging_context *msg_ctx;
42 messaging clients need server IDs as well ...
44 #define EJS_ID_BASE 0x30000000
47 setup a context for talking to a irpc server
49 var conn = new Object();
50 status = irpc_connect(conn, "smb_server");
52 static int ejs_irpc_connect(MprVarHandle eid, int argc, struct MprVar **argv)
57 struct event_context *ev;
58 struct ejs_irpc_connection *p;
60 /* validate arguments */
62 argv[0]->type != MPR_TYPE_OBJECT ||
63 argv[1]->type != MPR_TYPE_STRING) {
64 ejsSetErrorMsg(eid, "rpc_connect invalid arguments");
70 p = talloc(conn, struct ejs_irpc_connection);
75 p->server_name = mprToString(argv[1]);
77 ev = talloc_find_parent_bytype(mprMemCtx(), struct event_context);
79 /* create a messaging context, looping as we have no way to
80 allocate temporary server ids automatically */
81 for (i=0;i<10000;i++) {
82 p->msg_ctx = messaging_init(p, EJS_ID_BASE + i, ev);
83 if (p->msg_ctx) break;
85 if (p->msg_ctx == NULL) {
86 ejsSetErrorMsg(eid, "irpc_connect unable to create a messaging context");
91 p->dest_ids = irpc_servers_byname(p->msg_ctx, p->server_name);
92 if (p->dest_ids == NULL || p->dest_ids[0] == 0) {
94 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
96 mprSetPtrChild(conn, "irpc", p);
97 status = NT_STATUS_OK;
100 mpr_Return(eid, mprNTSTATUS(status));
106 connect to an rpc server
108 var conn = new Object();
109 status = rpc_connect(conn, "ncacn_ip_tcp:localhost", "rpcecho");
111 static int ejs_rpc_connect(MprVarHandle eid, int argc, struct MprVar **argv)
113 const char *binding, *pipe_name;
114 const struct dcerpc_interface_table *iface;
116 struct dcerpc_pipe *p;
118 struct cli_credentials *creds = cmdline_credentials;
119 struct event_context *ev;
121 /* validate arguments */
123 argv[0]->type != MPR_TYPE_OBJECT ||
124 argv[1]->type != MPR_TYPE_STRING ||
125 argv[2]->type != MPR_TYPE_STRING) {
126 ejsSetErrorMsg(eid, "rpc_connect invalid arguments");
131 binding = mprToString(argv[1]);
132 pipe_name = mprToString(argv[2]);
134 iface = idl_iface_by_name(pipe_name);
136 status = NT_STATUS_OBJECT_NAME_INVALID;
141 creds = cli_credentials_init(mprMemCtx());
142 cli_credentials_guess(creds);
143 cli_credentials_set_username(creds, "", CRED_GUESSED);
144 cli_credentials_set_password(creds, "", CRED_GUESSED);
147 ev = talloc_find_parent_bytype(mprMemCtx(), struct event_context);
149 status = dcerpc_pipe_connect(conn, &p, binding,
150 iface->uuid, iface->if_version,
152 if (!NT_STATUS_IS_OK(status)) goto done;
154 /* callers don't allocate ref vars in the ejs interface */
155 p->conn->flags |= DCERPC_NDR_REF_ALLOC;
157 /* by making the pipe a child of the connection variable, it will
158 auto close when it goes out of scope in the script */
159 mprSetPtrChild(conn, "pipe", p);
160 mprSetPtr(conn, "iface", iface);
163 mpr_Return(eid, mprNTSTATUS(status));
169 make an irpc call - called via the same interface as rpc
171 static int ejs_irpc_call(int eid, struct MprVar *conn, struct MprVar *io,
172 const struct dcerpc_interface_table *iface, int callnum,
173 ejs_pull_function_t ejs_pull, ejs_push_function_t ejs_push)
178 const struct dcerpc_interface_call *call;
179 struct ejs_irpc_connection *p;
180 struct irpc_request **reqs;
182 struct MprVar *results;
184 p = mprGetPtr(conn, "irpc");
186 ejs = talloc(mprMemCtx(), struct ejs_rpc);
188 status = NT_STATUS_NO_MEMORY;
192 call = &iface->calls[callnum];
195 ejs->callname = call->name;
197 /* allocate the C structure */
198 ptr = talloc_zero_size(ejs, call->struct_size);
200 status = NT_STATUS_NO_MEMORY;
204 /* convert the mpr object into a C structure */
205 status = ejs_pull(ejs, io, ptr);
206 if (!NT_STATUS_IS_OK(status)) {
210 for (count=0;p->dest_ids[count];count++) /* noop */ ;
212 /* we need to make a call per server */
213 reqs = talloc_array(ejs, struct irpc_request *, count);
215 status = NT_STATUS_NO_MEMORY;
219 /* make the actual calls */
220 for (i=0;i<count;i++) {
221 reqs[i] = irpc_call_send(p->msg_ctx, p->dest_ids[i],
222 iface, callnum, ptr);
223 if (reqs[i] == NULL) {
224 status = NT_STATUS_NO_MEMORY;
227 talloc_steal(reqs, reqs[i]);
230 mprSetVar(io, "results", mprObject("results"));
231 results = mprGetProperty(io, "results", NULL);
233 /* and receive the results, placing them in io.results[i] */
234 for (i=0;i<count;i++) {
235 struct MprVar *output;
237 status = irpc_call_recv(reqs[i]);
238 if (!NT_STATUS_IS_OK(status)) {
241 status = ejs_push(ejs, io, ptr);
242 if (!NT_STATUS_IS_OK(status)) {
245 talloc_free(reqs[i]);
247 /* add to the results array */
248 output = mprGetProperty(io, "output", NULL);
251 mprItoa(i, idx, sizeof(idx));
252 mprSetProperty(results, idx, output);
253 mprDeleteProperty(io, "output");
256 mprSetVar(results, "length", mprCreateIntegerVar(i));
260 mpr_Return(eid, mprNTSTATUS(status));
261 if (NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_ERROR)) {
269 backend code for making an rpc call - this is called from the pidl generated ejs
272 int ejs_rpc_call(int eid, int argc, struct MprVar **argv,
273 const struct dcerpc_interface_table *iface, int callnum,
274 ejs_pull_function_t ejs_pull, ejs_push_function_t ejs_push)
276 struct MprVar *conn, *io;
277 struct dcerpc_pipe *p;
280 struct rpc_request *req;
282 const struct dcerpc_interface_call *call;
285 argv[0]->type != MPR_TYPE_OBJECT ||
286 argv[1]->type != MPR_TYPE_OBJECT) {
287 ejsSetErrorMsg(eid, "rpc_call invalid arguments");
294 if (mprGetPtr(conn, "irpc")) {
295 /* its an irpc call */
296 return ejs_irpc_call(eid, conn, io, iface, callnum, ejs_pull, ejs_push);
299 /* get the pipe info */
300 p = mprGetPtr(conn, "pipe");
302 ejsSetErrorMsg(eid, "rpc_call invalid pipe");
306 ejs = talloc(mprMemCtx(), struct ejs_rpc);
308 status = NT_STATUS_NO_MEMORY;
312 call = &iface->calls[callnum];
315 ejs->callname = call->name;
317 /* allocate the C structure */
318 ptr = talloc_zero_size(ejs, call->struct_size);
320 status = NT_STATUS_NO_MEMORY;
324 /* convert the mpr object into a C structure */
325 status = ejs_pull(ejs, io, ptr);
326 if (!NT_STATUS_IS_OK(status)) {
330 /* if requested, print the structure */
331 if (p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
332 ndr_print_function_debug(call->ndr_print, call->name, NDR_IN, ptr);
335 /* make the actual call */
336 req = dcerpc_ndr_request_send(p, NULL, iface, callnum, ptr, ptr);
338 status = NT_STATUS_NO_MEMORY;
341 status = dcerpc_ndr_request_recv(req);
343 /* print the 'out' structure, if needed */
344 if (p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
345 ndr_print_function_debug(call->ndr_print, call->name, NDR_OUT, ptr);
348 status = ejs_push(ejs, io, ptr);
352 mpr_Return(eid, mprNTSTATUS(status));
353 if (NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_ERROR)) {
360 /* a list of registered ejs rpc modules */
361 static struct ejs_register {
362 struct ejs_register *next, *prev;
365 ejs_constants_t constants;
369 register a generated ejs module
371 NTSTATUS smbcalls_register_ejs(const char *name,
373 ejs_constants_t constants)
375 struct ejs_register *r;
376 void *ctx = ejs_registered;
378 ctx = talloc_autofree_context();
380 r = talloc(ctx, struct ejs_register);
381 NT_STATUS_HAVE_NO_MEMORY(r);
384 r->constants = constants;
385 DLIST_ADD(ejs_registered, r);
390 setup C functions that be called from ejs
392 void smb_setup_ejs_rpc(void)
394 struct ejs_register *r;
396 ejsDefineCFunction(-1, "rpc_connect", ejs_rpc_connect, NULL, MPR_VAR_SCRIPT_HANDLE);
397 ejsDefineCFunction(-1, "irpc_connect", ejs_irpc_connect, NULL, MPR_VAR_SCRIPT_HANDLE);
398 for (r=ejs_registered;r;r=r->next) {
404 setup constants for rpc calls
406 void smb_setup_ejs_rpc_constants(int eid)
408 struct ejs_register *r;
411 for (r=ejs_registered;r;r=r->next) {
415 v = mprCreatePtrVar(NULL);
416 mprSetProperty(ejsGetGlobalObject(eid), "NULL", &v);