r2100: rework the dcerpc client side library so that it is async. We now
[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
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         if (!NT_STATUS_IS_OK(req->status)) {
69                 pipe_dead(state->p, req->status);
70                 talloc_free(state);
71                 return;
72         }
73
74         status = smb_raw_read_recv(state->req, io);
75         if (!NT_STATUS_IS_OK(status)) {
76                 pipe_dead(state->p, status);
77                 talloc_free(state);
78                 return;
79         }
80
81         state->received += io->readx.out.nread;
82
83         if (state->received < 16) {
84                 DEBUG(0,("dcerpc_smb: short packet (length %d) in read callback!\n",
85                          state->received));
86                 pipe_dead(state->p, NT_STATUS_INFO_LENGTH_MISMATCH);
87                 talloc_free(state);
88                 return;
89         }
90
91         frag_length = dcerpc_get_frag_length(&state->data);
92         if (frag_length <= state->received) {
93                 state->data.length = state->received;
94                 state->p->transport.recv_data(state->p, &state->data, NT_STATUS_OK);
95                 talloc_free(state);
96                 return;
97         }
98
99         /* initiate another read request, as we only got part of a fragment */
100         state->data.data = talloc_realloc(state->data.data, frag_length);
101
102         io->readx.in.mincnt = frag_length - state->received;
103         io->readx.in.maxcnt = io->readx.in.mincnt;
104         io->readx.out.data = state->data.data + state->received;
105
106         req = smb_raw_read_send(smb->tree, io);
107         if (req == NULL) {
108                 pipe_dead(state->p, NT_STATUS_NO_MEMORY);
109                 talloc_free(state);
110                 return;
111         }
112
113         req->async.fn = smb_read_callback;
114         req->async.private = state;
115 }
116
117 /*
118   trigger a read request from the server
119 */
120 static NTSTATUS send_read_request(struct dcerpc_pipe *p)
121 {
122         struct smb_private *smb = p->transport.private;
123         union smb_read *io;
124         struct smb_read_state *state;
125         struct smbcli_request *req;
126
127         state = talloc_p(smb, struct smb_read_state);
128         if (state == NULL) {
129                 return NT_STATUS_NO_MEMORY;
130         }
131
132         state->p = p;
133         state->received = 0;
134         state->data = data_blob_talloc(state, NULL, 0x2000);
135         state->io = talloc_p(state, union smb_read);
136
137         io = state->io;
138         io->generic.level = RAW_READ_READX;
139         io->readx.in.fnum = smb->fnum;
140         io->readx.in.mincnt = state->data.length;
141         io->readx.in.maxcnt = state->data.length;
142         io->readx.in.offset = 0;
143         io->readx.in.remaining = 0;
144         io->readx.out.data = state->data.data;
145         req = smb_raw_read_send(smb->tree, io);
146         if (req == NULL) {
147                 return NT_STATUS_NO_MEMORY;
148         }
149
150         req->async.fn = smb_read_callback;
151         req->async.private = state;
152
153         state->req = req;
154
155         return NT_STATUS_OK;
156 }
157
158
159 /*
160   called when a write request has completed
161 */
162 static void smb_write_callback(struct smbcli_request *req)
163 {
164         struct dcerpc_pipe *p = req->async.private;
165
166         if (!NT_STATUS_IS_OK(req->status)) {
167                 DEBUG(0,("dcerpc_smb: write callback error\n"));
168                 pipe_dead(p, req->status);
169         }
170
171         smbcli_request_destroy(req);
172 }
173
174 /* 
175    send a packet to the server
176 */
177 static NTSTATUS smb_send_request(struct dcerpc_pipe *p, DATA_BLOB *blob)
178 {
179         struct smb_private *smb = p->transport.private;
180         union smb_write io;
181         struct smbcli_request *req;
182
183         io.generic.level = RAW_WRITE_WRITEX;
184         io.writex.in.fnum = smb->fnum;
185         io.writex.in.offset = 0;
186         io.writex.in.wmode = PIPE_START_MESSAGE;
187         io.writex.in.remaining = blob->length;
188         io.writex.in.count = blob->length;
189         io.writex.in.data = blob->data;
190
191         req = smb_raw_write_send(smb->tree, &io);
192         if (req == NULL) {
193                 return NT_STATUS_NO_MEMORY;
194         }
195
196         req->async.fn = smb_write_callback;
197         req->async.private = p;
198
199         return NT_STATUS_OK;
200 }
201
202 /* 
203    return the event context for the pipe, so the caller can wait
204    for events asynchronously
205 */
206 static struct event_context *smb_event_context(struct dcerpc_pipe *p)
207 {
208         struct smb_private *smb = p->transport.private;
209
210         return smb->tree->session->transport->event.ctx;
211 }
212
213
214 /* 
215    shutdown SMB pipe connection
216 */
217 static NTSTATUS smb_shutdown_pipe(struct dcerpc_pipe *p)
218 {
219         struct smb_private *smb = p->transport.private;
220         union smb_close c;
221
222         /* maybe we're still starting up */
223         if (!smb) return NT_STATUS_OK;
224
225         c.close.level = RAW_CLOSE_CLOSE;
226         c.close.in.fnum = smb->fnum;
227         c.close.in.write_time = 0;
228         smb_raw_close(smb->tree, &c);
229         smbcli_tree_close(smb->tree);
230
231         return NT_STATUS_OK;
232 }
233
234 /*
235   return SMB server name
236 */
237 static const char *smb_peer_name(struct dcerpc_pipe *p)
238 {
239         struct smb_private *smb = p->transport.private;
240         return smb->tree->session->transport->called.name;
241 }
242
243 /* 
244    open a rpc connection to a named pipe 
245 */
246 NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe **p, 
247                               struct smbcli_tree *tree,
248                               const char *pipe_name)
249 {
250         struct smb_private *smb;
251         NTSTATUS status;
252         char *name = NULL;
253         union smb_open io;
254         TALLOC_CTX *mem_ctx;
255
256         asprintf(&name, "\\%s", pipe_name);
257         if (!name) {
258                 return NT_STATUS_NO_MEMORY;
259         }
260
261         io.ntcreatex.level = RAW_OPEN_NTCREATEX;
262         io.ntcreatex.in.flags = 0;
263         io.ntcreatex.in.root_fid = 0;
264         io.ntcreatex.in.access_mask = 
265                 STD_RIGHT_READ_CONTROL_ACCESS | 
266                 SA_RIGHT_FILE_WRITE_ATTRIBUTES | 
267                 SA_RIGHT_FILE_WRITE_EA | 
268                 GENERIC_RIGHTS_FILE_READ |
269                 GENERIC_RIGHTS_FILE_WRITE;
270         io.ntcreatex.in.file_attr = 0;
271         io.ntcreatex.in.alloc_size = 0;
272         io.ntcreatex.in.share_access = 
273                 NTCREATEX_SHARE_ACCESS_READ |
274                 NTCREATEX_SHARE_ACCESS_WRITE;
275         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
276         io.ntcreatex.in.create_options = 0;
277         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
278         io.ntcreatex.in.security_flags = 0;
279         io.ntcreatex.in.fname = name;
280
281         mem_ctx = talloc_init("torture_rpc_connection");
282         if (!mem_ctx) {
283                 free(name);
284                 return NT_STATUS_NO_MEMORY;
285         }
286         status = smb_raw_open(tree, mem_ctx, &io);
287         free(name);
288         talloc_destroy(mem_ctx);
289
290         if (!NT_STATUS_IS_OK(status)) {
291                 return status;
292         }
293
294         if (!(*p = dcerpc_pipe_init())) {
295                 return NT_STATUS_NO_MEMORY;
296         }
297  
298         /*
299           fill in the transport methods
300         */
301         (*p)->transport.transport = NCACN_NP;
302         (*p)->transport.private = NULL;
303         (*p)->transport.shutdown_pipe = smb_shutdown_pipe;
304         (*p)->transport.peer_name = smb_peer_name;
305
306         (*p)->transport.send_request = smb_send_request;
307         (*p)->transport.send_read = send_read_request;
308         (*p)->transport.event_context = smb_event_context;
309         (*p)->transport.recv_data = NULL;
310         
311         smb = talloc((*p), sizeof(*smb));
312         if (!smb) {
313                 dcerpc_pipe_close(*p);
314                 return NT_STATUS_NO_MEMORY;
315         }
316
317         smb->fnum = io.ntcreatex.out.fnum;
318         smb->tree = tree;
319
320         (*p)->transport.private = smb;
321         tree->reference_count++;
322
323         return NT_STATUS_OK;
324 }
325
326 /*
327   return the SMB tree used for a dcerpc over SMB pipe
328 */
329 struct smbcli_tree *dcerpc_smb_tree(struct dcerpc_pipe *p)
330 {
331         struct smb_private *smb = p->transport.private;
332
333         if (p->transport.transport != NCACN_NP) {
334                 return NULL;
335         }
336
337         return smb->tree;
338 }