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