12b0d95e8e52c19271ef7e2cf8bdde3cf70cdaef
[jelmer/samba4-debian.git] / source / scripting / ejs / smbcalls_rpc.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    provide interfaces to rpc calls from ejs scripts
5
6    Copyright (C) Andrew Tridgell 2005
7    
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.
12    
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.
17    
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.
21 */
22
23 #include "includes.h"
24 #include "lib/ejs/ejs.h"
25 #include "librpc/gen_ndr/ndr_echo.h"
26 #include "lib/cmdline/popt_common.h"
27 #include "scripting/ejs/ejsrpc.h"
28 #include "dlinklist.h"
29
30 /*
31   connect to an rpc server
32      example: 
33         var conn = new Object();
34         status = rpc_connect(conn, "ncacn_ip_tcp:localhost", "rpcecho");
35 */
36 static int ejs_rpc_connect(MprVarHandle eid, int argc, struct MprVar **argv)
37 {
38         const char *binding, *pipe_name;
39         const struct dcerpc_interface_table *iface;
40         NTSTATUS status;
41         struct dcerpc_pipe *p;
42         struct MprVar *conn;
43         struct cli_credentials *creds = cmdline_credentials;
44         struct event_context *ev;
45
46         /* validate arguments */
47         if (argc != 3 ||
48             argv[0]->type != MPR_TYPE_OBJECT ||
49             argv[1]->type != MPR_TYPE_STRING ||
50             argv[2]->type != MPR_TYPE_STRING) {
51                 ejsSetErrorMsg(eid, "rpc_connect invalid arguments");
52                 return -1;
53         }
54
55         conn       = argv[0];
56         binding    = mprToString(argv[1]);
57         pipe_name  = mprToString(argv[2]);
58
59         iface = idl_iface_by_name(pipe_name);
60         if (iface == NULL) {
61                 status = NT_STATUS_OBJECT_NAME_INVALID;
62                 goto done;
63         }
64
65         if (creds == NULL) {
66                 creds = cli_credentials_init(mprMemCtx());
67                 cli_credentials_guess(creds);
68                 cli_credentials_set_username(creds, "", CRED_GUESSED);
69                 cli_credentials_set_password(creds, "", CRED_GUESSED);
70         }
71
72         ev = talloc_find_parent_bytype(mprMemCtx(), struct event_context);
73
74         status = dcerpc_pipe_connect(mprMemCtx(), &p, binding, 
75                                      iface->uuid, iface->if_version, 
76                                      creds, ev);
77         if (!NT_STATUS_IS_OK(status)) goto done;
78
79         /* callers don't allocate ref vars in the ejs interface */
80         p->conn->flags |= DCERPC_NDR_REF_ALLOC;
81
82         mprSetPtr(conn, "pipe", p);
83         mprSetPtr(conn, "iface", iface);
84
85 done:
86         ejsSetReturnValue(eid, mprNTSTATUS(status));
87         return 0;
88 }
89
90
91 /*
92   make an rpc call
93      example:
94             status = rpc_call(conn, "echo_AddOne", io);
95 */
96  int ejs_rpc_call(int eid, int argc, struct MprVar **argv,
97                   const char *callname,
98                   ejs_pull_function_t ejs_pull, ejs_push_function_t ejs_push)
99 {
100         struct MprVar *conn, *io;
101         const struct dcerpc_interface_table *iface;
102         struct dcerpc_pipe *p;
103         const struct dcerpc_interface_call *call;
104         NTSTATUS status;
105         void *ptr;
106         struct rpc_request *req;
107         int callnum;
108
109         if (argc != 2 ||
110             argv[0]->type != MPR_TYPE_OBJECT ||
111             argv[1]->type != MPR_TYPE_OBJECT) {
112                 ejsSetErrorMsg(eid, "rpc_call invalid arguments");
113                 return -1;
114         }
115             
116         conn     = argv[0];
117         io       = argv[1];
118
119         /* get the pipe info */
120         p = mprGetPtr(conn, "pipe");
121         iface = mprGetPtr(conn, "iface");
122         if (p == NULL || iface == NULL) {
123                 ejsSetErrorMsg(eid, "rpc_call invalid pipe");
124                 return -1;
125         }
126
127         /* find the call by name */
128         call = dcerpc_iface_find_call(iface, callname);
129         if (call == NULL) {
130                 status = NT_STATUS_OBJECT_NAME_INVALID;
131                 goto done;
132         }
133         callnum = call - iface->calls;
134
135         /* allocate the C structure */
136         ptr = talloc_zero_size(mprMemCtx(), call->struct_size);
137         if (ptr == NULL) {
138                 status = NT_STATUS_NO_MEMORY;
139                 goto done;
140         }
141
142         /* convert the mpr object into a C structure */
143         status = ejs_pull_rpc(eid, callname, io, ptr, ejs_pull);
144         if (!NT_STATUS_IS_OK(status)) {
145                 goto done;
146         }
147
148         /* if requested, print the structure */
149         if (p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
150                 ndr_print_function_debug(call->ndr_print, call->name, NDR_IN, ptr);
151         }
152
153         /* make the actual call */
154         req = dcerpc_ndr_request_send(p, NULL, iface, callnum, ptr, ptr);
155         if (req == NULL) {
156                 status = NT_STATUS_NO_MEMORY;
157                 talloc_free(ptr);
158                 goto done;
159         }
160         status = dcerpc_ndr_request_recv(req);
161
162         /* print the 'out' structure, if needed */
163         if (p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
164                 ndr_print_function_debug(call->ndr_print, call->name, NDR_OUT, ptr);
165         }
166
167         status = ejs_push_rpc(eid, callname, io, ptr, ejs_push);
168
169         talloc_free(ptr);
170 done:
171         ejsSetReturnValue(eid, mprNTSTATUS(status));
172         if (NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_ERROR)) {
173                 return -1;
174         }
175         return 0;
176 }
177
178
179 /* a list of registered ejs rpc modules */
180 static struct ejs_register {
181         struct ejs_register *next, *prev;
182         const char *name;
183         ejs_setup_t setup;
184         ejs_constants_t constants;
185 } *ejs_registered;
186
187 /*
188   register a generated ejs module
189 */
190  NTSTATUS smbcalls_register_ejs(const char *name, 
191                                 ejs_setup_t setup,
192                                 ejs_constants_t constants)
193 {
194         struct ejs_register *r;
195         void *ctx = ejs_registered;
196         if (ctx == NULL) {
197                 ctx = talloc_autofree_context();
198         }
199         r = talloc(ctx, struct ejs_register);
200         NT_STATUS_HAVE_NO_MEMORY(r);
201         r->name = name;
202         r->setup = setup;
203         r->constants = constants;
204         DLIST_ADD(ejs_registered, r);
205         return NT_STATUS_OK;
206 }
207
208 /*
209   setup C functions that be called from ejs
210 */
211 void smb_setup_ejs_rpc(void)
212 {
213         struct ejs_register *r;
214
215         ejsDefineCFunction(-1, "rpc_connect", ejs_rpc_connect, NULL, MPR_VAR_SCRIPT_HANDLE);
216         for (r=ejs_registered;r;r=r->next) {
217                 r->setup();
218         }
219 }
220
221 /*
222   setup constants for rpc calls
223 */
224 void smb_setup_ejs_rpc_constants(int eid)
225 {
226         struct ejs_register *r;
227         struct MprVar v;
228
229         for (r=ejs_registered;r;r=r->next) {
230                 r->constants(eid);
231         }
232
233         v = mprCreatePtrVar(NULL, "NULL");
234         mprSetProperty(ejsGetGlobalObject(eid), "NULL", &v);
235 }
236
237