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