separate out the setting of the fde in the packet context from the
[samba-svnmirror.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 "lib/events/events.h"
27 #include "librpc/gen_ndr/ndr_epmapper.h"
28 #include "lib/socket/socket.h"
29 #include "lib/stream/packet.h"
30
31 /* transport private information used by general socket pipe transports */
32 struct sock_private {
33         struct fd_event *fde;
34         struct socket_context *sock;
35         char *server_name;
36
37         struct packet_context *packet;
38         uint32_t pending_reads;
39 };
40
41
42 /*
43   mark the socket dead
44 */
45 static void sock_dead(struct dcerpc_connection *p, NTSTATUS status)
46 {
47         struct sock_private *sock = p->transport.private;
48
49         if (sock && sock->sock != NULL) {
50                 talloc_free(sock->fde);
51                 talloc_free(sock->sock);
52                 sock->sock = NULL;
53         }
54
55         if (!NT_STATUS_IS_OK(status)) {
56                 p->transport.recv_data(p, NULL, status);
57         }
58 }
59
60
61 /*
62   handle socket recv errors
63 */
64 static void sock_error_handler(void *private, NTSTATUS status)
65 {
66         struct dcerpc_connection *p = talloc_get_type(private, 
67                                                       struct dcerpc_connection);
68         sock_dead(p, status);
69 }
70
71 /*
72   check if a blob is a complete packet
73 */
74 static NTSTATUS sock_complete_packet(void *private, DATA_BLOB blob, size_t *size)
75 {
76         if (blob.length < DCERPC_FRAG_LEN_OFFSET+2) {
77                 return STATUS_MORE_ENTRIES;
78         }
79         *size = dcerpc_get_frag_length(&blob);
80         if (*size > blob.length) {
81                 return STATUS_MORE_ENTRIES;
82         }
83         return NT_STATUS_OK;
84 }
85
86 /*
87   process recv requests
88 */
89 static NTSTATUS sock_process_recv(void *private, DATA_BLOB blob)
90 {
91         struct dcerpc_connection *p = talloc_get_type(private, 
92                                                       struct dcerpc_connection);
93         struct sock_private *sock = p->transport.private;
94         sock->pending_reads--;
95         if (sock->pending_reads == 0) {
96                 packet_recv_disable(sock->packet);
97         }
98         p->transport.recv_data(p, &blob, NT_STATUS_OK);
99         return NT_STATUS_OK;
100 }
101
102 /*
103   called when a IO is triggered by the events system
104 */
105 static void sock_io_handler(struct event_context *ev, struct fd_event *fde, 
106                             uint16_t flags, void *private)
107 {
108         struct dcerpc_connection *p = talloc_get_type(private, 
109                                                       struct dcerpc_connection);
110         struct sock_private *sock = p->transport.private;
111
112         if (flags & EVENT_FD_WRITE) {
113                 packet_queue_run(sock->packet);
114                 return;
115         }
116
117         if (sock->sock == NULL) {
118                 return;
119         }
120
121         if (flags & EVENT_FD_READ) {
122                 packet_recv(sock->packet);
123         }
124 }
125
126 /* 
127    initiate a read request - not needed for dcerpc sockets
128 */
129 static NTSTATUS sock_send_read(struct dcerpc_connection *p)
130 {
131         struct sock_private *sock = p->transport.private;
132         sock->pending_reads++;
133         if (sock->pending_reads == 1) {
134                 packet_recv_enable(sock->packet);
135         }
136         return NT_STATUS_OK;
137 }
138
139 /* 
140    send an initial pdu in a multi-pdu sequence
141 */
142 static NTSTATUS sock_send_request(struct dcerpc_connection *p, DATA_BLOB *data, 
143                                   BOOL trigger_read)
144 {
145         struct sock_private *sock = p->transport.private;
146         DATA_BLOB blob;
147         NTSTATUS status;
148
149         if (sock->sock == NULL) {
150                 return NT_STATUS_CONNECTION_DISCONNECTED;
151         }
152
153         blob = data_blob_talloc(sock->packet, data->data, data->length);
154         if (blob.data == NULL) {
155                 return NT_STATUS_NO_MEMORY;
156         }
157
158         status = packet_send(sock->packet, blob);
159         if (!NT_STATUS_IS_OK(status)) {
160                 return status;
161         }
162
163         if (trigger_read) {
164                 sock_send_read(p);
165         }
166
167         return NT_STATUS_OK;
168 }
169
170 /* 
171    shutdown sock pipe connection
172 */
173 static NTSTATUS sock_shutdown_pipe(struct dcerpc_connection *p)
174 {
175         struct sock_private *sock = p->transport.private;
176
177         if (sock && sock->sock) {
178                 sock_dead(p, NT_STATUS_OK);
179         }
180
181         return NT_STATUS_OK;
182 }
183
184 /*
185   return sock server name
186 */
187 static const char *sock_peer_name(struct dcerpc_connection *p)
188 {
189         struct sock_private *sock = p->transport.private;
190         return sock->server_name;
191 }
192
193 /* 
194    open a rpc connection using the generic socket library
195 */
196 static NTSTATUS dcerpc_pipe_open_socket(struct dcerpc_connection *c, 
197                                         const char *server,
198                                         uint32_t port, 
199                                         const char *type,
200                                         enum dcerpc_transport_t transport)
201 {
202         struct sock_private *sock;
203         struct socket_context *socket_ctx;
204         NTSTATUS status;
205
206         sock = talloc(c, struct sock_private);
207         if (!sock) {
208                 return NT_STATUS_NO_MEMORY;
209         }
210
211         status = socket_create(type, SOCKET_TYPE_STREAM, &socket_ctx, 0);
212         if (!NT_STATUS_IS_OK(status)) {
213                 talloc_free(sock);
214                 return status;
215         }
216         talloc_steal(sock, socket_ctx);
217
218         status = socket_connect_ev(socket_ctx, NULL, 0, server, port, 0, c->event_ctx);
219         if (!NT_STATUS_IS_OK(status)) {
220                 talloc_free(sock);
221                 return status;
222         }
223
224         /*
225           fill in the transport methods
226         */
227         c->transport.transport = transport;
228         c->transport.private = NULL;
229
230         c->transport.send_request = sock_send_request;
231         c->transport.send_read = sock_send_read;
232         c->transport.recv_data = NULL;
233
234         c->transport.shutdown_pipe = sock_shutdown_pipe;
235         c->transport.peer_name = sock_peer_name;
236         
237         sock->sock = socket_ctx;
238         sock->pending_reads = 0;
239         sock->server_name = strupper_talloc(sock, server);
240
241         sock->fde = event_add_fd(c->event_ctx, sock->sock, socket_get_fd(sock->sock),
242                                  0, sock_io_handler, c);
243
244         c->transport.private = sock;
245
246         sock->packet = packet_init(sock);
247         if (sock->packet == NULL) {
248                 talloc_free(sock);
249                 return NT_STATUS_NO_MEMORY;
250         }
251         packet_set_private(sock->packet, c);
252         packet_set_socket(sock->packet, sock->sock);
253         packet_set_callback(sock->packet, sock_process_recv);
254         packet_set_full_request(sock->packet, sock_complete_packet);
255         packet_set_error_handler(sock->packet, sock_error_handler);
256         packet_set_event_context(sock->packet, c->event_ctx);
257         packet_set_fde(sock->packet, sock->fde);
258         packet_set_serialise(sock->packet);
259         packet_recv_disable(sock->packet);
260         packet_set_initial_read(sock->packet, 16);
261
262         /* ensure we don't get SIGPIPE */
263         BlockSignals(True,SIGPIPE);
264
265         return NT_STATUS_OK;
266 }
267
268 /* 
269    open a rpc connection using tcp
270 */
271 NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_connection *c, const char *server, uint32_t port)
272 {
273         NTSTATUS status;
274         
275         /* Try IPv6 first */
276         status = dcerpc_pipe_open_socket(c, server, port, "ipv6", NCACN_IP_TCP);
277         if (NT_STATUS_IS_OK(status)) {
278                 return status;
279         }
280         
281         return dcerpc_pipe_open_socket(c, server, port, "ipv4", NCACN_IP_TCP);
282 }
283
284 /* 
285    open a rpc connection to a unix socket 
286 */
287 NTSTATUS dcerpc_pipe_open_unix_stream(struct dcerpc_connection *c, const char *path)
288 {
289         return dcerpc_pipe_open_socket(c, path, 0, "unix", NCACN_UNIX_STREAM);
290 }
291
292 /* 
293    open a rpc connection to a named pipe 
294 */
295 NTSTATUS dcerpc_pipe_open_pipe(struct dcerpc_connection *c, const char *identifier)
296 {
297         NTSTATUS status;
298         char *canon, *full_path;
299
300         canon = talloc_strdup(NULL, identifier);
301
302         string_replace(canon, '/', '\\');
303         full_path = talloc_asprintf(canon, "%s/%s", lp_ncalrpc_dir(), canon);
304
305         status = dcerpc_pipe_open_socket(c, full_path, 0, "unix", NCALRPC);
306         talloc_free(canon);
307
308         return status;
309 }