s4:librpc: pass smbXcli_{conn,session,tcon} to dcerpc_pipe_open_smb_send()
[samba.git] / source4 / librpc / rpc / dcerpc_smb.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    dcerpc over SMB transport
5
6    Copyright (C) Tim Potter 2003
7    Copyright (C) Andrew Tridgell 2003
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "system/filesys.h"
25 #include <tevent.h>
26 #include "lib/tsocket/tsocket.h"
27 #include "libcli/smb/smb_constants.h"
28 #include "libcli/smb/smbXcli_base.h"
29 #include "libcli/smb/tstream_smbXcli_np.h"
30 #include "libcli/raw/libcliraw.h"
31 #include "librpc/rpc/dcerpc.h"
32 #include "librpc/rpc/dcerpc_proto.h"
33 #include "libcli/composite/composite.h"
34
35 /* transport private information used by SMB pipe transport */
36 struct smb_private {
37         DATA_BLOB session_key;
38         const char *server_name;
39
40         struct tstream_context *stream;
41         struct tevent_queue *write_queue;
42         struct tevent_req *read_subreq;
43         uint32_t pending_reads;
44
45         /*
46          * these are needed to open a secondary connection
47          */
48         struct smbXcli_conn *conn;
49         struct smbXcli_session *session;
50         struct smbXcli_tcon *tcon;
51         uint32_t timeout_msec;
52 };
53
54
55 /*
56   tell the dcerpc layer that the transport is dead
57 */
58 static void pipe_dead(struct dcecli_connection *c, NTSTATUS status)
59 {
60         struct smb_private *smb = talloc_get_type_abort(
61                 c->transport.private_data, struct smb_private);
62
63         if (smb->stream == NULL) {
64                 return;
65         }
66
67         tevent_queue_stop(smb->write_queue);
68         TALLOC_FREE(smb->read_subreq);
69         TALLOC_FREE(smb->stream);
70
71         if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
72                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
73         }
74
75         if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
76                 status = NT_STATUS_END_OF_FILE;
77         }
78
79         if (c->transport.recv_data) {
80                 c->transport.recv_data(c, NULL, status);
81         }
82 }
83
84 struct smb_send_read_state {
85         struct dcecli_connection *p;
86 };
87
88 static int smb_send_read_state_destructor(struct smb_send_read_state *state)
89 {
90         struct dcecli_connection *p = state->p;
91         struct smb_private *sock = talloc_get_type_abort(
92                 p->transport.private_data, struct smb_private);
93
94         sock->read_subreq = NULL;
95
96         return 0;
97 }
98
99 static void smb_send_read_done(struct tevent_req *subreq);
100
101 static NTSTATUS smb_send_read(struct dcecli_connection *p)
102 {
103         struct smb_private *sock = talloc_get_type_abort(
104                 p->transport.private_data, struct smb_private);
105         struct smb_send_read_state *state;
106
107         if (sock->read_subreq != NULL) {
108                 sock->pending_reads++;
109                 return NT_STATUS_OK;
110         }
111
112         state = talloc_zero(sock, struct smb_send_read_state);
113         if (state == NULL) {
114                 return NT_STATUS_NO_MEMORY;
115         }
116         state->p = p;
117
118         talloc_set_destructor(state, smb_send_read_state_destructor);
119
120         sock->read_subreq = dcerpc_read_ncacn_packet_send(state,
121                                                           p->event_ctx,
122                                                           sock->stream);
123         if (sock->read_subreq == NULL) {
124                 return NT_STATUS_NO_MEMORY;
125         }
126         tevent_req_set_callback(sock->read_subreq, smb_send_read_done, state);
127
128         return NT_STATUS_OK;
129 }
130
131 static void smb_send_read_done(struct tevent_req *subreq)
132 {
133         struct smb_send_read_state *state =
134                 tevent_req_callback_data(subreq,
135                                          struct smb_send_read_state);
136         struct dcecli_connection *p = state->p;
137         struct smb_private *sock = talloc_get_type_abort(
138                 p->transport.private_data, struct smb_private);
139         NTSTATUS status;
140         struct ncacn_packet *pkt;
141         DATA_BLOB blob;
142
143         status = dcerpc_read_ncacn_packet_recv(subreq, state,
144                                                &pkt, &blob);
145         TALLOC_FREE(subreq);
146         if (!NT_STATUS_IS_OK(status)) {
147                 TALLOC_FREE(state);
148                 pipe_dead(p, status);
149                 return;
150         }
151
152         /*
153          * here we steal into thet connection context,
154          * but p->transport.recv_data() will steal or free it again
155          */
156         talloc_steal(p, blob.data);
157         TALLOC_FREE(state);
158
159         if (sock->pending_reads > 0) {
160                 sock->pending_reads--;
161
162                 status = smb_send_read(p);
163                 if (!NT_STATUS_IS_OK(status)) {
164                         pipe_dead(p, status);
165                         return;
166                 }
167         }
168
169         if (p->transport.recv_data) {
170                 p->transport.recv_data(p, &blob, NT_STATUS_OK);
171         }
172 }
173
174 /*
175    send an initial pdu in a multi-pdu sequence
176 */
177
178 struct smb_send_request_state {
179         struct dcecli_connection *p;
180         DATA_BLOB blob;
181         struct iovec iov;
182 };
183
184 static int smb_send_request_state_destructor(struct smb_send_request_state *state)
185 {
186         struct dcecli_connection *p = state->p;
187         struct smb_private *sock = talloc_get_type_abort(
188                 p->transport.private_data, struct smb_private);
189
190         sock->read_subreq = NULL;
191
192         return 0;
193 }
194
195 static void smb_send_request_wait_done(struct tevent_req *subreq);
196 static void smb_send_request_done(struct tevent_req *subreq);
197
198 static NTSTATUS smb_send_request(struct dcecli_connection *p, DATA_BLOB *data,
199                                   bool trigger_read)
200 {
201         struct smb_private *sock = talloc_get_type_abort(
202                 p->transport.private_data, struct smb_private);
203         struct smb_send_request_state *state;
204         struct tevent_req *subreq;
205         bool use_trans = trigger_read;
206
207         if (sock->stream == NULL) {
208                 return NT_STATUS_CONNECTION_DISCONNECTED;
209         }
210
211         state = talloc_zero(sock, struct smb_send_request_state);
212         if (state == NULL) {
213                 return NT_STATUS_NO_MEMORY;
214         }
215         state->p = p;
216
217         state->blob = data_blob_talloc(state, data->data, data->length);
218         if (state->blob.data == NULL) {
219                 TALLOC_FREE(state);
220                 return NT_STATUS_NO_MEMORY;
221         }
222         state->iov.iov_base = (void *)state->blob.data;
223         state->iov.iov_len = state->blob.length;
224
225         if (sock->read_subreq != NULL) {
226                 use_trans = false;
227         }
228
229         if (use_trans) {
230                 /*
231                  * we need to block reads until our write is
232                  * the next in the write queue.
233                  */
234                 sock->read_subreq = tevent_queue_wait_send(state, p->event_ctx,
235                                                            sock->write_queue);
236                 if (sock->read_subreq == NULL) {
237                         TALLOC_FREE(state);
238                         return NT_STATUS_NO_MEMORY;
239                 }
240                 tevent_req_set_callback(sock->read_subreq,
241                                         smb_send_request_wait_done,
242                                         state);
243
244                 talloc_set_destructor(state, smb_send_request_state_destructor);
245
246                 trigger_read = false;
247         }
248
249         subreq = tstream_writev_queue_send(state, p->event_ctx,
250                                            sock->stream,
251                                            sock->write_queue,
252                                            &state->iov, 1);
253         if (subreq == NULL) {
254                 TALLOC_FREE(state);
255                 return NT_STATUS_NO_MEMORY;
256         }
257         tevent_req_set_callback(subreq, smb_send_request_done, state);
258
259         if (trigger_read) {
260                 smb_send_read(p);
261         }
262
263         return NT_STATUS_OK;
264 }
265
266 static void smb_send_request_wait_done(struct tevent_req *subreq)
267 {
268         struct smb_send_request_state *state =
269                 tevent_req_callback_data(subreq,
270                 struct smb_send_request_state);
271         struct dcecli_connection *p = state->p;
272         struct smb_private *sock = talloc_get_type_abort(
273                 p->transport.private_data, struct smb_private);
274         NTSTATUS status;
275         bool ok;
276
277         sock->read_subreq = NULL;
278         talloc_set_destructor(state, NULL);
279
280         ok = tevent_queue_wait_recv(subreq);
281         if (!ok) {
282                 TALLOC_FREE(state);
283                 pipe_dead(p, NT_STATUS_NO_MEMORY);
284                 return;
285         }
286
287         if (tevent_queue_length(sock->write_queue) <= 2) {
288                 status = tstream_smbXcli_np_use_trans(sock->stream);
289                 if (!NT_STATUS_IS_OK(status)) {
290                         TALLOC_FREE(state);
291                         pipe_dead(p, status);
292                         return;
293                 }
294         }
295
296         /* we free subreq after tstream_smbXcli_np_use_trans */
297         TALLOC_FREE(subreq);
298
299         smb_send_read(p);
300 }
301
302 static void smb_send_request_done(struct tevent_req *subreq)
303 {
304         struct smb_send_request_state *state =
305                 tevent_req_callback_data(subreq,
306                 struct smb_send_request_state);
307         int ret;
308         int error;
309
310         ret = tstream_writev_queue_recv(subreq, &error);
311         TALLOC_FREE(subreq);
312         if (ret == -1) {
313                 struct dcecli_connection *p = state->p;
314                 NTSTATUS status = map_nt_error_from_unix_common(error);
315
316                 TALLOC_FREE(state);
317                 pipe_dead(p, status);
318                 return;
319         }
320
321         TALLOC_FREE(state);
322 }
323
324 /* 
325    shutdown SMB pipe connection
326 */
327 struct smb_shutdown_pipe_state {
328         struct dcecli_connection *c;
329         NTSTATUS status;
330 };
331
332 static void smb_shutdown_pipe_done(struct tevent_req *subreq);
333
334 static NTSTATUS smb_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
335 {
336         struct smb_private *smb = talloc_get_type_abort(
337                 c->transport.private_data, struct smb_private);
338         struct smb_shutdown_pipe_state *state;
339         struct tevent_req *subreq;
340
341         if (smb->stream == NULL) {
342                 return NT_STATUS_OK;
343         }
344
345         state = talloc_zero(smb, struct smb_shutdown_pipe_state);
346         if (state == NULL) {
347                 return NT_STATUS_NO_MEMORY;
348         }
349         state->c = c;
350         state->status = status;
351
352         subreq = tstream_disconnect_send(state, c->event_ctx, smb->stream);
353         if (subreq == NULL) {
354                 return NT_STATUS_NO_MEMORY;
355         }
356         tevent_req_set_callback(subreq, smb_shutdown_pipe_done, state);
357
358         return status;
359 }
360
361 static void smb_shutdown_pipe_done(struct tevent_req *subreq)
362 {
363         struct smb_shutdown_pipe_state *state =
364                 tevent_req_callback_data(subreq, struct smb_shutdown_pipe_state);
365         struct dcecli_connection *c = state->c;
366         NTSTATUS status = state->status;
367         int error;
368
369         /*
370          * here we ignore the return values...
371          */
372         tstream_disconnect_recv(subreq, &error);
373         TALLOC_FREE(subreq);
374
375         TALLOC_FREE(state);
376
377         pipe_dead(c, status);
378 }
379
380 /*
381   return SMB server name (called name)
382 */
383 static const char *smb_peer_name(struct dcecli_connection *c)
384 {
385         struct smb_private *smb = talloc_get_type_abort(
386                 c->transport.private_data, struct smb_private);
387         if (smb == NULL) return "";
388         return smb->server_name;
389 }
390
391 /*
392   return remote name we make the actual connection (good for kerberos) 
393 */
394 static const char *smb_target_hostname(struct dcecli_connection *c)
395 {
396         struct smb_private *smb = talloc_get_type_abort(
397                 c->transport.private_data, struct smb_private);
398         if (smb == NULL) return "";
399         return smb->server_name;
400 }
401
402 /*
403   fetch the user session key 
404 */
405 static NTSTATUS smb_session_key(struct dcecli_connection *c, DATA_BLOB *session_key)
406 {
407         struct smb_private *smb = talloc_get_type_abort(
408                 c->transport.private_data, struct smb_private);
409
410         if (smb == NULL) return NT_STATUS_CONNECTION_DISCONNECTED;
411
412         if (smb->session_key.length == 0) {
413                 return NT_STATUS_NO_USER_SESSION_KEY;
414         }
415
416         *session_key = smb->session_key;
417         return NT_STATUS_OK;
418 }
419
420 struct dcerpc_pipe_open_smb_state {
421         struct dcecli_connection *c;
422         struct composite_context *ctx;
423
424         const char *fname;
425
426         struct smb_private *smb;
427 };
428
429 static void dcerpc_pipe_open_smb_done(struct tevent_req *subreq);
430
431 struct composite_context *dcerpc_pipe_open_smb_send(struct dcecli_connection *c,
432                                                 struct smbXcli_conn *conn,
433                                                 struct smbXcli_session *session,
434                                                 struct smbXcli_tcon *tcon,
435                                                 uint32_t timeout_msec,
436                                                 const char *pipe_name)
437 {
438         struct composite_context *ctx;
439         struct dcerpc_pipe_open_smb_state *state;
440         uint16_t pid = 0;
441         struct tevent_req *subreq;
442
443         ctx = composite_create(c, c->event_ctx);
444         if (ctx == NULL) return NULL;
445
446         state = talloc(ctx, struct dcerpc_pipe_open_smb_state);
447         if (composite_nomem(state, ctx)) return ctx;
448         ctx->private_data = state;
449
450         state->c = c;
451         state->ctx = ctx;
452
453         if ((strncasecmp(pipe_name, "/pipe/", 6) == 0) || 
454             (strncasecmp(pipe_name, "\\pipe\\", 6) == 0)) {
455                 pipe_name += 6;
456         }
457         if ((strncasecmp(pipe_name, "/", 1) == 0) ||
458             (strncasecmp(pipe_name, "\\", 1) == 0)) {
459                 pipe_name += 1;
460         }
461         state->fname = talloc_strdup(state, pipe_name);
462         if (composite_nomem(state->fname, ctx)) return ctx;
463
464         state->smb = talloc_zero(state, struct smb_private);
465         if (composite_nomem(state->smb, ctx)) return ctx;
466
467         state->smb->conn = conn;
468         state->smb->session = session;
469         state->smb->tcon = tcon;
470         state->smb->timeout_msec = timeout_msec;
471
472         state->smb->server_name = strupper_talloc(state->smb,
473                 smbXcli_conn_remote_name(conn));
474         if (composite_nomem(state->smb->server_name, ctx)) return ctx;
475
476         ctx->status = smbXcli_session_application_key(session,
477                                                       state->smb,
478                                                       &state->smb->session_key);
479         if (NT_STATUS_EQUAL(ctx->status, NT_STATUS_NO_USER_SESSION_KEY)) {
480                 state->smb->session_key = data_blob_null;
481                 ctx->status = NT_STATUS_OK;
482         }
483         if (!composite_is_ok(ctx)) return ctx;
484
485         subreq = tstream_smbXcli_np_open_send(state, c->event_ctx,
486                                               conn, session, tcon, pid,
487                                               timeout_msec, state->fname);
488         if (composite_nomem(subreq, ctx)) return ctx;
489         tevent_req_set_callback(subreq, dcerpc_pipe_open_smb_done, state);
490
491         return ctx;
492 }
493
494 static void dcerpc_pipe_open_smb_done(struct tevent_req *subreq)
495 {
496         struct dcerpc_pipe_open_smb_state *state =
497                 tevent_req_callback_data(subreq,
498                 struct dcerpc_pipe_open_smb_state);
499         struct composite_context *ctx = state->ctx;
500         struct dcecli_connection *c = state->c;
501
502         ctx->status = tstream_smbXcli_np_open_recv(subreq,
503                                                    state->smb,
504                                                    &state->smb->stream);
505         TALLOC_FREE(subreq);
506         if (!composite_is_ok(ctx)) return;
507
508         state->smb->write_queue = tevent_queue_create(state->smb,
509                                         "dcerpc_smb write queue");
510         if (composite_nomem(state->smb->write_queue, ctx)) return;
511
512         /*
513           fill in the transport methods
514         */
515         c->transport.transport       = NCACN_NP;
516         c->transport.private_data    = NULL;
517         c->transport.shutdown_pipe   = smb_shutdown_pipe;
518         c->transport.peer_name       = smb_peer_name;
519         c->transport.target_hostname = smb_target_hostname;
520
521         c->transport.send_request    = smb_send_request;
522         c->transport.send_read       = smb_send_read;
523         c->transport.recv_data       = NULL;
524
525         /*
526          * Windows uses 4280 for ncacn_np,
527          * so we also use it, this is what our
528          * tstream_smbXcli_np code relies on.
529          */
530         c->srv_max_xmit_frag = 4280;
531         c->srv_max_recv_frag = 4280;
532
533         /* Over-ride the default session key with the SMB session key */
534         c->security_state.session_key = smb_session_key;
535
536         c->transport.private_data = talloc_move(c, &state->smb);
537
538         composite_done(ctx);
539 }
540
541 NTSTATUS dcerpc_pipe_open_smb_recv(struct composite_context *c)
542 {
543         NTSTATUS status = composite_wait(c);
544         talloc_free(c);
545         return status;
546 }
547
548 _PUBLIC_ NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe *p,
549                               struct smbcli_tree *t,
550                               const char *pipe_name)
551 {
552         struct smbXcli_conn *conn;
553         struct smbXcli_session *session;
554         struct smbXcli_tcon *tcon;
555         uint32_t timeout_msec;
556         struct composite_context *ctx;
557
558         conn = t->session->transport->conn;
559         session = t->session->smbXcli;
560         tcon = t->smbXcli;
561         smb1cli_tcon_set_id(tcon, t->tid);
562         timeout_msec = t->session->transport->options.request_timeout * 1000;
563
564         /* if we don't have a binding on this pipe yet, then create one */
565         if (p->binding == NULL) {
566                 NTSTATUS status;
567                 const char *r = smbXcli_conn_remote_name(conn);
568                 char *str;
569                 SMB_ASSERT(r != NULL);
570                 str = talloc_asprintf(p, "ncacn_np:%s", r);
571                 if (str == NULL) {
572                         return NT_STATUS_NO_MEMORY;
573                 }
574                 status = dcerpc_parse_binding(p, str,
575                                               &p->binding);
576                 talloc_free(str);
577                 if (!NT_STATUS_IS_OK(status)) {
578                         return status;
579                 }
580         }
581
582         ctx = dcerpc_pipe_open_smb_send(p->conn,
583                                         conn, session,
584                                         tcon, timeout_msec,
585                                         pipe_name);
586         if (ctx == NULL) {
587                 return NT_STATUS_NO_MEMORY;
588         }
589
590         return dcerpc_pipe_open_smb_recv(ctx);
591 }
592
593 struct composite_context *dcerpc_secondary_smb_send(struct dcecli_connection *c1,
594                                                     struct dcerpc_pipe *p2,
595                                                     const char *pipe_name)
596 {
597         struct smb_private *smb;
598
599         if (c1->transport.transport != NCACN_NP) return NULL;
600
601         smb = talloc_get_type(c1->transport.private_data, struct smb_private);
602         if (!smb) return NULL;
603
604         return dcerpc_pipe_open_smb_send(p2->conn,
605                                          smb->conn,
606                                          smb->session,
607                                          smb->tcon,
608                                          smb->timeout_msec,
609                                          pipe_name);
610 }
611
612 NTSTATUS dcerpc_secondary_smb_recv(struct composite_context *c)
613 {
614         return dcerpc_pipe_open_smb_recv(c);
615 }