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