r3481: split out client.h and events.h
[sfrench/samba-autobuild/.git] / source4 / rpc_server / dcerpc_sock.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    server side dcerpc using various kinds of sockets (tcp, unix domain)
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Stefan (metze) Metzmacher 2004   
8    Copyright (C) Jelmer Vernooij 2004
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "events.h"
27 #include "rpc_server/dcerpc_server.h"
28
29 struct dcesrv_socket_context {
30         const struct dcesrv_endpoint *endpoint;
31         struct dcesrv_context *dcesrv_ctx;      
32 };
33
34 /*
35   write_fn callback for dcesrv_output()
36 */
37 static ssize_t dcerpc_write_fn(void *private, DATA_BLOB *out)
38 {
39         NTSTATUS status;
40         struct socket_context *sock = private;
41         size_t sendlen;
42
43         status = socket_send(sock, out, &sendlen, 0);
44         if (NT_STATUS_IS_ERR(status)) {
45                 return -1;
46         }
47
48         return sendlen;
49 }
50
51 void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
52 {
53         server_terminate_connection(dce_conn->srv_conn, reason);
54 }
55
56 static void add_socket_rpc_unix(struct server_service *service,
57                                 const struct model_ops *model_ops,
58                                 struct dcesrv_context *dce_ctx,
59                                 struct dcesrv_endpoint *e)
60 {
61         struct server_socket *sock;
62         struct dcesrv_socket_context *dcesrv_sock;
63         uint16_t port = 1;
64
65         sock = service_setup_socket(service,model_ops, "unix", e->ep_description.endpoint, &port);
66         if (!sock) {
67                 DEBUG(0,("service_setup_socket(path=%s) failed\n",e->ep_description.endpoint));
68                 return;
69         }
70
71         dcesrv_sock = talloc_p(sock, struct dcesrv_socket_context);
72         if (!dcesrv_sock) {
73                 DEBUG(0,("talloc_p(sock->mem_ctx, struct dcesrv_socket_context) failed\n"));
74                 return;
75         }
76
77         /* remember the endpoint of this socket */
78         dcesrv_sock->endpoint           = e;
79         dcesrv_sock->dcesrv_ctx         = dce_ctx;
80
81         sock->private_data = dcesrv_sock;
82 }
83
84 static void add_socket_rpc_ncalrpc(struct server_service *service,
85                                                         const struct model_ops *model_ops,
86                                                         struct dcesrv_context *dce_ctx, 
87                                                         struct dcesrv_endpoint *e)
88 {
89         struct server_socket *sock;
90         struct dcesrv_socket_context *dcesrv_sock;
91         uint16_t port = 1;
92         char *full_path;
93
94         if (!e->ep_description.endpoint) {
95                 /* No identifier specified: use DEFAULT. 
96                  * DO NOT hardcode this value anywhere else. Rather, specify 
97                  * no endpoint and let the epmapper worry about it. */
98                 e->ep_description.endpoint = talloc_strdup(dce_ctx, "DEFAULT");
99         }
100
101         full_path = talloc_asprintf(dce_ctx, "%s/%s", lp_ncalrpc_dir(), e->ep_description.endpoint);
102
103         sock = service_setup_socket(service,model_ops, "unix", full_path, &port);
104         if (!sock) {
105                 DEBUG(0,("service_setup_socket(identifier=%s,path=%s) failed\n",e->ep_description.endpoint, full_path));
106                 return;
107         }
108
109         dcesrv_sock = talloc_p(sock, struct dcesrv_socket_context);
110         if (!dcesrv_sock) {
111                 DEBUG(0,("talloc_p(sock->mem_ctx, struct dcesrv_socket_context) failed\n"));
112                 return;
113         }
114
115         /* remember the endpoint of this socket */
116         dcesrv_sock->endpoint           = e;
117         dcesrv_sock->dcesrv_ctx         = dce_ctx;
118
119         sock->private_data = dcesrv_sock;
120
121         return;
122 }
123
124 /*
125   add a socket address to the list of events, one event per dcerpc endpoint
126 */
127 static void add_socket_rpc_tcp_iface(struct server_service *service, 
128                                      const struct model_ops *model_ops,
129                                      struct dcesrv_context *dce_ctx, 
130                                      struct dcesrv_endpoint *e,
131                                      struct ipv4_addr *ifip)
132 {
133         struct server_socket *sock;
134         struct dcesrv_socket_context *dcesrv_sock;
135         uint16_t port = 0;
136         char *ip_str = talloc_strdup(service, sys_inet_ntoa(*ifip));
137                         
138         if (e->ep_description.endpoint) 
139                 port = atoi(e->ep_description.endpoint);
140
141         sock = service_setup_socket(service,model_ops, "ipv4", ip_str, &port);
142         if (!sock) {
143                 DEBUG(0,("service_setup_socket(port=%u) failed\n",port));
144                 return;
145         }
146
147         if (e->ep_description.endpoint == NULL) {
148                 e->ep_description.endpoint = talloc_asprintf(dce_ctx, "%d", port);
149         }
150
151         dcesrv_sock = talloc_p(sock, struct dcesrv_socket_context);
152         if (!dcesrv_sock) {
153                 DEBUG(0,("talloc_p(sock->mem_ctx, struct dcesrv_socket_context) failed\n"));
154                 return;
155         }
156
157         /* remember the endpoint of this socket */
158         dcesrv_sock->endpoint           = e;
159         dcesrv_sock->dcesrv_ctx         = dce_ctx;
160
161         sock->private_data = dcesrv_sock;
162
163         talloc_free(ip_str);
164
165         return;
166 }
167
168 static void add_socket_rpc_tcp(struct server_service *service,
169                                                         const struct model_ops *model_ops,
170                                                         struct dcesrv_context *dce_ctx, 
171                                                         struct dcesrv_endpoint *e)
172 {
173         /* Add TCP/IP sockets */
174         if (lp_interfaces() && lp_bind_interfaces_only()) {
175                 int num_interfaces = iface_count();
176                 int i;
177                 for(i = 0; i < num_interfaces; i++) {
178                         struct ipv4_addr *ifip = iface_n_ip(i);
179                         if (ifip == NULL) {
180                                 continue;
181                         }
182                         add_socket_rpc_tcp_iface(service, model_ops, dce_ctx, e, ifip);
183                 }
184         } else {
185                 struct ipv4_addr ifip;
186                 ifip = interpret_addr2(lp_socket_address());
187                 add_socket_rpc_tcp_iface(service, model_ops, dce_ctx, e, &ifip);
188         }
189
190         return;
191 }
192
193 /****************************************************************************
194  Open the listening sockets for RPC over NCACN_IP_TCP/NCALRPC/NCACN_UNIX_STREAM
195 ****************************************************************************/
196 void dcesrv_sock_init(struct server_service *service, const struct model_ops *model_ops, struct dcesrv_context *dce_ctx)
197 {
198         struct dcesrv_endpoint *e;
199
200         DEBUG(1,("dcesrv_sock_init\n"));
201
202         /* Make sure the directory for NCALRPC exists */
203         if (!directory_exist(lp_ncalrpc_dir(), NULL)) {
204                 mkdir(lp_ncalrpc_dir(), S_IWUSR | S_IRUSR | S_IXUSR);
205         }
206
207         for (e=dce_ctx->endpoint_list;e;e=e->next) {
208                 switch (e->ep_description.transport) {
209                 case NCACN_UNIX_STREAM:
210                         add_socket_rpc_unix(service, model_ops, dce_ctx, e);
211                         break;
212                 
213                 case NCALRPC:
214                         add_socket_rpc_ncalrpc(service, model_ops, dce_ctx, e);
215                         break;
216
217                 case NCACN_IP_TCP:
218                         add_socket_rpc_tcp(service, model_ops, dce_ctx, e);
219                         break;
220
221                 default:
222                         break;
223                 }
224         }
225
226         return; 
227 }
228
229 void dcesrv_sock_accept(struct server_connection *conn)
230 {
231         NTSTATUS status;
232         struct dcesrv_socket_context *dcesrv_sock = conn->server_socket->private_data;
233         struct dcesrv_connection *dcesrv_conn = NULL;
234
235         DEBUG(5,("dcesrv_sock_accept\n"));
236
237         status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx, dcesrv_sock->endpoint, &dcesrv_conn);
238         if (!NT_STATUS_IS_OK(status)) {
239                 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n", 
240                         nt_errstr(status)));
241                 return;
242         }
243
244         dcesrv_conn->srv_conn = conn;
245
246         conn->private_data = dcesrv_conn;
247
248         return; 
249 }
250
251 void dcesrv_sock_recv(struct server_connection *conn, time_t t, uint16_t flags)
252 {
253         NTSTATUS status;
254         struct dcesrv_connection *dce_conn = conn->private_data;
255         DATA_BLOB tmp_blob;
256         size_t nread;
257
258         tmp_blob = data_blob_talloc(conn->socket, NULL, 0x1000);
259         if (tmp_blob.data == NULL) {
260                 dcesrv_terminate_connection(dce_conn, "out of memory");
261                 return;
262         }
263
264         status = socket_recv(conn->socket, tmp_blob.data, tmp_blob.length, &nread, 0);
265         if (NT_STATUS_IS_ERR(status)) {
266                 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
267                 return;
268         }
269         if (nread == 0) {
270                 talloc_free(tmp_blob.data);
271                 return;
272         }
273
274         tmp_blob.length = nread;
275
276         status = dcesrv_input(dce_conn, &tmp_blob);
277         talloc_free(tmp_blob.data);
278
279         if (!NT_STATUS_IS_OK(status)) {
280                 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
281                 return;
282         }
283
284         if (dce_conn->call_list && dce_conn->call_list->replies) {
285                 conn->event.fde->flags |= EVENT_FD_WRITE;
286         }
287
288         return; 
289 }
290
291 void dcesrv_sock_send(struct server_connection *conn, time_t t, uint16_t flags)
292 {
293         struct dcesrv_connection *dce_conn = conn->private_data;
294         NTSTATUS status;
295
296         DEBUG(10,("dcesrv_sock_send\n"));
297
298         status = dcesrv_output(dce_conn, conn->socket, dcerpc_write_fn);
299         if (!NT_STATUS_IS_OK(status)) {
300                 dcesrv_terminate_connection(dce_conn, "eof on socket");
301                 return;
302         }
303
304         if (!dce_conn->call_list || !dce_conn->call_list->replies) {
305                 conn->event.fde->flags &= ~EVENT_FD_WRITE;
306         }
307
308         return;
309 }
310
311 void dcesrv_sock_idle(struct server_connection *conn, time_t t)
312 {
313         DEBUG(10,("dcesrv_sock_idle\n"));
314         conn->event.idle->next_event = t + 5;
315
316         return; 
317 }
318
319 void dcesrv_sock_close(struct server_connection *conn, const char *reason)
320 {
321         struct dcesrv_connection *dce_conn = conn->private_data;
322
323         DEBUG(5,("dcesrv_sock_close: %s\n",reason));
324
325         talloc_free(dce_conn);
326
327         return;
328 }
329
330 void dcesrv_sock_exit(struct server_service *service, const char *reason)
331 {
332         DEBUG(1,("dcesrv_sock_exit: %s\n",reason));
333         return;
334 }