r25000: Fix some more C++ compatibility warnings.
[gd/samba-autobuild/.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 = (struct sock_private *)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 = (struct sock_private *)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 = (struct sock_private *)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 = (struct sock_private *)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 = (struct sock_private *)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 = (struct sock_private *)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 static 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 static 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 struct pipe_tcp_state {
349         const char *server;
350         const char *target_hostname;
351         const char *address;
352         uint32_t port;
353         struct socket_address *srvaddr;
354         struct dcerpc_connection *conn;
355 };
356
357
358 #if 0 /* disabled till we can resolve names to ipv6 addresses */
359 static void continue_ipv6_open_socket(struct composite_context *ctx);
360 #endif
361 static void continue_ipv4_open_socket(struct composite_context *ctx);
362 static void continue_ip_resolve_name(struct composite_context *ctx);
363
364 static void continue_ip_resolve_name(struct composite_context *ctx)
365 {
366         struct composite_context *c = talloc_get_type(ctx->async.private_data,
367                                                       struct composite_context);
368         struct pipe_tcp_state *s = talloc_get_type(c->private_data,
369                                                    struct pipe_tcp_state);
370         struct composite_context *sock_ipv4_req;
371
372         c->status = resolve_name_recv(ctx, s, &s->address);
373         if (!composite_is_ok(c)) return;
374
375         /* prepare server address using host ip:port and transport name */
376         s->srvaddr = socket_address_from_strings(s->conn, "ipv4", s->address, s->port);
377         if (composite_nomem(s->srvaddr, c)) return;
378
379         /* resolve_nbt_name gives only ipv4 ... - send socket open request */
380         sock_ipv4_req = dcerpc_pipe_open_socket_send(c, s->conn,
381                                                      s->srvaddr, s->target_hostname,
382                                                      NCACN_IP_TCP);
383         composite_continue(c, sock_ipv4_req, continue_ipv4_open_socket, c);
384 }
385
386 /*
387   Stage 2 of dcerpc_pipe_open_tcp_send: receive result of pipe open request
388   on IPv6 and send the request on IPv4 unless IPv6 transport succeeded.
389 */
390 #if 0 /* disabled till we can resolve names to ipv6 addresses */
391 static void continue_ipv6_open_socket(struct composite_context *ctx)
392 {
393         struct composite_context *c = talloc_get_type(ctx->async.private_data,
394                                                       struct composite_context);
395         struct pipe_tcp_state *s = talloc_get_type(c->private_data,
396                                                    struct pipe_tcp_state);
397         struct composite_context *sock_ipv4_req;
398
399         /* receive result of socket open request */
400         c->status = dcerpc_pipe_open_socket_recv(ctx);
401         if (NT_STATUS_IS_OK(c->status)) {
402                 composite_done(c);
403                 return;
404         }
405
406         talloc_free(s->srvaddr);
407
408         /* prepare server address using host:ip and transport name */
409         s->srvaddr = socket_address_from_strings(s->conn, "ipv4", s->address, s->port);
410         if (composite_nomem(s->srvaddr, c)) return;
411
412         /* try IPv4 if IPv6 fails */
413         sock_ipv4_req = dcerpc_pipe_open_socket_send(c, s->conn, 
414                                                      s->srvaddr, s->target_hostname, 
415                                                      NCACN_IP_TCP);
416         composite_continue(c, sock_ipv4_req, continue_ipv4_open_socket, c);
417 }
418 #endif
419
420 /*
421   Stage 2 of dcerpc_pipe_open_tcp_send: receive result of pipe open request
422   on IPv4 transport.
423 */
424 static void continue_ipv4_open_socket(struct composite_context *ctx)
425 {
426         struct composite_context *c = talloc_get_type(ctx->async.private_data,
427                                                       struct composite_context);
428         struct pipe_tcp_state *s = talloc_get_type(c->private_data,
429                                                    struct pipe_tcp_state);
430         
431         /* receive result socket open request */
432         c->status = dcerpc_pipe_open_socket_recv(ctx);
433         if (!NT_STATUS_IS_OK(c->status)) {
434                 /* something went wrong... */
435                 DEBUG(0, ("Failed to connect host %s (%s) on port %d - %s.\n",
436                           s->address, s->target_hostname, 
437                           s->port, nt_errstr(c->status)));
438
439                 composite_error(c, c->status);
440                 return;
441         }
442
443         composite_done(c);
444 }
445
446
447 /*
448   Send rpc pipe open request to given host:port using
449   tcp/ip transport
450 */
451 struct composite_context* dcerpc_pipe_open_tcp_send(struct dcerpc_connection *conn,
452                                                     const char *server,
453                                                     const char *target_hostname,
454                                                     uint32_t port)
455 {
456         struct composite_context *c;
457         struct pipe_tcp_state *s;
458         struct composite_context *resolve_req;
459         struct nbt_name name;
460
461         /* composite context allocation and setup */
462         c = composite_create(conn, conn->event_ctx);
463         if (c == NULL) return NULL;
464
465         s = talloc_zero(c, struct pipe_tcp_state);
466         if (composite_nomem(s, c)) return c;
467         c->private_data = s;
468
469         /* store input parameters in state structure */
470         s->server          = talloc_strdup(c, server);
471         if (composite_nomem(s->server, c)) return c;
472         if (target_hostname) {
473                 s->target_hostname = talloc_strdup(c, target_hostname);
474                 if (composite_nomem(s->target_hostname, c)) return c;
475         }
476         s->port            = port;
477         s->conn            = conn;
478
479         make_nbt_name_server(&name, server);
480         resolve_req = resolve_name_send(&name, c->event_ctx, lp_name_resolve_order());
481         composite_continue(c, resolve_req, continue_ip_resolve_name, c);
482         return c;
483 }
484
485 /*
486   Receive result of pipe open request on tcp/ip
487 */
488 NTSTATUS dcerpc_pipe_open_tcp_recv(struct composite_context *c)
489 {
490         NTSTATUS status;
491         status = composite_wait(c);
492
493         talloc_free(c);
494         return status;
495 }
496
497
498 struct pipe_unix_state {
499         const char *path;
500         struct socket_address *srvaddr;
501         struct dcerpc_connection *conn;
502 };
503
504
505 /*
506   Stage 2 of dcerpc_pipe_open_unix_stream_send: receive result of pipe open
507   request on unix socket.
508 */
509 static void continue_unix_open_socket(struct composite_context *ctx)
510 {
511         struct composite_context *c = talloc_get_type(ctx->async.private_data,
512                                                       struct composite_context);
513
514         c->status = dcerpc_pipe_open_socket_recv(ctx);
515         if (NT_STATUS_IS_OK(c->status)) {
516                 composite_done(c);
517                 return;
518         }
519
520         composite_error(c, c->status);
521 }
522
523
524 /*
525   Send pipe open request on unix socket
526 */
527 struct composite_context *dcerpc_pipe_open_unix_stream_send(struct dcerpc_connection *conn,
528                                                             const char *path)
529 {
530         struct composite_context *c;
531         struct composite_context *sock_unix_req;
532         struct pipe_unix_state *s;
533
534         /* composite context allocation and setup */
535         c = composite_create(conn, conn->event_ctx);
536         if (c == NULL) return NULL;
537
538         s = talloc_zero(c, struct pipe_unix_state);
539         if (composite_nomem(s, c)) return c;
540         c->private_data = s;
541
542         /* store parameters in state structure */
543         s->path = talloc_strdup(c, path);
544         if (composite_nomem(s->path, c)) return c;
545         s->conn = conn;
546
547         /* prepare server address using socket path and transport name */
548         s->srvaddr = socket_address_from_strings(conn, "unix", s->path, 0);
549         if (composite_nomem(s->srvaddr, c)) return c;
550
551         /* send socket open request */
552         sock_unix_req = dcerpc_pipe_open_socket_send(c, s->conn, 
553                                                      s->srvaddr, NULL,
554                                                      NCALRPC);
555         composite_continue(c, sock_unix_req, continue_unix_open_socket, c);
556         return c;
557 }
558
559
560 /*
561   Receive result of pipe open request on unix socket
562 */
563 NTSTATUS dcerpc_pipe_open_unix_stream_recv(struct composite_context *c)
564 {
565         NTSTATUS status = composite_wait(c);
566
567         talloc_free(c);
568         return status;
569 }
570
571
572 struct pipe_np_state {
573         char *full_path;
574         struct socket_address *srvaddr;
575         struct dcerpc_connection *conn;
576 };
577
578
579 /*
580   Stage 2 of dcerpc_pipe_open_pipe_send: receive socket open request
581 */
582 static void continue_np_open_socket(struct composite_context *ctx)
583 {
584         struct composite_context *c = talloc_get_type(ctx->async.private_data,
585                                                       struct composite_context);
586
587         c->status = dcerpc_pipe_open_socket_recv(ctx);
588         if (!composite_is_ok(c)) return;
589
590         composite_done(c);
591 }
592
593
594 /*
595   Send pipe open request on ncalrpc
596 */
597 struct composite_context* dcerpc_pipe_open_pipe_send(struct dcerpc_connection *conn,
598                                                      const char *identifier)
599 {
600         char *canon = NULL;
601
602         struct composite_context *c;
603         struct composite_context *sock_np_req;
604         struct pipe_np_state *s;
605
606         /* composite context allocation and setup */
607         c = composite_create(conn, conn->event_ctx);
608         if (c == NULL) return NULL;
609
610         s = talloc_zero(c, struct pipe_np_state);
611         if (composite_nomem(s, c)) return c;
612         c->private_data = s;
613
614         /* store parameters in state structure */
615         canon = talloc_strdup(s, identifier);
616         if (composite_nomem(canon, c)) return c;
617         s->conn = conn;
618
619         string_replace(canon, '/', '\\');
620         s->full_path = talloc_asprintf(canon, "%s/%s", lp_ncalrpc_dir(), canon);
621         if (composite_nomem(s->full_path, c)) return c;
622
623         /* prepare server address using path and transport name */
624         s->srvaddr = socket_address_from_strings(conn, "unix", s->full_path, 0);
625         if (composite_nomem(s->srvaddr, c)) return c;
626
627         /* send socket open request */
628         sock_np_req = dcerpc_pipe_open_socket_send(c, s->conn, s->srvaddr, NULL, NCALRPC);
629         composite_continue(c, sock_np_req, continue_np_open_socket, c);
630         return c;
631 }
632
633
634 /*
635   Receive result of pipe open request on ncalrpc
636 */
637 NTSTATUS dcerpc_pipe_open_pipe_recv(struct composite_context *c)
638 {
639         NTSTATUS status = composite_wait(c);
640         
641         talloc_free(c);
642         return status;
643 }
644
645
646 /*
647   Open a rpc pipe on a named pipe - sync version
648 */
649 NTSTATUS dcerpc_pipe_open_pipe(struct dcerpc_connection *conn, const char *identifier)
650 {
651         struct composite_context *c = dcerpc_pipe_open_pipe_send(conn, identifier);
652         return dcerpc_pipe_open_pipe_recv(c);
653 }