2 Unix SMB/CIFS implementation.
4 dcerpc over standard sockets transport
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Jelmer Vernooij 2004
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.
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.
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.
25 #include "dlinklist.h"
27 #include "librpc/gen_ndr/ndr_epmapper.h"
29 #define MIN_HDR_SIZE 16
32 struct sock_blob
*next
, *prev
;
36 /* transport private information used by general socket pipe transports */
38 struct event_context
*event_ctx
;
40 struct socket_context
*sock
;
44 struct sock_blob
*pending_send
;
57 static void sock_dead(struct dcerpc_connection
*p
, NTSTATUS status
)
59 struct sock_private
*sock
= p
->transport
.private;
61 if (sock
&& sock
->sock
!= NULL
) {
62 talloc_free(sock
->sock
);
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
);
73 if (!NT_STATUS_IS_OK(status
)) {
74 p
->transport
.recv_data(p
, NULL
, status
);
77 talloc_free(sock
->fde
);
83 static void sock_process_send(struct dcerpc_connection
*p
)
85 struct sock_private
*sock
= p
->transport
.private;
87 while (sock
->pending_send
) {
88 struct sock_blob
*blob
= sock
->pending_send
;
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
);
100 blob
->data
.data
+= sent
;
101 blob
->data
.length
-= sent
;
103 if (blob
->data
.length
!= 0) {
107 DLIST_REMOVE(sock
->pending_send
, blob
);
111 if (sock
->pending_send
== NULL
) {
112 EVENT_FD_NOT_WRITEABLE(sock
->fde
);
118 process recv requests
120 static void sock_process_recv(struct dcerpc_connection
*p
)
122 struct sock_private
*sock
= p
->transport
.private;
126 if (sock
->recv
.data
.data
== NULL
) {
127 sock
->recv
.data
= data_blob_talloc(sock
, NULL
, MIN_HDR_SIZE
);
130 /* read in the base header to get the fragment length */
131 if (sock
->recv
.received
< MIN_HDR_SIZE
) {
132 uint32_t frag_length
;
134 status
= socket_recv(sock
->sock
,
135 sock
->recv
.data
.data
+ sock
->recv
.received
,
136 MIN_HDR_SIZE
- sock
->recv
.received
,
138 if (NT_STATUS_IS_ERR(status
)) {
139 sock_dead(p
, NT_STATUS_NET_WRITE_FAULT
);
146 sock
->recv
.received
+= nread
;
148 if (sock
->recv
.received
!= MIN_HDR_SIZE
) {
151 frag_length
= dcerpc_get_frag_length(&sock
->recv
.data
);
153 sock
->recv
.data
.data
= talloc_realloc(sock
, sock
->recv
.data
.data
,
154 uint8_t, frag_length
);
155 if (sock
->recv
.data
.data
== NULL
) {
156 sock_dead(p
, NT_STATUS_NO_MEMORY
);
159 sock
->recv
.data
.length
= frag_length
;
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
,
167 if (NT_STATUS_IS_ERR(status
)) {
168 sock_dead(p
, NT_STATUS_NET_WRITE_FAULT
);
174 sock
->recv
.received
+= nread
;
176 if (sock
->recv
.received
!= sock
->recv
.data
.length
) {
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 EVENT_FD_NOT_READABLE(sock
->fde
);
192 called when a IO is triggered by the events system
194 static void sock_io_handler(struct event_context
*ev
, struct fd_event
*fde
,
195 uint16_t flags
, void *private)
197 struct dcerpc_connection
*p
= talloc_get_type(private, struct dcerpc_connection
);
198 struct sock_private
*sock
= p
->transport
.private;
200 if (flags
& EVENT_FD_WRITE
) {
201 sock_process_send(p
);
205 if (sock
->sock
== NULL
) {
209 if (flags
& EVENT_FD_READ
) {
210 sock_process_recv(p
);
215 initiate a read request
217 static NTSTATUS
sock_send_read(struct dcerpc_connection
*p
)
219 struct sock_private
*sock
= p
->transport
.private;
221 sock
->recv
.pending_count
++;
222 if (sock
->recv
.pending_count
== 1) {
223 EVENT_FD_READABLE(sock
->fde
);
229 send an initial pdu in a multi-pdu sequence
231 static NTSTATUS
sock_send_request(struct dcerpc_connection
*p
, DATA_BLOB
*data
, BOOL trigger_read
)
233 struct sock_private
*sock
= p
->transport
.private;
234 struct sock_blob
*blob
;
236 if (sock
->sock
== NULL
) {
237 return NT_STATUS_CONNECTION_DISCONNECTED
;
240 blob
= talloc(sock
, struct sock_blob
);
242 return NT_STATUS_NO_MEMORY
;
245 blob
->data
= data_blob_talloc(blob
, data
->data
, data
->length
);
246 if (blob
->data
.data
== NULL
) {
248 return NT_STATUS_NO_MEMORY
;
251 DLIST_ADD_END(sock
->pending_send
, blob
, struct sock_blob
*);
253 EVENT_FD_WRITEABLE(sock
->fde
);
263 return the event context so the caller can process asynchronously
265 static struct event_context
*sock_event_context(struct dcerpc_connection
*p
)
267 struct sock_private
*sock
= p
->transport
.private;
269 return sock
->event_ctx
;
273 shutdown sock pipe connection
275 static NTSTATUS
sock_shutdown_pipe(struct dcerpc_connection
*p
)
277 sock_dead(p
, NT_STATUS_OK
);
283 return sock server name
285 static const char *sock_peer_name(struct dcerpc_connection
*p
)
287 struct sock_private
*sock
= p
->transport
.private;
288 return sock
->server_name
;
292 open a rpc connection using the generic socket library
294 static NTSTATUS
dcerpc_pipe_open_socket(struct dcerpc_connection
*c
,
298 enum dcerpc_transport_t transport
)
300 struct sock_private
*sock
;
301 struct socket_context
*socket_ctx
;
304 sock
= talloc(c
, struct sock_private
);
306 return NT_STATUS_NO_MEMORY
;
309 status
= socket_create(type
, SOCKET_TYPE_STREAM
, &socket_ctx
, 0);
310 if (!NT_STATUS_IS_OK(status
)) {
314 talloc_steal(sock
, socket_ctx
);
316 status
= socket_connect(socket_ctx
, NULL
, 0, server
, port
, 0);
317 if (!NT_STATUS_IS_OK(status
)) {
323 fill in the transport methods
325 c
->transport
.transport
= transport
;
326 c
->transport
.private = NULL
;
328 c
->transport
.send_request
= sock_send_request
;
329 c
->transport
.send_read
= sock_send_read
;
330 c
->transport
.event_context
= sock_event_context
;
331 c
->transport
.recv_data
= NULL
;
333 c
->transport
.shutdown_pipe
= sock_shutdown_pipe
;
334 c
->transport
.peer_name
= sock_peer_name
;
336 sock
->sock
= socket_ctx
;
337 sock
->server_name
= talloc_strdup(sock
, server
);
338 sock
->event_ctx
= event_context_init(sock
);
339 sock
->pending_send
= NULL
;
340 sock
->recv
.received
= 0;
341 sock
->recv
.data
= data_blob(NULL
, 0);
342 sock
->recv
.pending_count
= 0;
344 sock
->fde
= event_add_fd(sock
->event_ctx
, sock
, socket_get_fd(sock
->sock
),
345 0, sock_io_handler
, c
);
347 c
->transport
.private = sock
;
349 /* ensure we don't get SIGPIPE */
350 BlockSignals(True
,SIGPIPE
);
356 open a rpc connection using tcp
358 NTSTATUS
dcerpc_pipe_open_tcp(struct dcerpc_connection
*c
, const char *server
, uint32_t port
)
363 status
= dcerpc_pipe_open_socket(c
, server
, port
, "ipv6", NCACN_IP_TCP
);
364 if (NT_STATUS_IS_OK(status
)) {
368 return dcerpc_pipe_open_socket(c
, server
, port
, "ipv4", NCACN_IP_TCP
);
372 open a rpc connection to a unix socket
374 NTSTATUS
dcerpc_pipe_open_unix_stream(struct dcerpc_connection
*c
, const char *path
)
376 return dcerpc_pipe_open_socket(c
, path
, 0, "unix", NCACN_UNIX_STREAM
);
380 open a rpc connection to a named pipe
382 NTSTATUS
dcerpc_pipe_open_pipe(struct dcerpc_connection
*c
, const char *identifier
)
385 char *canon
, *full_path
;
387 canon
= talloc_strdup(NULL
, identifier
);
389 string_replace(canon
, '/', '\\');
390 full_path
= talloc_asprintf(canon
, "%s/%s", lp_ncalrpc_dir(), canon
);
392 status
= dcerpc_pipe_open_socket(c
, full_path
, 0, "unix", NCALRPC
);