8de43d845495e00445f25e616db4021db0f893e0
[jelmer/samba4-debian.git] / source / librpc / rpc / dcerpc_sock.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    dcerpc over standard sockets transport
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Jelmer Vernooij 2004
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "dlinklist.h"
26 #include "events.h"
27 #include "librpc/gen_ndr/ndr_epmapper.h"
28
29 #define MIN_HDR_SIZE 16
30
31 struct sock_blob {
32         struct sock_blob *next, *prev;
33         DATA_BLOB data;
34 };
35
36 /* transport private information used by general socket pipe transports */
37 struct sock_private {
38         struct event_context *event_ctx;
39         struct fd_event *fde;
40         struct socket_context *sock;
41         char *server_name;
42         uint32_t port;
43
44         struct sock_blob *pending_send;
45
46         struct {
47                 size_t received;
48                 DATA_BLOB data;
49                 uint_t pending_count;
50         } recv;
51 };
52
53
54 /*
55   mark the socket dead
56 */
57 static void sock_dead(struct dcerpc_pipe *p, NTSTATUS status)
58 {
59         struct sock_private *sock = p->transport.private;
60
61         if (sock && sock->sock != NULL) {
62                 talloc_free(sock->sock);
63                 sock->sock = NULL;
64         }
65
66         /* wipe any pending sends */
67         while (sock->pending_send) {
68                 struct sock_blob *blob = sock->pending_send;
69                 DLIST_REMOVE(sock->pending_send, blob);
70                 talloc_free(blob);
71         }
72
73         if (!NT_STATUS_IS_OK(status)) {
74                 p->transport.recv_data(p, NULL, status);
75         }
76
77         sock->fde->flags &= ~(EVENT_FD_WRITE | EVENT_FD_READ);
78 }
79
80 /*
81   process send requests
82 */
83 static void sock_process_send(struct dcerpc_pipe *p)
84 {
85         struct sock_private *sock = p->transport.private;
86
87         while (sock->pending_send) {
88                 struct sock_blob *blob = sock->pending_send;
89                 NTSTATUS status;
90                 size_t sent;
91                 status = socket_send(sock->sock, &blob->data, &sent, 0);
92                 if (NT_STATUS_IS_ERR(status)) {
93                         sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
94                         break;
95                 }
96                 if (sent == 0) {
97                         break;
98                 }
99
100                 blob->data.data += sent;
101                 blob->data.length -= sent;
102
103                 if (blob->data.length != 0) {
104                         break;
105                 }
106
107                 DLIST_REMOVE(sock->pending_send, blob);
108                 talloc_free(blob);
109         }
110
111         if (sock->pending_send == NULL) {
112                 sock->fde->flags &= ~EVENT_FD_WRITE;
113         }
114 }
115
116
117 /*
118   process recv requests
119 */
120 static void sock_process_recv(struct dcerpc_pipe *p)
121 {
122         struct sock_private *sock = p->transport.private;
123         NTSTATUS status;
124         size_t nread;
125
126         if (sock->recv.data.data == NULL) {
127                 sock->recv.data = data_blob_talloc(sock, NULL, MIN_HDR_SIZE);
128         }
129
130         /* read in the base header to get the fragment length */
131         if (sock->recv.received < MIN_HDR_SIZE) {
132                 uint32_t frag_length;
133
134                 status = socket_recv(sock->sock, 
135                                      sock->recv.data.data + sock->recv.received, 
136                                      MIN_HDR_SIZE - sock->recv.received, 
137                                      &nread, 0);
138                 if (NT_STATUS_IS_ERR(status)) {
139                         sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
140                         return;
141                 }
142                 if (nread == 0) {
143                         return;
144                 }
145                 
146                 sock->recv.received += nread;
147
148                 if (sock->recv.received != MIN_HDR_SIZE) {
149                         return;
150                 }
151                 frag_length = dcerpc_get_frag_length(&sock->recv.data);
152
153                 sock->recv.data.data = talloc_realloc(sock, sock->recv.data.data,
154                                                      frag_length);
155                 if (sock->recv.data.data == NULL) {
156                         sock_dead(p, NT_STATUS_NO_MEMORY);
157                         return;
158                 }
159                 sock->recv.data.length = frag_length;
160         }
161
162         /* read in the rest of the packet */
163         status = socket_recv(sock->sock, 
164                              sock->recv.data.data + sock->recv.received, 
165                              sock->recv.data.length - sock->recv.received, 
166                              &nread, 0);
167         if (NT_STATUS_IS_ERR(status)) {
168                 sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
169                 return;
170         }
171         if (nread == 0) {
172                 return;
173         }
174         sock->recv.received += nread;
175
176         if (sock->recv.received != sock->recv.data.length) {
177                 return;
178         }
179
180         /* we have a full packet */
181         p->transport.recv_data(p, &sock->recv.data, NT_STATUS_OK);
182         talloc_free(sock->recv.data.data);
183         sock->recv.data = data_blob(NULL, 0);
184         sock->recv.received = 0;
185         sock->recv.pending_count--;
186         if (sock->recv.pending_count == 0) {
187                 sock->fde->flags &= ~EVENT_FD_READ;
188         }
189 }
190
191 /*
192   called when a IO is triggered by the events system
193 */
194 static void sock_io_handler(struct event_context *ev, struct fd_event *fde, 
195                             struct timeval t, uint16_t flags)
196 {
197         struct dcerpc_pipe *p = fde->private;
198         struct sock_private *sock = p->transport.private;
199
200         if (flags & EVENT_FD_WRITE) {
201                 sock_process_send(p);
202         }
203
204         if (sock->sock == NULL) {
205                 return;
206         }
207
208         if (flags & EVENT_FD_READ) {
209                 sock_process_recv(p);
210         }
211 }
212
213 /* 
214    initiate a read request 
215 */
216 static NTSTATUS sock_send_read(struct dcerpc_pipe *p)
217 {
218         struct sock_private *sock = p->transport.private;
219
220         sock->recv.pending_count++;
221         if (sock->recv.pending_count == 1) {
222                 sock->fde->flags |= EVENT_FD_READ;
223         }
224         return NT_STATUS_OK;
225 }
226
227 /* 
228    send an initial pdu in a multi-pdu sequence
229 */
230 static NTSTATUS sock_send_request(struct dcerpc_pipe *p, DATA_BLOB *data, BOOL trigger_read)
231 {
232         struct sock_private *sock = p->transport.private;
233         struct sock_blob *blob;
234
235         if (sock->sock == NULL) {
236                 return NT_STATUS_CONNECTION_DISCONNECTED;
237         }
238
239         blob = talloc_p(sock, struct sock_blob);
240         if (blob == NULL) {
241                 return NT_STATUS_NO_MEMORY;
242         }
243
244         blob->data = data_blob_talloc(blob, data->data, data->length);
245         if (blob->data.data == NULL) {
246                 talloc_free(blob);
247                 return NT_STATUS_NO_MEMORY;
248         }
249
250         DLIST_ADD_END(sock->pending_send, blob, struct sock_blob *);
251
252         sock->fde->flags |= EVENT_FD_WRITE;
253
254         if (trigger_read) {
255                 sock_send_read(p);
256         }
257
258         return NT_STATUS_OK;
259 }
260
261 /* 
262    return the event context so the caller can process asynchronously
263 */
264 static struct event_context *sock_event_context(struct dcerpc_pipe *p)
265 {
266         struct sock_private *sock = p->transport.private;
267
268         return sock->event_ctx;
269 }
270
271 /* 
272    shutdown sock pipe connection
273 */
274 static NTSTATUS sock_shutdown_pipe(struct dcerpc_pipe *p)
275 {
276         sock_dead(p, NT_STATUS_OK);
277
278         return NT_STATUS_OK;
279 }
280
281 /*
282   return sock server name
283 */
284 static const char *sock_peer_name(struct dcerpc_pipe *p)
285 {
286         struct sock_private *sock = p->transport.private;
287         return sock->server_name;
288 }
289
290 /* 
291    open a rpc connection using the generic socket library
292 */
293 static NTSTATUS dcerpc_pipe_open_socket(struct dcerpc_pipe **p, 
294                                         const char *server,
295                                         uint32_t port, 
296                                         const char *type,
297                                         enum dcerpc_transport_t transport)
298 {
299         struct sock_private *sock;
300         struct socket_context *socket_ctx;
301         struct fd_event fde;
302         NTSTATUS status;
303
304         if (!(*p = dcerpc_pipe_init())) {
305                 return NT_STATUS_NO_MEMORY;
306         }
307  
308         sock = talloc_p((*p), struct sock_private);
309         if (!sock) {
310                 talloc_free(*p);
311                 return NT_STATUS_NO_MEMORY;
312         }
313
314         status = socket_create(type, SOCKET_TYPE_STREAM, &socket_ctx, 0);
315         if (!NT_STATUS_IS_OK(status)) {
316                 talloc_free(*p);
317                 return status;
318         }
319         talloc_steal(sock, socket_ctx);
320
321         status = socket_connect(socket_ctx, NULL, 0, server, port, 0);
322         if (!NT_STATUS_IS_OK(status)) {
323                 talloc_free(*p);
324                 return status;
325         }
326
327         /*
328           fill in the transport methods
329         */
330         (*p)->transport.transport = transport;
331         (*p)->transport.private = NULL;
332
333         (*p)->transport.send_request = sock_send_request;
334         (*p)->transport.send_read = sock_send_read;
335         (*p)->transport.event_context = sock_event_context;
336         (*p)->transport.recv_data = NULL;
337
338         (*p)->transport.shutdown_pipe = sock_shutdown_pipe;
339         (*p)->transport.peer_name = sock_peer_name;
340         
341         sock->sock = socket_ctx;
342         sock->server_name = talloc_strdup((*p), server);
343         sock->event_ctx = event_context_init(sock);
344         sock->pending_send = NULL;
345         sock->recv.received = 0;
346         sock->recv.data = data_blob(NULL, 0);
347         sock->recv.pending_count = 0;
348
349         fde.fd = socket_get_fd(sock->sock);
350         fde.flags = 0;
351         fde.handler = sock_io_handler;
352         fde.private = *p;
353
354         sock->fde = event_add_fd(sock->event_ctx, &fde);
355
356         (*p)->transport.private = sock;
357
358         /* ensure we don't get SIGPIPE */
359         BlockSignals(True,SIGPIPE);
360
361         return NT_STATUS_OK;
362 }
363
364 /* 
365    open a rpc connection using tcp
366 */
367 NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p, const char *server, uint32_t port)
368 {
369         NTSTATUS status;
370         
371         /* Try IPv6 first */
372         status = dcerpc_pipe_open_socket(p, server, port, "ipv6", NCACN_IP_TCP);
373         if (NT_STATUS_IS_OK(status)) {
374                 return status;
375         }
376         
377         return dcerpc_pipe_open_socket(p, server, port, "ipv4", NCACN_IP_TCP);
378 }
379
380 /* 
381    open a rpc connection to a unix socket 
382 */
383 NTSTATUS dcerpc_pipe_open_unix_stream(struct dcerpc_pipe **p, const char *path)
384 {
385         return dcerpc_pipe_open_socket(p, path, 0, "unix", NCACN_UNIX_STREAM);
386 }
387
388 /* 
389    open a rpc connection to a named pipe 
390 */
391 NTSTATUS dcerpc_pipe_open_pipe(struct dcerpc_pipe **p, const char *identifier)
392 {
393         NTSTATUS status;
394         char *canon, *full_path;
395
396         canon = talloc_strdup(NULL, identifier);
397
398         string_replace(canon, '/', '\\');
399         full_path = talloc_asprintf(canon, "%s/%s", lp_ncalrpc_dir(), canon);
400
401         status = dcerpc_pipe_open_socket(p, full_path, 0, "unix", NCALRPC);
402         talloc_free(canon);
403
404         return status;
405 }