This patch adds a better dcerpc server infastructure.
[abartlet/samba.git/.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
24 struct dcesrv_remote_private {
25         struct dcerpc_pipe *c_pipe;
26         void *private;  
27 };
28
29 static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
30 {
31         NTSTATUS status;
32         struct dcesrv_remote_private *private;
33         const char *binding = lp_parm_string(-1, "dcerpc_remote", "binding");
34         const char *print_debug = lp_parm_string(-1, "dcerpc_remote", "print_debug");
35
36         if (!binding) {
37                 printf("You must specify a ncacn binding string\n");
38                 return NT_STATUS_INVALID_PARAMETER;
39         }
40
41         private = talloc_p(dce_call->conn->mem_ctx, struct dcesrv_remote_private);
42         if (!private) {
43                 return NT_STATUS_NO_MEMORY;     
44         }
45
46         status = dcerpc_pipe_connect(&(private->c_pipe), binding, iface->ndr->uuid, iface->ndr->if_version,
47                                      lp_workgroup(), 
48                                      lp_parm_string(-1, "dcerpc_remote", "username"),
49                                      lp_parm_string(-1, "dcerpc_remote", "password"));
50
51         if (print_debug && strcasecmp("yes",print_debug) == 0) {
52                 private->c_pipe->flags |= DCERPC_DEBUG_PRINT_BOTH;
53         }
54
55         dce_call->conn->private = private;
56
57         return NT_STATUS_OK;    
58 }
59
60 static void remote_op_unbind(struct dcesrv_connection *dce_conn, const struct dcesrv_interface *iface)
61 {
62         struct dcesrv_remote_private *private = dce_conn->private;
63
64         dcerpc_pipe_close(private->c_pipe);
65
66         return; 
67 }
68
69 static NTSTATUS remote_op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
70 {
71         struct dcesrv_remote_private *private = dce_call->conn->private;
72         NTSTATUS status;
73         uint16 opnum = dce_call->pkt.u.request.opnum;
74         ndr_push_flags_fn_t ndr_push_fn = dce_call->conn->iface->ndr->calls[opnum].ndr_push;
75         ndr_pull_flags_fn_t ndr_pull_fn = dce_call->conn->iface->ndr->calls[opnum].ndr_pull;
76         size_t struct_size = dce_call->conn->iface->ndr->calls[opnum].struct_size;
77
78         status = dcerpc_ndr_request(private->c_pipe, opnum, mem_ctx,
79                                     (ndr_push_flags_fn_t) ndr_push_fn,
80                                     (ndr_pull_flags_fn_t) ndr_pull_fn,
81                                     r, struct_size);
82
83         return status;
84 }
85
86 static NTSTATUS remote_register_one_iface(struct dcesrv_context *dce_ctx, const struct dcesrv_interface *iface)
87 {
88         int i;
89
90         for (i=0;i<iface->ndr->endpoints->count;i++) {
91                 NTSTATUS ret;
92                 const char *name = iface->ndr->endpoints->names[i];
93
94                 ret = dcesrv_interface_register(dce_ctx, name, iface, NULL);
95                 if (!NT_STATUS_IS_OK(ret)) {
96                         DEBUG(1,("remote_op_init_server: failed to register endpoint '%s'\n",name));
97                         return ret;
98                 }
99         }
100
101         return NT_STATUS_OK;
102 }
103
104 static NTSTATUS remote_op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
105 {
106         int i;
107         char **ifaces = str_list_make(lp_parm_string(-1,"dcerpc_remote","interfaces"),NULL);
108
109         if (!ifaces) {
110                 DEBUG(3,("remote_op_init_server: no interfaces configured\n"));
111                 return NT_STATUS_OK;
112         }
113
114         for (i=0;ifaces[i];i++) {
115                 NTSTATUS ret;
116                 struct dcesrv_interface iface;
117                 
118                 if (!ep_server->interface_by_name(&iface, ifaces[i])) {
119                         DEBUG(0,("remote_op_init_server: failed to find interface = '%s'\n", ifaces[i]));
120                         str_list_free(&ifaces);
121                         return NT_STATUS_UNSUCCESSFUL;
122                 }
123
124                 ret = remote_register_one_iface(dce_ctx, &iface);
125                 if (!NT_STATUS_IS_OK(ret)) {
126                         DEBUG(0,("remote_op_init_server: failed to register interface = '%s'\n", ifaces[i]));
127                         str_list_free(&ifaces);
128                         return ret;
129                 }
130         }
131
132         str_list_free(&ifaces);
133         return NT_STATUS_OK;
134 }
135
136 static BOOL remote_fill_interface(struct dcesrv_interface *iface, const struct dcerpc_interface_table *if_tabl)
137 {
138         iface->ndr = if_tabl;
139
140         iface->bind = remote_op_bind;
141         iface->unbind = remote_op_unbind;
142         iface->dispatch = remote_op_dispatch;
143
144         return True;
145 }
146
147 static BOOL remote_op_interface_by_uuid(struct dcesrv_interface *iface, const char *uuid, uint32 if_version)
148 {
149         int i;
150
151         for (i=0;dcerpc_pipes[i];i++) {
152                 if (dcerpc_pipes[i]->if_version == if_version &&
153                         strcmp(dcerpc_pipes[i]->uuid, uuid)==0) {
154                         return remote_fill_interface(iface, dcerpc_pipes[i]);
155                 }
156         }
157
158         return False;   
159 }
160
161 static BOOL remote_op_interface_by_name(struct dcesrv_interface *iface, const char *name)
162 {
163         int i;
164
165         for (i=0;dcerpc_pipes[i];i++) {
166                 if (strcmp(dcerpc_pipes[i]->name, name)==0) {
167                         return remote_fill_interface(iface, dcerpc_pipes[i]);
168                 }
169         }
170
171         return False;   
172 }
173
174 NTSTATUS dcerpc_remote_init(void)
175 {
176         NTSTATUS ret;
177         struct dcesrv_endpoint_server ep_server;
178
179         ZERO_STRUCT(ep_server);
180
181         /* fill in our name */
182         ep_server.name = "remote";
183
184         /* fill in all the operations */
185         ep_server.init_server = remote_op_init_server;
186
187         ep_server.interface_by_uuid = remote_op_interface_by_uuid;
188         ep_server.interface_by_name = remote_op_interface_by_name;
189
190         /* register ourselves with the NTVFS subsystem. */
191         ret = register_backend("dcerpc", &ep_server);
192         if (!NT_STATUS_IS_OK(ret)) {
193                 DEBUG(0,("Failed to register 'remote' endpoint server!\n"));
194                 return ret;
195         }
196
197         return ret;
198 }