r3304: changed the API to lib/socket/ a little.
[bbaumbach/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
27 struct dcesrv_socket_context {
28         const struct dcesrv_endpoint *endpoint;
29         struct dcesrv_context *dcesrv_ctx;      
30 };
31
32 /*
33   write_fn callback for dcesrv_output()
34 */
35 static ssize_t dcerpc_write_fn(void *private, DATA_BLOB *out)
36 {
37         NTSTATUS status;
38         struct socket_context *sock = private;
39         size_t sendlen;
40
41         status = socket_send(sock, out, &sendlen, 0);
42         if (!NT_STATUS_IS_OK(status)) {
43                 return -1;
44         }
45
46         return sendlen;
47 }
48
49 void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
50 {
51         server_terminate_connection(dce_conn->srv_conn, reason);
52 }
53
54 static void add_socket_rpc_unix(struct server_service *service,
55                                 const struct model_ops *model_ops,
56                                 struct dcesrv_context *dce_ctx,
57                                 struct dcesrv_endpoint *e)
58 {
59         struct server_socket *sock;
60         struct dcesrv_socket_context *dcesrv_sock;
61         uint16_t port = 1;
62
63         sock = service_setup_socket(service,model_ops, "unix", e->ep_description.endpoint, &port);
64         if (!sock) {
65                 DEBUG(0,("service_setup_socket(path=%s) failed\n",e->ep_description.endpoint));
66                 return;
67         }
68
69         dcesrv_sock = talloc_p(sock, struct dcesrv_socket_context);
70         if (!dcesrv_sock) {
71                 DEBUG(0,("talloc_p(sock->mem_ctx, struct dcesrv_socket_context) failed\n"));
72                 return;
73         }
74
75         /* remember the endpoint of this socket */
76         dcesrv_sock->endpoint           = e;
77         dcesrv_sock->dcesrv_ctx         = dce_ctx;
78
79         sock->private_data = dcesrv_sock;
80 }
81
82 static void add_socket_rpc_ncalrpc(struct server_service *service,
83                                                         const struct model_ops *model_ops,
84                                                         struct dcesrv_context *dce_ctx, 
85                                                         struct dcesrv_endpoint *e)
86 {
87         struct server_socket *sock;
88         struct dcesrv_socket_context *dcesrv_sock;
89         uint16_t port = 1;
90         char *full_path;
91
92         if (!e->ep_description.endpoint) {
93                 /* No identifier specified: use DEFAULT. 
94                  * DO NOT hardcode this value anywhere else. Rather, specify 
95                  * no endpoint and let the epmapper worry about it. */
96                 e->ep_description.endpoint = talloc_strdup(dce_ctx, "DEFAULT");
97         }
98
99         full_path = talloc_asprintf(dce_ctx, "%s/%s", lp_ncalrpc_dir(), e->ep_description.endpoint);
100
101         sock = service_setup_socket(service,model_ops, "unix", full_path, &port);
102         if (!sock) {
103                 DEBUG(0,("service_setup_socket(identifier=%s,path=%s) failed\n",e->ep_description.endpoint, full_path));
104                 return;
105         }
106
107         dcesrv_sock = talloc_p(sock, struct dcesrv_socket_context);
108         if (!dcesrv_sock) {
109                 DEBUG(0,("talloc_p(sock->mem_ctx, struct dcesrv_socket_context) failed\n"));
110                 return;
111         }
112
113         /* remember the endpoint of this socket */
114         dcesrv_sock->endpoint           = e;
115         dcesrv_sock->dcesrv_ctx         = dce_ctx;
116
117         sock->private_data = dcesrv_sock;
118
119         return;
120 }
121
122 /*
123   add a socket address to the list of events, one event per dcerpc endpoint
124 */
125 static void add_socket_rpc_tcp_iface(struct server_service *service, 
126                        const struct model_ops *model_ops,
127                        struct dcesrv_context *dce_ctx, 
128                            struct dcesrv_endpoint *e,
129                        struct in_addr *ifip)
130 {
131         struct server_socket *sock;
132         struct dcesrv_socket_context *dcesrv_sock;
133         uint16_t port = 0;
134         char *ip_str = talloc_strdup(service, inet_ntoa(*ifip));
135                         
136         if (e->ep_description.endpoint) 
137                 port = atoi(e->ep_description.endpoint);
138
139         sock = service_setup_socket(service,model_ops, "ipv4", ip_str, &port);
140         if (!sock) {
141                 DEBUG(0,("service_setup_socket(port=%u) failed\n",port));
142                 return;
143         }
144
145         if (e->ep_description.endpoint == NULL) {
146                 e->ep_description.endpoint = talloc_asprintf(dce_ctx, "%d", port);
147         }
148
149         dcesrv_sock = talloc_p(sock, struct dcesrv_socket_context);
150         if (!dcesrv_sock) {
151                 DEBUG(0,("talloc_p(sock->mem_ctx, struct dcesrv_socket_context) failed\n"));
152                 return;
153         }
154
155         /* remember the endpoint of this socket */
156         dcesrv_sock->endpoint           = e;
157         dcesrv_sock->dcesrv_ctx         = dce_ctx;
158
159         sock->private_data = dcesrv_sock;
160
161         talloc_free(ip_str);
162
163         return;
164 }
165
166 static void add_socket_rpc_tcp(struct server_service *service,
167                                                         const struct model_ops *model_ops,
168                                                         struct dcesrv_context *dce_ctx, 
169                                                         struct dcesrv_endpoint *e)
170 {
171         /* Add TCP/IP sockets */
172         if (lp_interfaces() && lp_bind_interfaces_only()) {
173                 int num_interfaces = iface_count();
174                 int i;
175                 for(i = 0; i < num_interfaces; i++) {
176                         struct in_addr *ifip = iface_n_ip(i);
177                         if (ifip == NULL) {
178                                 continue;
179                         }
180                         add_socket_rpc_tcp_iface(service, model_ops, dce_ctx, e, ifip);
181                 }
182         } else {
183                 struct in_addr ifip;
184                 ifip = interpret_addr2(lp_socket_address());
185                 add_socket_rpc_tcp_iface(service, model_ops, dce_ctx, e, &ifip);
186         }
187
188         return;
189 }
190
191 /****************************************************************************
192  Open the listening sockets for RPC over NCACN_IP_TCP/NCALRPC/NCACN_UNIX_STREAM
193 ****************************************************************************/
194 void dcesrv_sock_init(struct server_service *service, const struct model_ops *model_ops, struct dcesrv_context *dce_ctx)
195 {
196         struct dcesrv_endpoint *e;
197
198         DEBUG(1,("dcesrv_sock_init\n"));
199
200         /* Make sure the directory for NCALRPC exists */
201         if (!directory_exist(lp_ncalrpc_dir(), NULL)) {
202                 mkdir(lp_ncalrpc_dir(), S_IWUSR | S_IRUSR | S_IXUSR);
203         }
204
205         for (e=dce_ctx->endpoint_list;e;e=e->next) {
206                 switch (e->ep_description.transport) {
207                 case NCACN_UNIX_STREAM:
208                         add_socket_rpc_unix(service, model_ops, dce_ctx, e);
209                         break;
210                 
211                 case NCALRPC:
212                         add_socket_rpc_ncalrpc(service, model_ops, dce_ctx, e);
213                         break;
214
215                 case NCACN_IP_TCP:
216                         add_socket_rpc_tcp(service, model_ops, dce_ctx, e);
217                         break;
218
219                 default:
220                         break;
221                 }
222         }
223
224         return; 
225 }
226
227 void dcesrv_sock_accept(struct server_connection *conn)
228 {
229         NTSTATUS status;
230         struct dcesrv_socket_context *dcesrv_sock = conn->server_socket->private_data;
231         struct dcesrv_connection *dcesrv_conn = NULL;
232
233         DEBUG(5,("dcesrv_sock_accept\n"));
234
235         status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx, dcesrv_sock->endpoint, &dcesrv_conn);
236         if (!NT_STATUS_IS_OK(status)) {
237                 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n", 
238                         nt_errstr(status)));
239                 return;
240         }
241
242         dcesrv_conn->srv_conn = conn;
243
244         conn->private_data = dcesrv_conn;
245
246         return; 
247 }
248
249 void dcesrv_sock_recv(struct server_connection *conn, time_t t, uint16_t flags)
250 {
251         NTSTATUS status;
252         struct dcesrv_connection *dce_conn = conn->private_data;
253         DATA_BLOB tmp_blob;
254         size_t nread;
255
256         tmp_blob = data_blob_talloc(conn->socket, NULL, 0x1000);
257         if (tmp_blob.data == NULL) {
258                 dcesrv_terminate_connection(dce_conn, "out of memory");
259                 return;
260         }
261
262         status = socket_recv(conn->socket, tmp_blob.data, tmp_blob.length, &nread, 0);
263         if (NT_STATUS_IS_ERR(status)) {
264                 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
265                 return;
266         }
267         if (nread == 0) {
268                 return;
269         }
270
271         tmp_blob.length = nread;
272
273         status = dcesrv_input(dce_conn, &tmp_blob);
274         talloc_free(tmp_blob.data);
275
276         if (!NT_STATUS_IS_OK(status)) {
277                 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
278                 return;
279         }
280
281         if (dce_conn->call_list && dce_conn->call_list->replies) {
282                 conn->event.fde->flags |= EVENT_FD_WRITE;
283         }
284
285         return; 
286 }
287
288 void dcesrv_sock_send(struct server_connection *conn, time_t t, uint16_t flags)
289 {
290         struct dcesrv_connection *dce_conn = conn->private_data;
291         NTSTATUS status;
292
293         DEBUG(10,("dcesrv_sock_send\n"));
294
295         status = dcesrv_output(dce_conn, conn->socket, dcerpc_write_fn);
296         if (!NT_STATUS_IS_OK(status)) {
297                 dcesrv_terminate_connection(dce_conn, "eof on socket");
298                 return;
299         }
300
301         if (!dce_conn->call_list || !dce_conn->call_list->replies) {
302                 conn->event.fde->flags &= ~EVENT_FD_WRITE;
303         }
304
305         return;
306 }
307
308 void dcesrv_sock_idle(struct server_connection *conn, time_t t)
309 {
310         DEBUG(10,("dcesrv_sock_idle\n"));
311         conn->event.idle->next_event = t + 5;
312
313         return; 
314 }
315
316 void dcesrv_sock_close(struct server_connection *conn, const char *reason)
317 {
318         struct dcesrv_connection *dce_conn = conn->private_data;
319
320         DEBUG(5,("dcesrv_sock_close: %s\n",reason));
321
322         talloc_free(dce_conn);
323
324         return;
325 }
326
327 void dcesrv_sock_exit(struct server_service *service, const char *reason)
328 {
329         DEBUG(1,("dcesrv_sock_exit: %s\n",reason));
330         return;
331 }