r12512: Use GUID structs in API functions everywhere rather then converting back and
[gd/samba-autobuild/.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
26
27 struct dcesrv_remote_private {
28         struct dcerpc_pipe *c_pipe;
29 };
30
31 static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
32 {
33         NTSTATUS status;
34                 const struct dcerpc_interface_table *table;
35         struct dcesrv_remote_private *private;
36         const char *binding = lp_parm_string(-1, "dcerpc_remote", "binding");
37         const char *user, *pass, *domain;
38         struct cli_credentials *credentials;
39         BOOL machine_account;
40
41         machine_account = lp_parm_bool(-1, "dcerpc_remote", "use_machine_account", False);
42
43         private = talloc(dce_call->conn, struct dcesrv_remote_private);
44         if (!private) {
45                 return NT_STATUS_NO_MEMORY;     
46         }
47         
48         private->c_pipe = NULL;
49         dce_call->context->private = private;
50
51         if (!binding) {
52                 DEBUG(0,("You must specify a DCE/RPC binding string\n"));
53                 return NT_STATUS_INVALID_PARAMETER;
54         }
55
56         user = lp_parm_string(-1, "dcerpc_remote", "user");
57         pass = lp_parm_string(-1, "dcerpc_remote", "password");
58         domain = lp_parm_string(-1, "dceprc_remote", "domain");
59
60         table = idl_iface_by_uuid(&iface->uuid); /* FIXME: What about if_version ? */
61         if (!table) {
62                 dce_call->fault_code = DCERPC_FAULT_UNK_IF;
63                 return NT_STATUS_NET_WRITE_FAULT;
64         }
65
66         if (user && pass) {
67                 DEBUG(5, ("dcerpc_remote: RPC Proxy: Using specified account\n"));
68                 credentials = cli_credentials_init(private);
69                 if (!credentials) {
70                         return NT_STATUS_NO_MEMORY;
71                 }
72                 cli_credentials_set_conf(credentials);
73                 cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
74                 if (domain) {
75                         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
76                 }
77                 cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
78         } else if (machine_account) {
79                 DEBUG(5, ("dcerpc_remote: RPC Proxy: Using machine account\n"));
80                 credentials = cli_credentials_init(private);
81                 cli_credentials_set_conf(credentials);
82                 if (domain) {
83                         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
84                 }
85                 status = cli_credentials_set_machine_account(credentials);
86                 if (!NT_STATUS_IS_OK(status)) {
87                         return status;
88                 }
89         } else if (dce_call->conn->auth_state.session_info->credentials) {
90                 DEBUG(5, ("dcerpc_remote: RPC Proxy: Using delegated credentials\n"));
91                 credentials = dce_call->conn->auth_state.session_info->credentials;
92         } else {
93                 DEBUG(1,("dcerpc_remote: RPC Proxy: You must supply binding, user and password or have delegated credentials\n"));
94                 return NT_STATUS_INVALID_PARAMETER;
95         }
96
97         status = dcerpc_pipe_connect(private, 
98                                      &(private->c_pipe), binding, table,
99                                      credentials, dce_call->event_ctx);
100
101         talloc_free(credentials);
102         if (!NT_STATUS_IS_OK(status)) {
103                 return status;
104         }
105
106         return NT_STATUS_OK;    
107 }
108
109 static void remote_op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)
110 {
111         struct dcesrv_remote_private *private = context->private;
112
113         talloc_free(private->c_pipe);
114
115         return; 
116 }
117
118 static NTSTATUS remote_op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
119 {
120         NTSTATUS status;
121         const struct dcerpc_interface_table *table = dce_call->context->iface->private;
122         uint16_t opnum = dce_call->pkt.u.request.opnum;
123
124         dce_call->fault_code = 0;
125
126         if (opnum >= table->num_calls) {
127                 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
128                 return NT_STATUS_NET_WRITE_FAULT;
129         }
130
131         *r = talloc_size(mem_ctx, table->calls[opnum].struct_size);
132         if (!*r) {
133                 return NT_STATUS_NO_MEMORY;
134         }
135
136         /* unravel the NDR for the packet */
137         status = table->calls[opnum].ndr_pull(pull, NDR_IN, *r);
138         if (!NT_STATUS_IS_OK(status)) {
139                 dcerpc_log_packet(table, opnum, NDR_IN,
140                                   &dce_call->pkt.u.request.stub_and_verifier);
141                 dce_call->fault_code = DCERPC_FAULT_NDR;
142                 return NT_STATUS_NET_WRITE_FAULT;
143         }
144
145         return NT_STATUS_OK;
146 }
147
148 static NTSTATUS remote_op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
149 {
150         struct dcesrv_remote_private *private = dce_call->context->private;
151         uint16_t opnum = dce_call->pkt.u.request.opnum;
152         const struct dcerpc_interface_table *table = dce_call->context->iface->private;
153         const struct dcerpc_interface_call *call;
154         const char *name;
155
156         name = table->calls[opnum].name;
157         call = &table->calls[opnum];
158
159         if (private->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_IN) {
160                 ndr_print_function_debug(call->ndr_print, name, NDR_IN | NDR_SET_VALUES, r);            
161         }
162
163         /* we didn't use the return code of this function as we only check the last_fault_code */
164         dcerpc_ndr_request(private->c_pipe, NULL, table, opnum, mem_ctx,r);
165
166         dce_call->fault_code = private->c_pipe->last_fault_code;
167         if (dce_call->fault_code != 0) {
168                 DEBUG(0,("dcesrv_remote: call[%s] failed with: %s!\n",name, dcerpc_errstr(mem_ctx, dce_call->fault_code)));
169                 return NT_STATUS_NET_WRITE_FAULT;
170         }
171
172         if ((dce_call->fault_code == 0) && 
173             (private->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_OUT)) {
174                 ndr_print_function_debug(call->ndr_print, name, NDR_OUT, r);            
175         }
176
177         return NT_STATUS_OK;
178 }
179
180 static NTSTATUS remote_op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
181 {
182         NTSTATUS status;
183         const struct dcerpc_interface_table *table = dce_call->context->iface->private;
184         uint16_t opnum = dce_call->pkt.u.request.opnum;
185
186         /* unravel the NDR for the packet */
187         status = table->calls[opnum].ndr_push(push, NDR_OUT, r);
188         if (!NT_STATUS_IS_OK(status)) {
189                 dce_call->fault_code = DCERPC_FAULT_NDR;
190                 return NT_STATUS_NET_WRITE_FAULT;
191         }
192
193         return NT_STATUS_OK;
194 }
195
196 static NTSTATUS remote_register_one_iface(struct dcesrv_context *dce_ctx, const struct dcesrv_interface *iface)
197 {
198         int i;
199         const struct dcerpc_interface_table *table = iface->private;
200
201         for (i=0;i<table->endpoints->count;i++) {
202                 NTSTATUS ret;
203                 const char *name = table->endpoints->names[i];
204
205                 ret = dcesrv_interface_register(dce_ctx, name, iface, NULL);
206                 if (!NT_STATUS_IS_OK(ret)) {
207                         DEBUG(1,("remote_op_init_server: failed to register endpoint '%s'\n",name));
208                         return ret;
209                 }
210         }
211
212         return NT_STATUS_OK;
213 }
214
215 static NTSTATUS remote_op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
216 {
217         int i;
218         const char **ifaces = str_list_make(dce_ctx, lp_parm_string(-1,"dcerpc_remote","interfaces"),NULL);
219
220         if (!ifaces) {
221                 DEBUG(3,("remote_op_init_server: no interfaces configured\n"));
222                 return NT_STATUS_OK;
223         }
224
225         for (i=0;ifaces[i];i++) {
226                 NTSTATUS ret;
227                 struct dcesrv_interface iface;
228                 
229                 if (!ep_server->interface_by_name(&iface, ifaces[i])) {
230                         DEBUG(0,("remote_op_init_server: failed to find interface = '%s'\n", ifaces[i]));
231                         talloc_free(ifaces);
232                         return NT_STATUS_UNSUCCESSFUL;
233                 }
234
235                 ret = remote_register_one_iface(dce_ctx, &iface);
236                 if (!NT_STATUS_IS_OK(ret)) {
237                         DEBUG(0,("remote_op_init_server: failed to register interface = '%s'\n", ifaces[i]));
238                         talloc_free(ifaces);
239                         return ret;
240                 }
241         }
242
243         talloc_free(ifaces);
244         return NT_STATUS_OK;
245 }
246
247 static BOOL remote_fill_interface(struct dcesrv_interface *iface, const struct dcerpc_interface_table *if_tabl)
248 {
249         iface->name = if_tabl->name;
250         iface->uuid = if_tabl->uuid;
251         iface->if_version = if_tabl->if_version;
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->if_version == if_version &&
271                         GUID_equal(&l->table->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         return ret;
313 }