7b6b45d2dd00b6ea10c6002cf75e080a19cc104a
[samba.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    Copyright (C) Rafal Szczesniak 2006
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 #include "lib/events/events.h"
27 #include "lib/socket/socket.h"
28 #include "lib/stream/packet.h"
29 #include "libcli/composite/composite.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 struct pipe_open_socket_state {
195         struct dcerpc_connection *conn;
196         struct socket_context *socket_ctx;
197         struct sock_private *sock;
198         struct socket_address *server;
199         enum dcerpc_transport_t transport;
200 };
201
202
203 static void continue_socket_connect(struct composite_context *ctx)
204 {
205         struct dcerpc_connection *conn;
206         struct sock_private *sock;
207         struct composite_context *c = talloc_get_type(ctx->async.private_data,
208                                                       struct composite_context);
209         struct pipe_open_socket_state *s = talloc_get_type(c->private_data,
210                                                            struct pipe_open_socket_state);
211
212         /* make it easier to write a function calls */
213         conn = s->conn;
214         sock = s->sock;
215
216         c->status = socket_connect_recv(ctx);
217         if (!NT_STATUS_IS_OK(c->status)) {
218                 DEBUG(0, ("Failed to connect host %s on port %d - %s\n", 
219                           s->server->addr, s->server->port,
220                           nt_errstr(c->status)));
221                 composite_error(c, c->status);
222                 return;
223         }
224
225         /*
226           fill in the transport methods
227         */
228         conn->transport.transport     = s->transport;
229         conn->transport.private       = NULL;
230
231         conn->transport.send_request  = sock_send_request;
232         conn->transport.send_read     = sock_send_read;
233         conn->transport.recv_data     = NULL;
234
235         conn->transport.shutdown_pipe = sock_shutdown_pipe;
236         conn->transport.peer_name     = sock_peer_name;
237
238         sock->sock          = s->socket_ctx;
239         sock->pending_reads = 0;
240         sock->server_name   = strupper_talloc(sock, s->server->addr);
241
242         sock->fde = event_add_fd(conn->event_ctx, sock->sock, socket_get_fd(sock->sock),
243                                  0, sock_io_handler, conn);
244         
245         conn->transport.private = sock;
246
247         sock->packet = packet_init(sock);
248         if (sock->packet == NULL) {
249                 composite_error(c, NT_STATUS_NO_MEMORY);
250                 talloc_free(sock);
251                 return;
252         }
253
254         packet_set_private(sock->packet, conn);
255         packet_set_socket(sock->packet, sock->sock);
256         packet_set_callback(sock->packet, sock_process_recv);
257         packet_set_full_request(sock->packet, sock_complete_packet);
258         packet_set_error_handler(sock->packet, sock_error_handler);
259         packet_set_event_context(sock->packet, conn->event_ctx);
260         packet_set_fde(sock->packet, sock->fde);
261         packet_set_serialise(sock->packet);
262         packet_recv_disable(sock->packet);
263         packet_set_initial_read(sock->packet, 16);
264
265         /* ensure we don't get SIGPIPE */
266         BlockSignals(True,SIGPIPE);
267
268         composite_done(c);
269 }
270
271
272 struct composite_context *dcerpc_pipe_open_socket_send(TALLOC_CTX *mem_ctx,
273                                                        struct dcerpc_connection *cn,
274                                                        struct socket_address *server,
275                                                        enum dcerpc_transport_t transport)
276 {
277         NTSTATUS status;
278         struct composite_context *c;
279         struct pipe_open_socket_state *s;
280         struct composite_context *conn_req;
281
282         c = talloc_zero(mem_ctx, struct composite_context);
283         if (c == NULL) return NULL;
284
285         s = talloc_zero(c, struct pipe_open_socket_state);
286         if (s == NULL) {
287                 composite_error(c, NT_STATUS_NO_MEMORY);
288                 goto done;
289         }
290
291         c->state = COMPOSITE_STATE_IN_PROGRESS;
292         c->private_data = s;
293         c->event_ctx = cn->event_ctx;
294
295         s->conn      = cn;
296         s->transport = transport;
297         s->server    = talloc_reference(c, server);
298         if (s->server == NULL) {
299                 composite_error(c, NT_STATUS_NO_MEMORY);
300                 goto done;
301         }
302
303         s->sock = talloc(cn, struct sock_private);
304         if (s->sock == NULL) {
305                 composite_error(c, NT_STATUS_NO_MEMORY);
306                 goto done;
307         }
308
309         status = socket_create(server->family, SOCKET_TYPE_STREAM, &s->socket_ctx, 0);
310         if (!NT_STATUS_IS_OK(status)) {
311                 composite_error(c, status);
312                 talloc_free(s->sock);
313                 goto done;
314         }
315         talloc_steal(s->sock, s->socket_ctx);
316
317         conn_req = socket_connect_send(s->socket_ctx, NULL, s->server, 0, c->event_ctx);
318         if (conn_req == NULL) {
319                 composite_error(c, NT_STATUS_NO_MEMORY);
320                 goto done;
321         }
322         
323         composite_continue(c, conn_req, continue_socket_connect, c);
324
325 done:
326         return c;
327 }
328
329
330 NTSTATUS dcerpc_pipe_open_socket_recv(struct composite_context *c)
331 {
332         NTSTATUS status = composite_wait(c);
333
334         talloc_free(c);
335         return status;
336 }
337
338 /* 
339    open a rpc connection using the generic socket library
340 */
341 NTSTATUS dcerpc_pipe_open_socket(struct dcerpc_connection *conn,
342                                  struct socket_address *server,
343                                  enum dcerpc_transport_t transport)
344 {
345         struct composite_context *c;
346         
347         c = dcerpc_pipe_open_socket_send(conn, conn, server, transport);
348         return dcerpc_pipe_open_socket_recv(c);
349 }
350
351
352 struct pipe_tcp_state {
353         const char *server;
354         uint32_t port;
355         struct socket_address *srvaddr;
356         struct dcerpc_connection *conn;
357 };
358
359
360 void continue_ipv6_open_socket(struct composite_context *ctx);
361 void continue_ipv4_open_socket(struct composite_context *ctx);
362
363
364 /*
365   Stage 2 of dcerpc_pipe_open_tcp_send: receive result of pipe open request
366   on IPv6 and send the request on IPv4 unless IPv6 transport succeeded.
367 */
368 void continue_ipv6_open_socket(struct composite_context *ctx)
369 {
370         struct composite_context *c = talloc_get_type(ctx->async.private_data,
371                                                       struct composite_context);
372         struct pipe_tcp_state *s = talloc_get_type(c->private_data,
373                                                    struct pipe_tcp_state);
374         struct composite_context *sock_ipv4_req;
375
376         /* receive result of socket open request */
377         c->status = dcerpc_pipe_open_socket_recv(ctx);
378         if (NT_STATUS_IS_OK(c->status)) return;
379
380         talloc_free(s->srvaddr);
381
382         /* prepare server address using host:ip and transport name */
383         s->srvaddr = socket_address_from_strings(s->conn, "ipv4", s->server, s->port);
384         if (!s->srvaddr) {
385                 composite_error(c, NT_STATUS_NO_MEMORY);
386                 return;
387         }
388         
389         /* try IPv4 if IPv6 fails */
390         sock_ipv4_req = dcerpc_pipe_open_socket_send(c, s->conn, s->srvaddr, NCACN_IP_TCP);
391         if (sock_ipv4_req == NULL) {
392                 composite_error(c, NT_STATUS_NO_MEMORY);
393                 return;
394         }
395
396         composite_continue(c, sock_ipv4_req, continue_ipv4_open_socket, c);
397 }
398
399
400 /*
401   Stage 2 of dcerpc_pipe_open_tcp_send: receive result of pipe open request
402   on IPv4 transport.
403 */
404 void continue_ipv4_open_socket(struct composite_context *ctx)
405 {
406         struct composite_context *c = talloc_get_type(ctx->async.private_data,
407                                                       struct composite_context);
408         struct pipe_tcp_state *s = talloc_get_type(c->private_data,
409                                                    struct pipe_tcp_state);
410         
411         /* receive result socket open request */
412         c->status = dcerpc_pipe_open_socket_recv(ctx);
413         if (NT_STATUS_IS_OK(c->status)) {
414                 composite_done(c);
415                 return;
416         }
417
418         /* something went wrong... */
419         DEBUG(0, ("Failed to connect host %s on port %d - %s.\n",
420                   s->server, s->port, nt_errstr(c->status)));
421
422         composite_error(c, c->status);
423 }
424
425
426 /*
427   Send rpc pipe open request to given host:port using
428   tcp/ip transport
429 */
430 struct composite_context* dcerpc_pipe_open_tcp_send(struct dcerpc_connection *conn,
431                                                     const char* server, uint32_t port)
432 {
433         struct composite_context *c;
434         struct composite_context *sock_ipv6_req;
435         struct pipe_tcp_state *s;
436
437         /* composite context allocation and setup */
438         c = talloc_zero(conn, struct composite_context);
439         if (c == NULL) return NULL;
440
441         s = talloc_zero(c, struct pipe_tcp_state);
442         if (s == NULL) {
443                 composite_error(c, NT_STATUS_NO_MEMORY);
444                 goto done;
445         }
446         
447         c->state = COMPOSITE_STATE_IN_PROGRESS;
448         c->private_data = s;
449         c->event_ctx = conn->event_ctx;
450
451         /* store input parameters in state structure */
452         s->server = talloc_strdup(c, server);
453         s->port   = port;
454         s->conn   = conn;
455         
456         /* prepare server address using host ip:port and transport name */
457         s->srvaddr = socket_address_from_strings(s->conn, "ipv6", s->server, s->port);
458         if (!s->srvaddr) {
459                 composite_error(c, NT_STATUS_NO_MEMORY);
460                 goto done;
461         }
462
463         /* try IPv6 first - send socket open request */
464         sock_ipv6_req = dcerpc_pipe_open_socket_send(c, s->conn, s->srvaddr, NCACN_IP_TCP);
465         if (sock_ipv6_req == NULL) {
466                 composite_error(c, NT_STATUS_NO_MEMORY);
467                 goto done;
468         }
469
470         composite_continue(c, sock_ipv6_req, continue_ipv6_open_socket, c);
471 done:
472         return c;
473 }
474
475
476 /*
477   Receive result of pipe open request on tcp/ip
478 */
479 NTSTATUS dcerpc_pipe_open_tcp_recv(struct composite_context *c)
480 {
481         NTSTATUS status;
482         status = composite_wait(c);
483
484         talloc_free(c);
485         return status;
486 }
487
488
489 /*
490   Open rpc pipe on tcp/ip transport - sync version
491 */
492 NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_connection *conn, const char *server,
493                               uint32_t port)
494 {
495         struct composite_context *c;
496
497         c = dcerpc_pipe_open_tcp_send(conn, server, port);
498         return dcerpc_pipe_open_tcp_recv(c);
499 }
500
501
502 struct pipe_unix_state {
503         const char *path;
504         struct socket_address *srvaddr;
505         struct dcerpc_connection *conn;
506 };
507
508
509 /*
510   Stage 2 of dcerpc_pipe_open_unix_stream_send: receive result of pipe open
511   request on unix socket.
512 */
513 void continue_unix_open_socket(struct composite_context *ctx)
514 {
515         struct composite_context *c = talloc_get_type(ctx->async.private_data,
516                                                       struct composite_context);
517
518         c->status = dcerpc_pipe_open_socket_recv(ctx);
519         if (NT_STATUS_IS_OK(c->status)) {
520                 composite_done(c);
521                 return;
522         }
523
524         composite_error(c, c->status);
525 }
526
527
528 /*
529   Send pipe open request on unix socket
530 */
531 struct composite_context *dcerpc_pipe_open_unix_stream_send(struct dcerpc_connection *conn,
532                                                             const char *path)
533 {
534         struct composite_context *c;
535         struct composite_context *sock_unix_req;
536         struct pipe_unix_state *s;
537
538         /* composite context allocation and setup */
539         c = talloc_zero(conn, struct composite_context);
540         if (c == NULL) return NULL;
541
542         s = talloc_zero(c, struct pipe_unix_state);
543         if (s == NULL) {
544                 composite_error(c, NT_STATUS_NO_MEMORY);
545                 goto done;
546         }
547         
548         c->state = COMPOSITE_STATE_IN_PROGRESS;
549         c->private_data = s;
550         c->event_ctx = conn->event_ctx;
551
552         /* store parameters in state structure */
553         s->path = talloc_strdup(c, path);
554         s->conn = conn;
555
556         /* prepare server address using socket path and transport name */
557         s->srvaddr = socket_address_from_strings(conn, "unix", s->path, 0);
558         if (s->srvaddr == NULL) {
559                 composite_error(c, NT_STATUS_NO_MEMORY);
560                 goto done;
561         }
562
563         /* send socket open request */
564         sock_unix_req = dcerpc_pipe_open_socket_send(c, s->conn, s->srvaddr, NCALRPC);
565         if (sock_unix_req == NULL) {
566                 composite_error(c, NT_STATUS_NO_MEMORY);
567                 goto done;
568         }
569
570         composite_continue(c, sock_unix_req, continue_unix_open_socket, c);
571
572 done:
573         return c;
574 }
575
576
577 /*
578   Receive result of pipe open request on unix socket
579 */
580 NTSTATUS dcerpc_pipe_open_unix_stream_recv(struct composite_context *c)
581 {
582         NTSTATUS status = composite_wait(c);
583
584         talloc_free(c);
585         return status;
586 }
587
588
589 /*
590   Open a rpc pipe on a unix socket - sync version
591 */
592 NTSTATUS dcerpc_pipe_open_unix_stream(struct dcerpc_connection *conn, const char *path)
593 {
594         struct composite_context *c = dcerpc_pipe_open_unix_stream_send(conn, path);
595         return dcerpc_pipe_open_unix_stream_recv(c);
596 }
597
598
599 struct pipe_np_state {
600         char *full_path;
601         struct socket_address *srvaddr;
602         struct dcerpc_connection *conn;
603 };
604
605
606 /*
607   Stage 2 of dcerpc_pipe_open_pipe_send: receive socket open request
608 */
609 void continue_np_open_socket(struct composite_context *ctx)
610 {
611         struct composite_context *c = talloc_get_type(ctx->async.private_data,
612                                                       struct composite_context);
613
614         c->status = dcerpc_pipe_open_socket_recv(ctx);
615         if (NT_STATUS_IS_OK(c->status)) {
616                 composite_done(c);
617                 return;
618         }
619         
620         composite_error(c, c->status);
621 }
622
623
624 /*
625   Send pipe open request on ncalrpc
626 */
627 struct composite_context* dcerpc_pipe_open_pipe_send(struct dcerpc_connection *conn,
628                                                      const char *identifier)
629 {
630         char *canon = NULL;
631
632         struct composite_context *c;
633         struct composite_context *sock_np_req;
634         struct pipe_np_state *s;
635
636         /* composite context allocation and setup */
637         c = talloc_zero(conn, struct composite_context);
638         if (c == NULL) return NULL;
639
640         s = talloc_zero(c, struct pipe_np_state);
641         if (s == NULL) {
642                 composite_error(c, NT_STATUS_NO_MEMORY);
643                 goto done;
644         }
645
646         c->state = COMPOSITE_STATE_IN_PROGRESS;
647         c->private_data = s;
648         c->event_ctx = conn->event_ctx;
649
650         /* store parameters in state structure */
651         canon = talloc_strdup(c, identifier);
652         s->conn = conn;
653
654         string_replace(canon, '/', '\\');
655         s->full_path = talloc_asprintf(canon, "%s/%s", lp_ncalrpc_dir(), canon);
656
657         /* prepare server address using path and transport name */
658         s->srvaddr = socket_address_from_strings(conn, "unix", s->full_path, 0);
659         if (s->srvaddr == NULL) {
660                 composite_error(c, NT_STATUS_NO_MEMORY);
661                 goto done;
662         }
663
664         /* send socket open request */
665         sock_np_req = dcerpc_pipe_open_socket_send(c, s->conn, s->srvaddr, NCALRPC);
666         if (sock_np_req == NULL) {
667                 composite_error(c, NT_STATUS_NO_MEMORY);
668                 goto done;
669         }
670
671         composite_continue(c, sock_np_req, continue_np_open_socket, c);
672
673 done:
674         talloc_free(canon);
675         return c;
676 }
677
678
679 /*
680   Receive result of pipe open request on ncalrpc
681 */
682 NTSTATUS dcerpc_pipe_open_pipe_recv(struct composite_context *c)
683 {
684         NTSTATUS status = composite_wait(c);
685         
686         talloc_free(c);
687         return status;
688 }
689
690
691 /*
692   Open a rpc pipe on a named pipe - sync version
693 */
694 NTSTATUS dcerpc_pipe_open_pipe(struct dcerpc_connection *conn, const char *identifier)
695 {
696         struct composite_context *c = dcerpc_pipe_open_pipe_send(conn, identifier);
697         return dcerpc_pipe_open_pipe_recv(c);
698 }