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