r5037: got rid of all of the TALLOC_DEPRECATED stuff. My apologies for the
[kai/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 2 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "libcli/raw/libcliraw.h"
26 #include "librpc/gen_ndr/ndr_security.h"
27
28 /* transport private information used by SMB pipe transport */
29 struct smb_private {
30         uint16_t fnum;
31         struct smbcli_tree *tree;
32 };
33
34
35 /*
36   tell the dcerpc layer that the transport is dead
37 */
38 static void pipe_dead(struct dcerpc_connection *c, NTSTATUS status)
39 {
40         c->transport.recv_data(c, NULL, status);
41 }
42
43
44 /* 
45    this holds the state of an in-flight call
46 */
47 struct smb_read_state {
48         struct dcerpc_connection *c;
49         struct smbcli_request *req;
50         size_t received;
51         DATA_BLOB data;
52         union smb_read *io;
53 };
54
55 /*
56   called when a read request has completed
57 */
58 static void smb_read_callback(struct smbcli_request *req)
59 {
60         struct smb_private *smb;
61         struct smb_read_state *state;
62         union smb_read *io;
63         uint16_t frag_length;
64         NTSTATUS status;
65
66         state = req->async.private;
67         smb = state->c->transport.private;
68         io = state->io;
69
70         status = smb_raw_read_recv(state->req, io);
71         if (NT_STATUS_IS_ERR(status)) {
72                 pipe_dead(state->c, status);
73                 talloc_free(state);
74                 return;
75         }
76
77         state->received += io->readx.out.nread;
78
79         if (state->received < 16) {
80                 DEBUG(0,("dcerpc_smb: short packet (length %d) in read callback!\n",
81                          state->received));
82                 pipe_dead(state->c, NT_STATUS_INFO_LENGTH_MISMATCH);
83                 talloc_free(state);
84                 return;
85         }
86
87         frag_length = dcerpc_get_frag_length(&state->data);
88
89         if (frag_length <= state->received) {
90                 state->data.length = state->received;
91                 state->c->transport.recv_data(state->c, &state->data, NT_STATUS_OK);
92                 talloc_free(state);
93                 return;
94         }
95
96         /* initiate another read request, as we only got part of a fragment */
97         state->data.data = talloc_realloc(state, state->data.data, uint8_t, frag_length);
98
99         io->readx.in.mincnt = MIN(state->c->srv_max_xmit_frag, 
100                                   frag_length - state->received);
101         io->readx.in.maxcnt = io->readx.in.mincnt;
102         io->readx.out.data = state->data.data + state->received;
103
104         state->req = smb_raw_read_send(smb->tree, io);
105         if (state->req == NULL) {
106                 pipe_dead(state->c, NT_STATUS_NO_MEMORY);
107                 talloc_free(state);
108                 return;
109         }
110
111         state->req->async.fn = smb_read_callback;
112         state->req->async.private = state;
113 }
114
115 /*
116   trigger a read request from the server, possibly with some initial
117   data in the read buffer
118 */
119 static NTSTATUS send_read_request_continue(struct dcerpc_connection *c, DATA_BLOB *blob)
120 {
121         struct smb_private *smb = c->transport.private;
122         union smb_read *io;
123         struct smb_read_state *state;
124         struct smbcli_request *req;
125
126         state = talloc(smb, struct smb_read_state);
127         if (state == NULL) {
128                 return NT_STATUS_NO_MEMORY;
129         }
130
131         state->c = c;
132         if (blob == NULL) {
133                 state->received = 0;
134                 state->data = data_blob_talloc(state, NULL, 0x2000);
135         } else {
136                 uint32_t frag_length = blob->length>=16?
137                         dcerpc_get_frag_length(blob):0x2000;
138                 state->received = blob->length;
139                 state->data = data_blob_talloc(state, NULL, frag_length);
140                 if (!state->data.data) {
141                         talloc_free(state);
142                         return NT_STATUS_NO_MEMORY;
143                 }
144                 memcpy(state->data.data, blob->data, blob->length);
145         }
146
147         state->io = talloc(state, union smb_read);
148
149         io = state->io;
150         io->generic.level = RAW_READ_READX;
151         io->readx.in.fnum = smb->fnum;
152         io->readx.in.mincnt = state->data.length - state->received;
153         io->readx.in.maxcnt = io->readx.in.mincnt;
154         io->readx.in.offset = 0;
155         io->readx.in.remaining = 0;
156         io->readx.out.data = state->data.data + state->received;
157         req = smb_raw_read_send(smb->tree, io);
158         if (req == NULL) {
159                 return NT_STATUS_NO_MEMORY;
160         }
161
162         req->async.fn = smb_read_callback;
163         req->async.private = state;
164
165         state->req = req;
166
167         return NT_STATUS_OK;
168 }
169
170
171 /*
172   trigger a read request from the server
173 */
174 static NTSTATUS send_read_request(struct dcerpc_connection *c)
175 {
176         return send_read_request_continue(c, NULL);
177 }
178
179 /* 
180    this holds the state of an in-flight trans call
181 */
182 struct smb_trans_state {
183         struct dcerpc_connection *c;
184         struct smbcli_request *req;
185         struct smb_trans2 *trans;
186 };
187
188 /*
189   called when a trans request has completed
190 */
191 static void smb_trans_callback(struct smbcli_request *req)
192 {
193         struct smb_trans_state *state = req->async.private;
194         struct dcerpc_connection *c = state->c;
195         NTSTATUS status;
196
197         status = smb_raw_trans_recv(req, state, state->trans);
198
199         if (NT_STATUS_IS_ERR(status)) {
200                 pipe_dead(c, status);
201                 return;
202         }
203
204         if (!NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
205                 c->transport.recv_data(c, &state->trans->out.data, NT_STATUS_OK);
206                 talloc_free(state);
207                 return;
208         }
209
210         /* there is more to receive - setup a readx */
211         send_read_request_continue(c, &state->trans->out.data);
212         talloc_free(state);
213 }
214
215 /*
216   send a SMBtrans style request
217 */
218 static NTSTATUS smb_send_trans_request(struct dcerpc_connection *c, DATA_BLOB *blob)
219 {
220         struct smb_private *smb = c->transport.private;
221         struct smb_trans2 *trans;
222         uint16 setup[2];
223         struct smb_trans_state *state;
224
225         state = talloc(smb, struct smb_trans_state);
226         if (state == NULL) {
227                 return NT_STATUS_NO_MEMORY;
228         }
229
230         state->c = c;
231         state->trans = talloc(state, struct smb_trans2);
232         trans = state->trans;
233
234         trans->in.data = *blob;
235         trans->in.params = data_blob(NULL, 0);
236         
237         setup[0] = TRANSACT_DCERPCCMD;
238         setup[1] = smb->fnum;
239
240         trans->in.max_param = 0;
241         trans->in.max_data = smb_raw_max_trans_data(smb->tree, 0);
242         trans->in.max_setup = 0;
243         trans->in.setup_count = 2;
244         trans->in.flags = 0;
245         trans->in.timeout = 0;
246         trans->in.setup = setup;
247         trans->in.trans_name = "\\PIPE\\";
248
249         state->req = smb_raw_trans_send(smb->tree, trans);
250         if (state->req == NULL) {
251                 talloc_free(state);
252                 return NT_STATUS_NO_MEMORY;
253         }
254
255         state->req->async.fn = smb_trans_callback;
256         state->req->async.private = state;
257
258         return NT_STATUS_OK;
259 }
260
261 /*
262   called when a write request has completed
263 */
264 static void smb_write_callback(struct smbcli_request *req)
265 {
266         struct dcerpc_connection *c = req->async.private;
267
268         if (!NT_STATUS_IS_OK(req->status)) {
269                 DEBUG(0,("dcerpc_smb: write callback error\n"));
270                 pipe_dead(c, req->status);
271         }
272
273         smbcli_request_destroy(req);
274 }
275
276 /* 
277    send a packet to the server
278 */
279 static NTSTATUS smb_send_request(struct dcerpc_connection *c, DATA_BLOB *blob, BOOL trigger_read)
280 {
281         struct smb_private *smb = c->transport.private;
282         union smb_write io;
283         struct smbcli_request *req;
284
285         if (trigger_read) {
286                 return smb_send_trans_request(c, blob);
287         }
288
289         io.generic.level = RAW_WRITE_WRITEX;
290         io.writex.in.fnum = smb->fnum;
291         io.writex.in.offset = 0;
292         io.writex.in.wmode = PIPE_START_MESSAGE;
293         io.writex.in.remaining = blob->length;
294         io.writex.in.count = blob->length;
295         io.writex.in.data = blob->data;
296
297         req = smb_raw_write_send(smb->tree, &io);
298         if (req == NULL) {
299                 return NT_STATUS_NO_MEMORY;
300         }
301
302         req->async.fn = smb_write_callback;
303         req->async.private = c;
304
305         if (trigger_read) {
306                 send_read_request(c);
307         }
308
309         return NT_STATUS_OK;
310 }
311
312 /* 
313    return the event context for the pipe, so the caller can wait
314    for events asynchronously
315 */
316 static struct event_context *smb_event_context(struct dcerpc_connection *c)
317 {
318         struct smb_private *smb = c->transport.private;
319
320         return smb->tree->session->transport->socket->event.ctx;
321 }
322
323
324 /* 
325    shutdown SMB pipe connection
326 */
327 static NTSTATUS smb_shutdown_pipe(struct dcerpc_connection *c)
328 {
329         struct smb_private *smb = c->transport.private;
330         union smb_close io;
331
332         /* maybe we're still starting up */
333         if (!smb) return NT_STATUS_OK;
334
335         io.close.level = RAW_CLOSE_CLOSE;
336         io.close.in.fnum = smb->fnum;
337         io.close.in.write_time = 0;
338         smb_raw_close(smb->tree, &io);
339
340         talloc_free(smb);
341
342         return NT_STATUS_OK;
343 }
344
345 /*
346   return SMB server name
347 */
348 static const char *smb_peer_name(struct dcerpc_connection *c)
349 {
350         struct smb_private *smb = c->transport.private;
351         return smb->tree->session->transport->called.name;
352 }
353
354 /*
355   fetch the user session key 
356 */
357 static NTSTATUS smb_session_key(struct dcerpc_connection *c, DATA_BLOB *session_key)
358 {
359         struct smb_private *smb = c->transport.private;
360
361         if (smb->tree->session->user_session_key.data) {
362                 *session_key = smb->tree->session->user_session_key;
363                 return NT_STATUS_OK;
364         }
365         return NT_STATUS_NO_USER_SESSION_KEY;
366 }
367
368 /* 
369    open a rpc connection to a named pipe 
370 */
371 NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_connection *c, 
372                               struct smbcli_tree *tree,
373                               const char *pipe_name)
374 {
375         struct smb_private *smb;
376         NTSTATUS status;
377         union smb_open io;
378
379         io.ntcreatex.level = RAW_OPEN_NTCREATEX;
380         io.ntcreatex.in.flags = 0;
381         io.ntcreatex.in.root_fid = 0;
382         io.ntcreatex.in.access_mask = 
383                 SEC_STD_READ_CONTROL |
384                 SEC_FILE_WRITE_ATTRIBUTE |
385                 SEC_FILE_WRITE_EA |
386                 SEC_FILE_READ_DATA |
387                 SEC_FILE_WRITE_DATA;
388         io.ntcreatex.in.file_attr = 0;
389         io.ntcreatex.in.alloc_size = 0;
390         io.ntcreatex.in.share_access = 
391                 NTCREATEX_SHARE_ACCESS_READ |
392                 NTCREATEX_SHARE_ACCESS_WRITE;
393         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
394         io.ntcreatex.in.create_options = 0;
395         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
396         io.ntcreatex.in.security_flags = 0;
397         io.ntcreatex.in.fname = pipe_name;
398
399         status = smb_raw_open(tree, tree, &io);
400
401         if (!NT_STATUS_IS_OK(status)) {
402                 return status;
403         }
404
405         /*
406           fill in the transport methods
407         */
408         c->transport.transport = NCACN_NP;
409         c->transport.private = NULL;
410         c->transport.shutdown_pipe = smb_shutdown_pipe;
411         c->transport.peer_name = smb_peer_name;
412
413         c->transport.send_request = smb_send_request;
414         c->transport.send_read = send_read_request;
415         c->transport.event_context = smb_event_context;
416         c->transport.recv_data = NULL;
417         
418         /* Over-ride the default session key with the SMB session key */
419         c->security_state.session_key = smb_session_key;
420
421         smb = talloc(c, struct smb_private);
422         if (smb == NULL) {
423                 return NT_STATUS_NO_MEMORY;
424         }
425
426         smb->fnum = io.ntcreatex.out.fnum;
427         smb->tree = tree;
428
429         c->transport.private = smb;
430
431         return NT_STATUS_OK;
432 }
433
434 /*
435   return the SMB tree used for a dcerpc over SMB pipe
436 */
437 struct smbcli_tree *dcerpc_smb_tree(struct dcerpc_connection *c)
438 {
439         struct smb_private *smb = c->transport.private;
440
441         if (c->transport.transport != NCACN_NP) {
442                 return NULL;
443         }
444
445         return smb->tree;
446 }