r3205: Create ncalrpc directory if it didn't exist yet
[jra/samba/.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, 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: generate one */
94                 e->ep_description.endpoint = generate_random_str(dce_ctx, 10);
95         }
96
97         full_path = talloc_asprintf(dce_ctx, "%s/%s", lp_ncalrpc_dir(), e->ep_description.endpoint);
98
99         sock = service_setup_socket(service,model_ops, "unix", full_path, &port);
100         if (!sock) {
101                 DEBUG(0,("service_setup_socket(identifier=%s,path=%s) failed\n",e->ep_description.endpoint, full_path));
102                 return;
103         }
104
105         dcesrv_sock = talloc_p(sock, struct dcesrv_socket_context);
106         if (!dcesrv_sock) {
107                 DEBUG(0,("talloc_p(sock->mem_ctx, struct dcesrv_socket_context) failed\n"));
108                 return;
109         }
110
111         /* remember the endpoint of this socket */
112         dcesrv_sock->endpoint           = e;
113         dcesrv_sock->dcesrv_ctx         = dce_ctx;
114
115         sock->private_data = dcesrv_sock;
116
117         return;
118 }
119
120 /*
121   add a socket address to the list of events, one event per dcerpc endpoint
122 */
123 static void add_socket_rpc_tcp_iface(struct server_service *service, 
124                        const struct model_ops *model_ops,
125                        struct dcesrv_context *dce_ctx, 
126                            struct dcesrv_endpoint *e,
127                        struct in_addr *ifip)
128 {
129         struct server_socket *sock;
130         struct dcesrv_socket_context *dcesrv_sock;
131         uint16_t port = 0;
132         const char *ip_str = talloc_strdup(service, inet_ntoa(*ifip));
133                         
134         if (e->ep_description.endpoint) 
135                 port = atoi(e->ep_description.endpoint);
136
137         sock = service_setup_socket(service,model_ops, "ipv4", ip_str, &port);
138         if (!sock) {
139                 DEBUG(0,("service_setup_socket(port=%u) failed\n",port));
140                 return;
141         }
142
143         if (e->ep_description.endpoint == NULL) {
144                 e->ep_description.endpoint = talloc_asprintf(dce_ctx, "%d", port);
145         }
146
147         dcesrv_sock = talloc_p(sock, struct dcesrv_socket_context);
148         if (!dcesrv_sock) {
149                 DEBUG(0,("talloc_p(sock->mem_ctx, struct dcesrv_socket_context) failed\n"));
150                 return;
151         }
152
153         /* remember the endpoint of this socket */
154         dcesrv_sock->endpoint           = e;
155         dcesrv_sock->dcesrv_ctx         = dce_ctx;
156
157         sock->private_data = dcesrv_sock;
158
159         talloc_free(ip_str);
160
161         return;
162 }
163
164 static void add_socket_rpc_tcp(struct server_service *service,
165                                                         const struct model_ops *model_ops,
166                                                         struct dcesrv_context *dce_ctx, 
167                                                         struct dcesrv_endpoint *e)
168 {
169         /* Add TCP/IP sockets */
170         if (lp_interfaces() && lp_bind_interfaces_only()) {
171                 int num_interfaces = iface_count();
172                 int i;
173                 for(i = 0; i < num_interfaces; i++) {
174                         struct in_addr *ifip = iface_n_ip(i);
175                         if (ifip == NULL) {
176                                 continue;
177                         }
178                         add_socket_rpc_tcp_iface(service, model_ops, dce_ctx, e, ifip);
179                 }
180         } else {
181                 struct in_addr *ifip;
182                 ifip = interpret_addr2(dce_ctx, lp_socket_address());
183                 add_socket_rpc_tcp_iface(service, model_ops, dce_ctx, e, ifip);
184                 talloc_free(ifip);
185         }
186
187         return;
188 }
189
190 /****************************************************************************
191  Open the listening sockets for RPC over NCACN_IP_TCP/NCALRPC/NCACN_UNIX_STREAM
192 ****************************************************************************/
193 void dcesrv_sock_init(struct server_service *service, const struct model_ops *model_ops, struct dcesrv_context *dce_ctx)
194 {
195         struct dcesrv_endpoint *e;
196
197         DEBUG(1,("dcesrv_sock_init\n"));
198
199         /* Make sure the directory for NCALRPC exists */
200         if (!directory_exist(lp_ncalrpc_dir(), NULL)) {
201                 mkdir(lp_ncalrpc_dir(), 700);
202         }
203
204         for (e=dce_ctx->endpoint_list;e;e=e->next) {
205                 switch (e->ep_description.transport) {
206                 case NCACN_UNIX_STREAM:
207                         add_socket_rpc_unix(service, model_ops, dce_ctx, e);
208                         break;
209                 
210                 case NCALRPC:
211                         add_socket_rpc_ncalrpc(service, model_ops, dce_ctx, e);
212                         break;
213
214                 case NCACN_IP_TCP:
215                         add_socket_rpc_tcp(service, model_ops, dce_ctx, e);
216                         break;
217
218                 default:
219                         break;
220                 }
221         }
222
223         return; 
224 }
225
226 void dcesrv_sock_accept(struct server_connection *conn)
227 {
228         NTSTATUS status;
229         struct dcesrv_socket_context *dcesrv_sock = conn->server_socket->private_data;
230         struct dcesrv_connection *dcesrv_conn = NULL;
231
232         DEBUG(5,("dcesrv_sock_accept\n"));
233
234         status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx, dcesrv_sock->endpoint, &dcesrv_conn);
235         if (!NT_STATUS_IS_OK(status)) {
236                 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n", 
237                         nt_errstr(status)));
238                 return;
239         }
240
241         dcesrv_conn->srv_conn = conn;
242
243         conn->private_data = dcesrv_conn;
244
245         return; 
246 }
247
248 void dcesrv_sock_recv(struct server_connection *conn, time_t t, uint16_t flags)
249 {
250         NTSTATUS status;
251         struct dcesrv_connection *dce_conn = conn->private_data;
252         DATA_BLOB tmp_blob;
253
254         DEBUG(10,("dcesrv_sock_recv\n"));
255
256         status = socket_recv(conn->socket, conn->socket, &tmp_blob, 0x4000, 0);
257         if (!NT_STATUS_IS_OK(status)) {
258                 if (NT_STATUS_IS_ERR(status)) {
259                         dcesrv_terminate_connection(dce_conn, "eof on socket");
260                         return;
261                 }
262                 return;
263         }
264
265         status = dcesrv_input(dce_conn, &tmp_blob);
266         talloc_free(tmp_blob.data);
267         if (!NT_STATUS_IS_OK(status)) {
268                 dcesrv_terminate_connection(dce_conn, "eof on socket");
269                 return;
270         }
271
272         if (dce_conn->call_list && dce_conn->call_list->replies) {
273                 conn->event.fde->flags |= EVENT_FD_WRITE;
274         }
275
276         return; 
277 }
278
279 void dcesrv_sock_send(struct server_connection *conn, time_t t, uint16_t flags)
280 {
281         struct dcesrv_connection *dce_conn = conn->private_data;
282         NTSTATUS status;
283
284         DEBUG(10,("dcesrv_sock_send\n"));
285
286         status = dcesrv_output(dce_conn, conn->socket, dcerpc_write_fn);
287         if (!NT_STATUS_IS_OK(status)) {
288                 dcesrv_terminate_connection(dce_conn, "eof on socket");
289                 return;
290         }
291
292         if (!dce_conn->call_list || !dce_conn->call_list->replies) {
293                 conn->event.fde->flags &= ~EVENT_FD_WRITE;
294         }
295
296         return;
297 }
298
299 void dcesrv_sock_idle(struct server_connection *conn, time_t t)
300 {
301         DEBUG(10,("dcesrv_sock_idle\n"));
302         conn->event.idle->next_event = t + 5;
303
304         return; 
305 }
306
307 void dcesrv_sock_close(struct server_connection *conn, const char *reason)
308 {
309         struct dcesrv_connection *dce_conn = conn->private_data;
310
311         DEBUG(5,("dcesrv_sock_close: %s\n",reason));
312
313         talloc_free(dce_conn);
314
315         return;
316 }
317
318 void dcesrv_sock_exit(struct server_service *service, const char *reason)
319 {
320         DEBUG(1,("dcesrv_sock_exit: %s\n",reason));
321         return;
322 }