r14542: Remove librpc, libndr and libnbt from includes.h
[gd/samba-autobuild/.git] / source4 / 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 #include "librpc/rpc/dcerpc.h"
31
32 /* transport private information used by general socket pipe transports */
33 struct sock_private {
34         struct fd_event *fde;
35         struct socket_context *sock;
36         char *server_name;
37
38         struct packet_context *packet;
39         uint32_t pending_reads;
40 };
41
42
43 /*
44   mark the socket dead
45 */
46 static void sock_dead(struct dcerpc_connection *p, NTSTATUS status)
47 {
48         struct sock_private *sock = p->transport.private;
49
50         if (sock && sock->sock != NULL) {
51                 talloc_free(sock->fde);
52                 talloc_free(sock->sock);
53                 sock->sock = NULL;
54         }
55
56         if (!NT_STATUS_IS_OK(status)) {
57                 p->transport.recv_data(p, NULL, status);
58         }
59 }
60
61
62 /*
63   handle socket recv errors
64 */
65 static void sock_error_handler(void *private, NTSTATUS status)
66 {
67         struct dcerpc_connection *p = talloc_get_type(private, 
68                                                       struct dcerpc_connection);
69         sock_dead(p, status);
70 }
71
72 /*
73   check if a blob is a complete packet
74 */
75 static NTSTATUS sock_complete_packet(void *private, DATA_BLOB blob, size_t *size)
76 {
77         if (blob.length < DCERPC_FRAG_LEN_OFFSET+2) {
78                 return STATUS_MORE_ENTRIES;
79         }
80         *size = dcerpc_get_frag_length(&blob);
81         if (*size > blob.length) {
82                 return STATUS_MORE_ENTRIES;
83         }
84         return NT_STATUS_OK;
85 }
86
87 /*
88   process recv requests
89 */
90 static NTSTATUS sock_process_recv(void *private, DATA_BLOB blob)
91 {
92         struct dcerpc_connection *p = talloc_get_type(private, 
93                                                       struct dcerpc_connection);
94         struct sock_private *sock = p->transport.private;
95         sock->pending_reads--;
96         if (sock->pending_reads == 0) {
97                 packet_recv_disable(sock->packet);
98         }
99         p->transport.recv_data(p, &blob, NT_STATUS_OK);
100         return NT_STATUS_OK;
101 }
102
103 /*
104   called when a IO is triggered by the events system
105 */
106 static void sock_io_handler(struct event_context *ev, struct fd_event *fde, 
107                             uint16_t flags, void *private)
108 {
109         struct dcerpc_connection *p = talloc_get_type(private, 
110                                                       struct dcerpc_connection);
111         struct sock_private *sock = p->transport.private;
112
113         if (flags & EVENT_FD_WRITE) {
114                 packet_queue_run(sock->packet);
115                 return;
116         }
117
118         if (sock->sock == NULL) {
119                 return;
120         }
121
122         if (flags & EVENT_FD_READ) {
123                 packet_recv(sock->packet);
124         }
125 }
126
127 /* 
128    initiate a read request - not needed for dcerpc sockets
129 */
130 static NTSTATUS sock_send_read(struct dcerpc_connection *p)
131 {
132         struct sock_private *sock = p->transport.private;
133         sock->pending_reads++;
134         if (sock->pending_reads == 1) {
135                 packet_recv_enable(sock->packet);
136         }
137         return NT_STATUS_OK;
138 }
139
140 /* 
141    send an initial pdu in a multi-pdu sequence
142 */
143 static NTSTATUS sock_send_request(struct dcerpc_connection *p, DATA_BLOB *data, 
144                                   BOOL trigger_read)
145 {
146         struct sock_private *sock = p->transport.private;
147         DATA_BLOB blob;
148         NTSTATUS status;
149
150         if (sock->sock == NULL) {
151                 return NT_STATUS_CONNECTION_DISCONNECTED;
152         }
153
154         blob = data_blob_talloc(sock->packet, data->data, data->length);
155         if (blob.data == NULL) {
156                 return NT_STATUS_NO_MEMORY;
157         }
158
159         status = packet_send(sock->packet, blob);
160         if (!NT_STATUS_IS_OK(status)) {
161                 return status;
162         }
163
164         if (trigger_read) {
165                 sock_send_read(p);
166         }
167
168         return NT_STATUS_OK;
169 }
170
171 /* 
172    shutdown sock pipe connection
173 */
174 static NTSTATUS sock_shutdown_pipe(struct dcerpc_connection *p)
175 {
176         struct sock_private *sock = p->transport.private;
177
178         if (sock && sock->sock) {
179                 sock_dead(p, NT_STATUS_OK);
180         }
181
182         return NT_STATUS_OK;
183 }
184
185 /*
186   return sock server name
187 */
188 static const char *sock_peer_name(struct dcerpc_connection *p)
189 {
190         struct sock_private *sock = p->transport.private;
191         return sock->server_name;
192 }
193
194
195 struct pipe_open_socket_state {
196         struct dcerpc_connection *conn;
197         struct socket_context *socket_ctx;
198         struct sock_private *sock;
199         struct socket_address *server;
200         enum dcerpc_transport_t transport;
201 };
202
203
204 static void continue_socket_connect(struct composite_context *ctx)
205 {
206         struct dcerpc_connection *conn;
207         struct sock_private *sock;
208         struct composite_context *c = talloc_get_type(ctx->async.private_data,
209                                                       struct composite_context);
210         struct pipe_open_socket_state *s = talloc_get_type(c->private_data,
211                                                            struct pipe_open_socket_state);
212
213         /* make it easier to write a function calls */
214         conn = s->conn;
215         sock = s->sock;
216
217         c->status = socket_connect_recv(ctx);
218         if (!NT_STATUS_IS_OK(c->status)) {
219                 DEBUG(0, ("Failed to connect host %s on port %d - %s\n", 
220                           s->server->addr, s->server->port,
221                           nt_errstr(c->status)));
222                 composite_error(c, c->status);
223                 return;
224         }
225
226         /*
227           fill in the transport methods
228         */
229         conn->transport.transport     = s->transport;
230         conn->transport.private       = NULL;
231
232         conn->transport.send_request  = sock_send_request;
233         conn->transport.send_read     = sock_send_read;
234         conn->transport.recv_data     = NULL;
235
236         conn->transport.shutdown_pipe = sock_shutdown_pipe;
237         conn->transport.peer_name     = sock_peer_name;
238
239         sock->sock          = s->socket_ctx;
240         sock->pending_reads = 0;
241         sock->server_name   = strupper_talloc(sock, s->server->addr);
242
243         sock->fde = event_add_fd(conn->event_ctx, sock->sock, socket_get_fd(sock->sock),
244                                  0, sock_io_handler, conn);
245         
246         conn->transport.private = sock;
247
248         sock->packet = packet_init(sock);
249         if (sock->packet == NULL) {
250                 composite_error(c, NT_STATUS_NO_MEMORY);
251                 talloc_free(sock);
252                 return;
253         }
254
255         packet_set_private(sock->packet, conn);
256         packet_set_socket(sock->packet, sock->sock);
257         packet_set_callback(sock->packet, sock_process_recv);
258         packet_set_full_request(sock->packet, sock_complete_packet);
259         packet_set_error_handler(sock->packet, sock_error_handler);
260         packet_set_event_context(sock->packet, conn->event_ctx);
261         packet_set_fde(sock->packet, sock->fde);
262         packet_set_serialise(sock->packet);
263         packet_recv_disable(sock->packet);
264         packet_set_initial_read(sock->packet, 16);
265
266         /* ensure we don't get SIGPIPE */
267         BlockSignals(True,SIGPIPE);
268
269         composite_done(c);
270 }
271
272
273 struct composite_context *dcerpc_pipe_open_socket_send(TALLOC_CTX *mem_ctx,
274                                                        struct dcerpc_connection *cn,
275                                                        struct socket_address *server,
276                                                        enum dcerpc_transport_t transport)
277 {
278         NTSTATUS status;
279         struct composite_context *c;
280         struct pipe_open_socket_state *s;
281         struct composite_context *conn_req;
282
283         c = talloc_zero(mem_ctx, struct composite_context);
284         if (c == NULL) return NULL;
285
286         s = talloc_zero(c, struct pipe_open_socket_state);
287         if (s == NULL) {
288                 composite_error(c, NT_STATUS_NO_MEMORY);
289                 goto done;
290         }
291
292         c->state = COMPOSITE_STATE_IN_PROGRESS;
293         c->private_data = s;
294         c->event_ctx = cn->event_ctx;
295
296         s->conn      = cn;
297         s->transport = transport;
298         s->server    = talloc_reference(c, server);
299         if (s->server == NULL) {
300                 composite_error(c, NT_STATUS_NO_MEMORY);
301                 goto done;
302         }
303
304         s->sock = talloc(cn, struct sock_private);
305         if (s->sock == NULL) {
306                 composite_error(c, NT_STATUS_NO_MEMORY);
307                 goto done;
308         }
309
310         status = socket_create(server->family, SOCKET_TYPE_STREAM, &s->socket_ctx, 0);
311         if (!NT_STATUS_IS_OK(status)) {
312                 composite_error(c, status);
313                 talloc_free(s->sock);
314                 goto done;
315         }
316         talloc_steal(s->sock, s->socket_ctx);
317
318         conn_req = socket_connect_send(s->socket_ctx, NULL, s->server, 0, c->event_ctx);
319         if (conn_req == NULL) {
320                 composite_error(c, NT_STATUS_NO_MEMORY);
321                 goto done;
322         }
323         
324         composite_continue(c, conn_req, continue_socket_connect, c);
325
326 done:
327         return c;
328 }
329
330
331 NTSTATUS dcerpc_pipe_open_socket_recv(struct composite_context *c)
332 {
333         NTSTATUS status = composite_wait(c);
334
335         talloc_free(c);
336         return status;
337 }
338
339 /* 
340    open a rpc connection using the generic socket library
341 */
342 NTSTATUS dcerpc_pipe_open_socket(struct dcerpc_connection *conn,
343                                  struct socket_address *server,
344                                  enum dcerpc_transport_t transport)
345 {
346         struct composite_context *c;
347         
348         c = dcerpc_pipe_open_socket_send(conn, conn, server, transport);
349         return dcerpc_pipe_open_socket_recv(c);
350 }
351
352
353 struct pipe_tcp_state {
354         const char *server;
355         uint32_t port;
356         struct socket_address *srvaddr;
357         struct dcerpc_connection *conn;
358 };
359
360
361 void continue_ipv6_open_socket(struct composite_context *ctx);
362 void continue_ipv4_open_socket(struct composite_context *ctx);
363
364
365 /*
366   Stage 2 of dcerpc_pipe_open_tcp_send: receive result of pipe open request
367   on IPv6 and send the request on IPv4 unless IPv6 transport succeeded.
368 */
369 void continue_ipv6_open_socket(struct composite_context *ctx)
370 {
371         struct composite_context *c = talloc_get_type(ctx->async.private_data,
372                                                       struct composite_context);
373         struct pipe_tcp_state *s = talloc_get_type(c->private_data,
374                                                    struct pipe_tcp_state);
375         struct composite_context *sock_ipv4_req;
376
377         /* receive result of socket open request */
378         c->status = dcerpc_pipe_open_socket_recv(ctx);
379         if (NT_STATUS_IS_OK(c->status)) return;
380
381         talloc_free(s->srvaddr);
382
383         /* prepare server address using host:ip and transport name */
384         s->srvaddr = socket_address_from_strings(s->conn, "ipv4", s->server, s->port);
385         if (!s->srvaddr) {
386                 composite_error(c, NT_STATUS_NO_MEMORY);
387                 return;
388         }
389         
390         /* try IPv4 if IPv6 fails */
391         sock_ipv4_req = dcerpc_pipe_open_socket_send(c, s->conn, s->srvaddr, NCACN_IP_TCP);
392         if (sock_ipv4_req == NULL) {
393                 composite_error(c, NT_STATUS_NO_MEMORY);
394                 return;
395         }
396
397         composite_continue(c, sock_ipv4_req, continue_ipv4_open_socket, c);
398 }
399
400
401 /*
402   Stage 2 of dcerpc_pipe_open_tcp_send: receive result of pipe open request
403   on IPv4 transport.
404 */
405 void continue_ipv4_open_socket(struct composite_context *ctx)
406 {
407         struct composite_context *c = talloc_get_type(ctx->async.private_data,
408                                                       struct composite_context);
409         struct pipe_tcp_state *s = talloc_get_type(c->private_data,
410                                                    struct pipe_tcp_state);
411         
412         /* receive result socket open request */
413         c->status = dcerpc_pipe_open_socket_recv(ctx);
414         if (NT_STATUS_IS_OK(c->status)) {
415                 composite_done(c);
416                 return;
417         }
418
419         /* something went wrong... */
420         DEBUG(0, ("Failed to connect host %s on port %d - %s.\n",
421                   s->server, s->port, nt_errstr(c->status)));
422
423         composite_error(c, c->status);
424 }
425
426
427 /*
428   Send rpc pipe open request to given host:port using
429   tcp/ip transport
430 */
431 struct composite_context* dcerpc_pipe_open_tcp_send(struct dcerpc_connection *conn,
432                                                     const char* server, uint32_t port)
433 {
434         struct composite_context *c;
435         struct composite_context *sock_ipv6_req;
436         struct pipe_tcp_state *s;
437
438         /* composite context allocation and setup */
439         c = talloc_zero(conn, struct composite_context);
440         if (c == NULL) return NULL;
441
442         s = talloc_zero(c, struct pipe_tcp_state);
443         if (s == NULL) {
444                 composite_error(c, NT_STATUS_NO_MEMORY);
445                 goto done;
446         }
447         
448         c->state = COMPOSITE_STATE_IN_PROGRESS;
449         c->private_data = s;
450         c->event_ctx = conn->event_ctx;
451
452         /* store input parameters in state structure */
453         s->server = talloc_strdup(c, server);
454         s->port   = port;
455         s->conn   = conn;
456         
457         /* prepare server address using host ip:port and transport name */
458         s->srvaddr = socket_address_from_strings(s->conn, "ipv6", s->server, s->port);
459         if (!s->srvaddr) {
460                 composite_error(c, NT_STATUS_NO_MEMORY);
461                 goto done;
462         }
463
464         /* try IPv6 first - send socket open request */
465         sock_ipv6_req = dcerpc_pipe_open_socket_send(c, s->conn, s->srvaddr, NCACN_IP_TCP);
466         if (sock_ipv6_req == NULL) {
467                 composite_error(c, NT_STATUS_NO_MEMORY);
468                 goto done;
469         }
470
471         composite_continue(c, sock_ipv6_req, continue_ipv6_open_socket, c);
472 done:
473         return c;
474 }
475
476
477 /*
478   Receive result of pipe open request on tcp/ip
479 */
480 NTSTATUS dcerpc_pipe_open_tcp_recv(struct composite_context *c)
481 {
482         NTSTATUS status;
483         status = composite_wait(c);
484
485         talloc_free(c);
486         return status;
487 }
488
489
490 /*
491   Open rpc pipe on tcp/ip transport - sync version
492 */
493 NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_connection *conn, const char *server,
494                               uint32_t port)
495 {
496         struct composite_context *c;
497
498         c = dcerpc_pipe_open_tcp_send(conn, server, port);
499         return dcerpc_pipe_open_tcp_recv(c);
500 }
501
502
503 struct pipe_unix_state {
504         const char *path;
505         struct socket_address *srvaddr;
506         struct dcerpc_connection *conn;
507 };
508
509
510 /*
511   Stage 2 of dcerpc_pipe_open_unix_stream_send: receive result of pipe open
512   request on unix socket.
513 */
514 void continue_unix_open_socket(struct composite_context *ctx)
515 {
516         struct composite_context *c = talloc_get_type(ctx->async.private_data,
517                                                       struct composite_context);
518
519         c->status = dcerpc_pipe_open_socket_recv(ctx);
520         if (NT_STATUS_IS_OK(c->status)) {
521                 composite_done(c);
522                 return;
523         }
524
525         composite_error(c, c->status);
526 }
527
528
529 /*
530   Send pipe open request on unix socket
531 */
532 struct composite_context *dcerpc_pipe_open_unix_stream_send(struct dcerpc_connection *conn,
533                                                             const char *path)
534 {
535         struct composite_context *c;
536         struct composite_context *sock_unix_req;
537         struct pipe_unix_state *s;
538
539         /* composite context allocation and setup */
540         c = talloc_zero(conn, struct composite_context);
541         if (c == NULL) return NULL;
542
543         s = talloc_zero(c, struct pipe_unix_state);
544         if (s == NULL) {
545                 composite_error(c, NT_STATUS_NO_MEMORY);
546                 goto done;
547         }
548         
549         c->state = COMPOSITE_STATE_IN_PROGRESS;
550         c->private_data = s;
551         c->event_ctx = conn->event_ctx;
552
553         /* store parameters in state structure */
554         s->path = talloc_strdup(c, path);
555         s->conn = conn;
556
557         /* prepare server address using socket path and transport name */
558         s->srvaddr = socket_address_from_strings(conn, "unix", s->path, 0);
559         if (s->srvaddr == NULL) {
560                 composite_error(c, NT_STATUS_NO_MEMORY);
561                 goto done;
562         }
563
564         /* send socket open request */
565         sock_unix_req = dcerpc_pipe_open_socket_send(c, s->conn, s->srvaddr, NCALRPC);
566         if (sock_unix_req == NULL) {
567                 composite_error(c, NT_STATUS_NO_MEMORY);
568                 goto done;
569         }
570
571         composite_continue(c, sock_unix_req, continue_unix_open_socket, c);
572
573 done:
574         return c;
575 }
576
577
578 /*
579   Receive result of pipe open request on unix socket
580 */
581 NTSTATUS dcerpc_pipe_open_unix_stream_recv(struct composite_context *c)
582 {
583         NTSTATUS status = composite_wait(c);
584
585         talloc_free(c);
586         return status;
587 }
588
589
590 /*
591   Open a rpc pipe on a unix socket - sync version
592 */
593 NTSTATUS dcerpc_pipe_open_unix_stream(struct dcerpc_connection *conn, const char *path)
594 {
595         struct composite_context *c = dcerpc_pipe_open_unix_stream_send(conn, path);
596         return dcerpc_pipe_open_unix_stream_recv(c);
597 }
598
599
600 struct pipe_np_state {
601         char *full_path;
602         struct socket_address *srvaddr;
603         struct dcerpc_connection *conn;
604 };
605
606
607 /*
608   Stage 2 of dcerpc_pipe_open_pipe_send: receive socket open request
609 */
610 void continue_np_open_socket(struct composite_context *ctx)
611 {
612         struct composite_context *c = talloc_get_type(ctx->async.private_data,
613                                                       struct composite_context);
614
615         c->status = dcerpc_pipe_open_socket_recv(ctx);
616         if (NT_STATUS_IS_OK(c->status)) {
617                 composite_done(c);
618                 return;
619         }
620         
621         composite_error(c, c->status);
622 }
623
624
625 /*
626   Send pipe open request on ncalrpc
627 */
628 struct composite_context* dcerpc_pipe_open_pipe_send(struct dcerpc_connection *conn,
629                                                      const char *identifier)
630 {
631         char *canon = NULL;
632
633         struct composite_context *c;
634         struct composite_context *sock_np_req;
635         struct pipe_np_state *s;
636
637         /* composite context allocation and setup */
638         c = talloc_zero(conn, struct composite_context);
639         if (c == NULL) return NULL;
640
641         s = talloc_zero(c, struct pipe_np_state);
642         if (s == NULL) {
643                 composite_error(c, NT_STATUS_NO_MEMORY);
644                 goto done;
645         }
646
647         c->state = COMPOSITE_STATE_IN_PROGRESS;
648         c->private_data = s;
649         c->event_ctx = conn->event_ctx;
650
651         /* store parameters in state structure */
652         canon = talloc_strdup(c, identifier);
653         s->conn = conn;
654
655         string_replace(canon, '/', '\\');
656         s->full_path = talloc_asprintf(canon, "%s/%s", lp_ncalrpc_dir(), canon);
657
658         /* prepare server address using path and transport name */
659         s->srvaddr = socket_address_from_strings(conn, "unix", s->full_path, 0);
660         if (s->srvaddr == NULL) {
661                 composite_error(c, NT_STATUS_NO_MEMORY);
662                 goto done;
663         }
664
665         /* send socket open request */
666         sock_np_req = dcerpc_pipe_open_socket_send(c, s->conn, s->srvaddr, NCALRPC);
667         if (sock_np_req == NULL) {
668                 composite_error(c, NT_STATUS_NO_MEMORY);
669                 goto done;
670         }
671
672         composite_continue(c, sock_np_req, continue_np_open_socket, c);
673
674 done:
675         talloc_free(canon);
676         return c;
677 }
678
679
680 /*
681   Receive result of pipe open request on ncalrpc
682 */
683 NTSTATUS dcerpc_pipe_open_pipe_recv(struct composite_context *c)
684 {
685         NTSTATUS status = composite_wait(c);
686         
687         talloc_free(c);
688         return status;
689 }
690
691
692 /*
693   Open a rpc pipe on a named pipe - sync version
694 */
695 NTSTATUS dcerpc_pipe_open_pipe(struct dcerpc_connection *conn, const char *identifier)
696 {
697         struct composite_context *c = dcerpc_pipe_open_pipe_send(conn, identifier);
698         return dcerpc_pipe_open_pipe_recv(c);
699 }