Add context for libcli_resolve.
[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 3 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, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "lib/events/events.h"
26 #include "lib/socket/socket.h"
27 #include "lib/stream/packet.h"
28 #include "libcli/composite/composite.h"
29 #include "librpc/rpc/dcerpc.h"
30 #include "libcli/resolve/resolve.h"
31 #include "param/param.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 = (struct sock_private *)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 = (struct sock_private *)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 = (struct sock_private *)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 = (struct sock_private *)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 = (struct sock_private *)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 = (struct sock_private *)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 static 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, 
336                                        lp_resolve_context(global_loadparm), 
337                                        c->event_ctx);
338         composite_continue(c, conn_req, continue_socket_connect, c);
339         return c;
340 }
341
342
343 static NTSTATUS dcerpc_pipe_open_socket_recv(struct composite_context *c)
344 {
345         NTSTATUS status = composite_wait(c);
346
347         talloc_free(c);
348         return status;
349 }
350
351 struct pipe_tcp_state {
352         const char *server;
353         const char *target_hostname;
354         const char *address;
355         uint32_t port;
356         struct socket_address *srvaddr;
357         struct dcerpc_connection *conn;
358 };
359
360
361 #if 0 /* disabled till we can resolve names to ipv6 addresses */
362 static void continue_ipv6_open_socket(struct composite_context *ctx);
363 #endif
364 static void continue_ipv4_open_socket(struct composite_context *ctx);
365 static void continue_ip_resolve_name(struct composite_context *ctx);
366
367 static void continue_ip_resolve_name(struct composite_context *ctx)
368 {
369         struct composite_context *c = talloc_get_type(ctx->async.private_data,
370                                                       struct composite_context);
371         struct pipe_tcp_state *s = talloc_get_type(c->private_data,
372                                                    struct pipe_tcp_state);
373         struct composite_context *sock_ipv4_req;
374
375         c->status = resolve_name_recv(ctx, s, &s->address);
376         if (!composite_is_ok(c)) return;
377
378         /* prepare server address using host ip:port and transport name */
379         s->srvaddr = socket_address_from_strings(s->conn, "ipv4", s->address, s->port);
380         if (composite_nomem(s->srvaddr, c)) return;
381
382         /* resolve_nbt_name gives only ipv4 ... - send socket open request */
383         sock_ipv4_req = dcerpc_pipe_open_socket_send(c, s->conn,
384                                                      s->srvaddr, s->target_hostname,
385                                                      NCACN_IP_TCP);
386         composite_continue(c, sock_ipv4_req, continue_ipv4_open_socket, c);
387 }
388
389 /*
390   Stage 2 of dcerpc_pipe_open_tcp_send: receive result of pipe open request
391   on IPv6 and send the request on IPv4 unless IPv6 transport succeeded.
392 */
393 #if 0 /* disabled till we can resolve names to ipv6 addresses */
394 static void continue_ipv6_open_socket(struct composite_context *ctx)
395 {
396         struct composite_context *c = talloc_get_type(ctx->async.private_data,
397                                                       struct composite_context);
398         struct pipe_tcp_state *s = talloc_get_type(c->private_data,
399                                                    struct pipe_tcp_state);
400         struct composite_context *sock_ipv4_req;
401
402         /* receive result of socket open request */
403         c->status = dcerpc_pipe_open_socket_recv(ctx);
404         if (NT_STATUS_IS_OK(c->status)) {
405                 composite_done(c);
406                 return;
407         }
408
409         talloc_free(s->srvaddr);
410
411         /* prepare server address using host:ip and transport name */
412         s->srvaddr = socket_address_from_strings(s->conn, "ipv4", s->address, s->port);
413         if (composite_nomem(s->srvaddr, c)) return;
414
415         /* try IPv4 if IPv6 fails */
416         sock_ipv4_req = dcerpc_pipe_open_socket_send(c, s->conn, 
417                                                      s->srvaddr, s->target_hostname, 
418                                                      NCACN_IP_TCP);
419         composite_continue(c, sock_ipv4_req, continue_ipv4_open_socket, c);
420 }
421 #endif
422
423 /*
424   Stage 2 of dcerpc_pipe_open_tcp_send: receive result of pipe open request
425   on IPv4 transport.
426 */
427 static void continue_ipv4_open_socket(struct composite_context *ctx)
428 {
429         struct composite_context *c = talloc_get_type(ctx->async.private_data,
430                                                       struct composite_context);
431         struct pipe_tcp_state *s = talloc_get_type(c->private_data,
432                                                    struct pipe_tcp_state);
433         
434         /* receive result socket open request */
435         c->status = dcerpc_pipe_open_socket_recv(ctx);
436         if (!NT_STATUS_IS_OK(c->status)) {
437                 /* something went wrong... */
438                 DEBUG(0, ("Failed to connect host %s (%s) on port %d - %s.\n",
439                           s->address, s->target_hostname, 
440                           s->port, nt_errstr(c->status)));
441
442                 composite_error(c, c->status);
443                 return;
444         }
445
446         composite_done(c);
447 }
448
449
450 /*
451   Send rpc pipe open request to given host:port using
452   tcp/ip transport
453 */
454 struct composite_context* dcerpc_pipe_open_tcp_send(struct dcerpc_connection *conn,
455                                                     const char *server,
456                                                     const char *target_hostname,
457                                                     uint32_t port,
458                                                     struct resolve_context *resolve_ctx)
459 {
460         struct composite_context *c;
461         struct pipe_tcp_state *s;
462         struct composite_context *resolve_req;
463         struct nbt_name name;
464
465         /* composite context allocation and setup */
466         c = composite_create(conn, conn->event_ctx);
467         if (c == NULL) return NULL;
468
469         s = talloc_zero(c, struct pipe_tcp_state);
470         if (composite_nomem(s, c)) return c;
471         c->private_data = s;
472
473         /* store input parameters in state structure */
474         s->server          = talloc_strdup(c, server);
475         if (composite_nomem(s->server, c)) return c;
476         if (target_hostname) {
477                 s->target_hostname = talloc_strdup(c, target_hostname);
478                 if (composite_nomem(s->target_hostname, c)) return c;
479         }
480         s->port            = port;
481         s->conn            = conn;
482
483         make_nbt_name_server(&name, server);
484         resolve_req = resolve_name_send(resolve_ctx, &name, c->event_ctx);
485         composite_continue(c, resolve_req, continue_ip_resolve_name, c);
486         return c;
487 }
488
489 /*
490   Receive result of pipe open request on tcp/ip
491 */
492 NTSTATUS dcerpc_pipe_open_tcp_recv(struct composite_context *c)
493 {
494         NTSTATUS status;
495         status = composite_wait(c);
496
497         talloc_free(c);
498         return status;
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 static 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 = composite_create(conn, conn->event_ctx);
540         if (c == NULL) return NULL;
541
542         s = talloc_zero(c, struct pipe_unix_state);
543         if (composite_nomem(s, c)) return c;
544         c->private_data = s;
545
546         /* store parameters in state structure */
547         s->path = talloc_strdup(c, path);
548         if (composite_nomem(s->path, c)) return c;
549         s->conn = conn;
550
551         /* prepare server address using socket path and transport name */
552         s->srvaddr = socket_address_from_strings(conn, "unix", s->path, 0);
553         if (composite_nomem(s->srvaddr, c)) return c;
554
555         /* send socket open request */
556         sock_unix_req = dcerpc_pipe_open_socket_send(c, s->conn, 
557                                                      s->srvaddr, NULL,
558                                                      NCALRPC);
559         composite_continue(c, sock_unix_req, continue_unix_open_socket, c);
560         return c;
561 }
562
563
564 /*
565   Receive result of pipe open request on unix socket
566 */
567 NTSTATUS dcerpc_pipe_open_unix_stream_recv(struct composite_context *c)
568 {
569         NTSTATUS status = composite_wait(c);
570
571         talloc_free(c);
572         return status;
573 }
574
575
576 struct pipe_np_state {
577         char *full_path;
578         struct socket_address *srvaddr;
579         struct dcerpc_connection *conn;
580 };
581
582
583 /*
584   Stage 2 of dcerpc_pipe_open_pipe_send: receive socket open request
585 */
586 static void continue_np_open_socket(struct composite_context *ctx)
587 {
588         struct composite_context *c = talloc_get_type(ctx->async.private_data,
589                                                       struct composite_context);
590
591         c->status = dcerpc_pipe_open_socket_recv(ctx);
592         if (!composite_is_ok(c)) return;
593
594         composite_done(c);
595 }
596
597
598 /*
599   Send pipe open request on ncalrpc
600 */
601 struct composite_context* dcerpc_pipe_open_pipe_send(struct dcerpc_connection *conn,
602                                                      const char *ncalrpc_dir,
603                                                      const char *identifier)
604 {
605         char *canon = NULL;
606
607         struct composite_context *c;
608         struct composite_context *sock_np_req;
609         struct pipe_np_state *s;
610
611         /* composite context allocation and setup */
612         c = composite_create(conn, conn->event_ctx);
613         if (c == NULL) return NULL;
614
615         s = talloc_zero(c, struct pipe_np_state);
616         if (composite_nomem(s, c)) return c;
617         c->private_data = s;
618
619         /* store parameters in state structure */
620         canon = talloc_strdup(s, identifier);
621         if (composite_nomem(canon, c)) return c;
622         s->conn = conn;
623
624         string_replace(canon, '/', '\\');
625         s->full_path = talloc_asprintf(canon, "%s/%s", ncalrpc_dir, canon);
626         if (composite_nomem(s->full_path, c)) return c;
627
628         /* prepare server address using path and transport name */
629         s->srvaddr = socket_address_from_strings(conn, "unix", s->full_path, 0);
630         if (composite_nomem(s->srvaddr, c)) return c;
631
632         /* send socket open request */
633         sock_np_req = dcerpc_pipe_open_socket_send(c, s->conn, s->srvaddr, NULL, NCALRPC);
634         composite_continue(c, sock_np_req, continue_np_open_socket, c);
635         return c;
636 }
637
638
639 /*
640   Receive result of pipe open request on ncalrpc
641 */
642 NTSTATUS dcerpc_pipe_open_pipe_recv(struct composite_context *c)
643 {
644         NTSTATUS status = composite_wait(c);
645         
646         talloc_free(c);
647         return status;
648 }
649
650
651 /*
652   Open a rpc pipe on a named pipe - sync version
653 */
654 NTSTATUS dcerpc_pipe_open_pipe(struct dcerpc_connection *conn, const char *ncalrpc_dir, const char *identifier)
655 {
656         struct composite_context *c = dcerpc_pipe_open_pipe_send(conn, ncalrpc_dir, identifier);
657         return dcerpc_pipe_open_pipe_recv(c);
658 }