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