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