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