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.
26 #define MIN_HDR_SIZE 16
29 struct sock_blob *next, *prev;
33 /* transport private information used by general socket pipe transports */
35 struct event_context *event_ctx;
37 struct socket_context *sock;
41 struct sock_blob *pending_send;
54 static void sock_dead(struct dcerpc_pipe *p, NTSTATUS status)
56 struct sock_private *sock = p->transport.private;
58 if (sock && sock->sock != NULL) {
59 talloc_free(sock->sock);
63 /* wipe any pending sends */
64 while (sock->pending_send) {
65 struct sock_blob *blob = sock->pending_send;
66 DLIST_REMOVE(sock->pending_send, blob);
70 if (!NT_STATUS_IS_OK(status)) {
71 p->transport.recv_data(p, NULL, status);
78 static void sock_process_send(struct dcerpc_pipe *p)
80 struct sock_private *sock = p->transport.private;
82 while (sock->pending_send) {
83 struct sock_blob *blob = sock->pending_send;
86 status = socket_send(sock->sock, blob, &blob->data, &sent, 0);
87 if (NT_STATUS_IS_ERR(status)) {
88 sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
95 blob->data.data += sent;
96 blob->data.length -= sent;
98 if (blob->data.length != 0) {
102 DLIST_REMOVE(sock->pending_send, blob);
106 if (sock->pending_send == NULL) {
107 sock->fde->flags &= ~EVENT_FD_WRITE;
113 process recv requests
115 static void sock_process_recv(struct dcerpc_pipe *p)
117 struct sock_private *sock = p->transport.private;
121 if (sock->recv.data.data == NULL) {
122 sock->recv.data = data_blob_talloc(sock, NULL, MIN_HDR_SIZE);
125 /* read in the base header to get the fragment length */
126 if (sock->recv.received < MIN_HDR_SIZE) {
127 uint32_t frag_length;
129 status = socket_recv(sock->sock, sock, &blob, MIN_HDR_SIZE - sock->recv.received, 0);
130 if (NT_STATUS_IS_ERR(status)) {
131 sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
134 if (blob.length == 0) {
138 memcpy(sock->recv.data.data + sock->recv.received,
139 blob.data, blob.length);
140 sock->recv.received += blob.length;
141 talloc_free(blob.data);
143 if (sock->recv.received != MIN_HDR_SIZE) {
146 frag_length = dcerpc_get_frag_length(&sock->recv.data);
148 sock->recv.data.data = talloc_realloc(sock, sock->recv.data.data,
150 if (sock->recv.data.data == NULL) {
151 sock_dead(p, NT_STATUS_NO_MEMORY);
154 sock->recv.data.length = frag_length;
157 /* read in the rest of the packet */
158 status = socket_recv(sock->sock, sock, &blob, sock->recv.data.length - sock->recv.received, 0);
159 if (NT_STATUS_IS_ERR(status)) {
160 sock_dead(p, NT_STATUS_NET_WRITE_FAULT);
163 if (blob.length == 0) {
166 memcpy(sock->recv.data.data + sock->recv.received,
167 blob.data, blob.length);
168 sock->recv.received += blob.length;
169 talloc_free(blob.data);
171 if (sock->recv.received != sock->recv.data.length) {
175 /* we have a full packet */
176 p->transport.recv_data(p, &sock->recv.data, NT_STATUS_OK);
177 talloc_free(sock->recv.data.data);
178 sock->recv.data = data_blob(NULL, 0);
179 sock->recv.received = 0;
180 sock->recv.pending_count--;
181 if (sock->recv.pending_count == 0) {
182 sock->fde->flags &= ~EVENT_FD_READ;
187 called when a IO is triggered by the events system
189 static void sock_io_handler(struct event_context *ev, struct fd_event *fde,
190 time_t t, uint16_t flags)
192 struct dcerpc_pipe *p = fde->private;
193 struct sock_private *sock = p->transport.private;
195 if (flags & EVENT_FD_WRITE) {
196 sock_process_send(p);
199 if (sock->sock == NULL) {
203 if (flags & EVENT_FD_READ) {
204 sock_process_recv(p);
209 initiate a read request
211 static NTSTATUS sock_send_read(struct dcerpc_pipe *p)
213 struct sock_private *sock = p->transport.private;
215 sock->recv.pending_count++;
216 if (sock->recv.pending_count == 1) {
217 sock->fde->flags |= EVENT_FD_READ;
223 send an initial pdu in a multi-pdu sequence
225 static NTSTATUS sock_send_request(struct dcerpc_pipe *p, DATA_BLOB *data, BOOL trigger_read)
227 struct sock_private *sock = p->transport.private;
228 struct sock_blob *blob;
230 blob = talloc_p(sock, struct sock_blob);
232 return NT_STATUS_NO_MEMORY;
235 blob->data = data_blob_talloc(blob, data->data, data->length);
236 if (blob->data.data == NULL) {
238 return NT_STATUS_NO_MEMORY;
241 DLIST_ADD_END(sock->pending_send, blob, struct sock_blob *);
243 sock->fde->flags |= EVENT_FD_WRITE;
253 return the event context so the caller can process asynchronously
255 static struct event_context *sock_event_context(struct dcerpc_pipe *p)
257 struct sock_private *sock = p->transport.private;
259 return sock->event_ctx;
263 shutdown sock pipe connection
265 static NTSTATUS sock_shutdown_pipe(struct dcerpc_pipe *p)
267 sock_dead(p, NT_STATUS_OK);
273 return sock server name
275 static const char *sock_peer_name(struct dcerpc_pipe *p)
277 struct sock_private *sock = p->transport.private;
278 return sock->server_name;
282 open a rpc connection using the generic socket library
284 static NTSTATUS dcerpc_pipe_open_socket(struct dcerpc_pipe **p,
288 enum dcerpc_transport_t transport)
290 struct sock_private *sock;
291 struct socket_context *socket_ctx;
296 port = EPMAPPER_PORT;
299 if (!(*p = dcerpc_pipe_init())) {
300 return NT_STATUS_NO_MEMORY;
303 sock = talloc_p((*p), 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 (*p)->transport.transport = transport;
326 (*p)->transport.private = NULL;
328 (*p)->transport.send_request = sock_send_request;
329 (*p)->transport.send_read = sock_send_read;
330 (*p)->transport.event_context = sock_event_context;
331 (*p)->transport.recv_data = NULL;
333 (*p)->transport.shutdown_pipe = sock_shutdown_pipe;
334 (*p)->transport.peer_name = sock_peer_name;
336 sock->sock = socket_ctx;
337 sock->server_name = talloc_strdup((*p), 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 fde.fd = socket_get_fd(sock->sock);
346 fde.handler = sock_io_handler;
349 sock->fde = event_add_fd(sock->event_ctx, &fde);
351 (*p)->transport.private = sock;
353 /* ensure we don't get SIGPIPE */
354 BlockSignals(True,SIGPIPE);
360 open a rpc connection using tcp
362 NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p, const char *server, uint32_t port)
364 return dcerpc_pipe_open_socket(p, server, port, "ip", NCACN_IP_TCP);
368 open a rpc connection to a unix socket
370 NTSTATUS dcerpc_pipe_open_unix_stream(struct dcerpc_pipe **p, const char *path)
372 return dcerpc_pipe_open_socket(p, path, 0, "unix", NCACN_UNIX_STREAM);
376 open a rpc connection to a named pipe
378 NTSTATUS dcerpc_pipe_open_pipe(struct dcerpc_pipe **p, const char *identifier)
381 char *canon, *full_path;
383 canon = talloc_strdup(NULL, identifier);
385 string_replace(canon, '/', '\\');
386 full_path = talloc_asprintf(canon, "%s/%s", lp_ncalrpc_dir(), canon);
388 status = dcerpc_pipe_open_socket(p, full_path, 0, "unix", NCALRPC);