r14735: Use dcerpc_syntax_id rather then seperate GUID + if_version everywhere
[samba.git] / source4 / rpc_server / remote / dcesrv_remote.c
1 /* 
2    Unix SMB/CIFS implementation.
3    remote dcerpc operations
4
5    Copyright (C) Stefan (metze) Metzmacher 2004
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "rpc_server/dcerpc_server.h"
24 #include "auth/auth.h"
25 #include "librpc/rpc/dcerpc_table.h"
26
27
28 struct dcesrv_remote_private {
29         struct dcerpc_pipe *c_pipe;
30 };
31
32 static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
33 {
34         NTSTATUS status;
35                 const struct dcerpc_interface_table *table;
36         struct dcesrv_remote_private *private;
37         const char *binding = lp_parm_string(-1, "dcerpc_remote", "binding");
38         const char *user, *pass, *domain;
39         struct cli_credentials *credentials;
40         BOOL machine_account;
41
42         machine_account = lp_parm_bool(-1, "dcerpc_remote", "use_machine_account", False);
43
44         private = talloc(dce_call->conn, struct dcesrv_remote_private);
45         if (!private) {
46                 return NT_STATUS_NO_MEMORY;     
47         }
48         
49         private->c_pipe = NULL;
50         dce_call->context->private = private;
51
52         if (!binding) {
53                 DEBUG(0,("You must specify a DCE/RPC binding string\n"));
54                 return NT_STATUS_INVALID_PARAMETER;
55         }
56
57         user = lp_parm_string(-1, "dcerpc_remote", "user");
58         pass = lp_parm_string(-1, "dcerpc_remote", "password");
59         domain = lp_parm_string(-1, "dceprc_remote", "domain");
60
61         table = idl_iface_by_uuid(&iface->syntax_id.uuid); /* FIXME: What about if_version ? */
62         if (!table) {
63                 dce_call->fault_code = DCERPC_FAULT_UNK_IF;
64                 return NT_STATUS_NET_WRITE_FAULT;
65         }
66
67         if (user && pass) {
68                 DEBUG(5, ("dcerpc_remote: RPC Proxy: Using specified account\n"));
69                 credentials = cli_credentials_init(private);
70                 if (!credentials) {
71                         return NT_STATUS_NO_MEMORY;
72                 }
73                 cli_credentials_set_conf(credentials);
74                 cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
75                 if (domain) {
76                         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
77                 }
78                 cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
79         } else if (machine_account) {
80                 DEBUG(5, ("dcerpc_remote: RPC Proxy: Using machine account\n"));
81                 credentials = cli_credentials_init(private);
82                 cli_credentials_set_conf(credentials);
83                 if (domain) {
84                         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
85                 }
86                 status = cli_credentials_set_machine_account(credentials);
87                 if (!NT_STATUS_IS_OK(status)) {
88                         return status;
89                 }
90         } else if (dce_call->conn->auth_state.session_info->credentials) {
91                 DEBUG(5, ("dcerpc_remote: RPC Proxy: Using delegated credentials\n"));
92                 credentials = dce_call->conn->auth_state.session_info->credentials;
93         } else {
94                 DEBUG(1,("dcerpc_remote: RPC Proxy: You must supply binding, user and password or have delegated credentials\n"));
95                 return NT_STATUS_INVALID_PARAMETER;
96         }
97
98         status = dcerpc_pipe_connect(private, 
99                                      &(private->c_pipe), binding, table,
100                                      credentials, dce_call->event_ctx);
101
102         talloc_free(credentials);
103         if (!NT_STATUS_IS_OK(status)) {
104                 return status;
105         }
106
107         return NT_STATUS_OK;    
108 }
109
110 static void remote_op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)
111 {
112         struct dcesrv_remote_private *private = context->private;
113
114         talloc_free(private->c_pipe);
115
116         return; 
117 }
118
119 static NTSTATUS remote_op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
120 {
121         NTSTATUS status;
122         const struct dcerpc_interface_table *table = dce_call->context->iface->private;
123         uint16_t opnum = dce_call->pkt.u.request.opnum;
124
125         dce_call->fault_code = 0;
126
127         if (opnum >= table->num_calls) {
128                 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
129                 return NT_STATUS_NET_WRITE_FAULT;
130         }
131
132         *r = talloc_size(mem_ctx, table->calls[opnum].struct_size);
133         if (!*r) {
134                 return NT_STATUS_NO_MEMORY;
135         }
136
137         /* unravel the NDR for the packet */
138         status = table->calls[opnum].ndr_pull(pull, NDR_IN, *r);
139         if (!NT_STATUS_IS_OK(status)) {
140                 dcerpc_log_packet(table, opnum, NDR_IN,
141                                   &dce_call->pkt.u.request.stub_and_verifier);
142                 dce_call->fault_code = DCERPC_FAULT_NDR;
143                 return NT_STATUS_NET_WRITE_FAULT;
144         }
145
146         return NT_STATUS_OK;
147 }
148
149 static NTSTATUS remote_op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
150 {
151         struct dcesrv_remote_private *private = dce_call->context->private;
152         uint16_t opnum = dce_call->pkt.u.request.opnum;
153         const struct dcerpc_interface_table *table = dce_call->context->iface->private;
154         const struct dcerpc_interface_call *call;
155         const char *name;
156
157         name = table->calls[opnum].name;
158         call = &table->calls[opnum];
159
160         if (private->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_IN) {
161                 ndr_print_function_debug(call->ndr_print, name, NDR_IN | NDR_SET_VALUES, r);            
162         }
163
164         /* we didn't use the return code of this function as we only check the last_fault_code */
165         dcerpc_ndr_request(private->c_pipe, NULL, table, opnum, mem_ctx,r);
166
167         dce_call->fault_code = private->c_pipe->last_fault_code;
168         if (dce_call->fault_code != 0) {
169                 DEBUG(0,("dcesrv_remote: call[%s] failed with: %s!\n",name, dcerpc_errstr(mem_ctx, dce_call->fault_code)));
170                 return NT_STATUS_NET_WRITE_FAULT;
171         }
172
173         if ((dce_call->fault_code == 0) && 
174             (private->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_OUT)) {
175                 ndr_print_function_debug(call->ndr_print, name, NDR_OUT, r);            
176         }
177
178         return NT_STATUS_OK;
179 }
180
181 static NTSTATUS remote_op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
182 {
183         NTSTATUS status;
184         const struct dcerpc_interface_table *table = dce_call->context->iface->private;
185         uint16_t opnum = dce_call->pkt.u.request.opnum;
186
187         /* unravel the NDR for the packet */
188         status = table->calls[opnum].ndr_push(push, NDR_OUT, r);
189         if (!NT_STATUS_IS_OK(status)) {
190                 dce_call->fault_code = DCERPC_FAULT_NDR;
191                 return NT_STATUS_NET_WRITE_FAULT;
192         }
193
194         return NT_STATUS_OK;
195 }
196
197 static NTSTATUS remote_register_one_iface(struct dcesrv_context *dce_ctx, const struct dcesrv_interface *iface)
198 {
199         int i;
200         const struct dcerpc_interface_table *table = iface->private;
201
202         for (i=0;i<table->endpoints->count;i++) {
203                 NTSTATUS ret;
204                 const char *name = table->endpoints->names[i];
205
206                 ret = dcesrv_interface_register(dce_ctx, name, iface, NULL);
207                 if (!NT_STATUS_IS_OK(ret)) {
208                         DEBUG(1,("remote_op_init_server: failed to register endpoint '%s'\n",name));
209                         return ret;
210                 }
211         }
212
213         return NT_STATUS_OK;
214 }
215
216 static NTSTATUS remote_op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
217 {
218         int i;
219         const char **ifaces = str_list_make(dce_ctx, lp_parm_string(-1,"dcerpc_remote","interfaces"),NULL);
220
221         if (!ifaces) {
222                 DEBUG(3,("remote_op_init_server: no interfaces configured\n"));
223                 return NT_STATUS_OK;
224         }
225
226         for (i=0;ifaces[i];i++) {
227                 NTSTATUS ret;
228                 struct dcesrv_interface iface;
229                 
230                 if (!ep_server->interface_by_name(&iface, ifaces[i])) {
231                         DEBUG(0,("remote_op_init_server: failed to find interface = '%s'\n", ifaces[i]));
232                         talloc_free(ifaces);
233                         return NT_STATUS_UNSUCCESSFUL;
234                 }
235
236                 ret = remote_register_one_iface(dce_ctx, &iface);
237                 if (!NT_STATUS_IS_OK(ret)) {
238                         DEBUG(0,("remote_op_init_server: failed to register interface = '%s'\n", ifaces[i]));
239                         talloc_free(ifaces);
240                         return ret;
241                 }
242         }
243
244         talloc_free(ifaces);
245         return NT_STATUS_OK;
246 }
247
248 static BOOL remote_fill_interface(struct dcesrv_interface *iface, const struct dcerpc_interface_table *if_tabl)
249 {
250         iface->name = if_tabl->name;
251         iface->syntax_id = if_tabl->syntax_id;
252         
253         iface->bind = remote_op_bind;
254         iface->unbind = remote_op_unbind;
255
256         iface->ndr_pull = remote_op_ndr_pull;
257         iface->dispatch = remote_op_dispatch;
258         iface->ndr_push = remote_op_ndr_push;
259
260         iface->private = if_tabl;
261
262         return True;
263 }
264
265 static BOOL remote_op_interface_by_uuid(struct dcesrv_interface *iface, const struct GUID *uuid, uint32_t if_version)
266 {
267         const struct dcerpc_interface_list *l;
268
269         for (l=librpc_dcerpc_pipes();l;l=l->next) {
270                 if (l->table->syntax_id.if_version == if_version &&
271                         GUID_equal(&l->table->syntax_id.uuid, uuid)==0) {
272                         return remote_fill_interface(iface, l->table);
273                 }
274         }
275
276         return False;   
277 }
278
279 static BOOL remote_op_interface_by_name(struct dcesrv_interface *iface, const char *name)
280 {
281         const struct dcerpc_interface_table *tbl = idl_iface_by_name(name);
282
283         if (tbl)
284                 return remote_fill_interface(iface, tbl);
285
286         return False;   
287 }
288
289 NTSTATUS dcerpc_server_remote_init(void)
290 {
291         NTSTATUS ret;
292         struct dcesrv_endpoint_server ep_server;
293
294         ZERO_STRUCT(ep_server);
295
296         /* fill in our name */
297         ep_server.name = "remote";
298
299         /* fill in all the operations */
300         ep_server.init_server = remote_op_init_server;
301
302         ep_server.interface_by_uuid = remote_op_interface_by_uuid;
303         ep_server.interface_by_name = remote_op_interface_by_name;
304
305         /* register ourselves with the DCERPC subsystem. */
306         ret = dcerpc_register_ep_server(&ep_server);
307         if (!NT_STATUS_IS_OK(ret)) {
308                 DEBUG(0,("Failed to register 'remote' endpoint server!\n"));
309                 return ret;
310         }
311
312         /* We need the full DCE/RPC interface table */
313         dcerpc_table_init();
314
315         return ret;
316 }