Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-wsgi
[samba.git] / source4 / libcli / smb_composite / smb2.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Andrew Tridgell 2008
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 /*
20   a composite API for making SMB-like calls using SMB2. This is useful
21   as SMB2 often requires more than one requests where a single SMB
22   request would do. In converting code that uses SMB to use SMB2,
23   these routines make life a lot easier
24 */
25
26
27 #include "includes.h"
28 #include "libcli/raw/libcliraw.h"
29 #include "libcli/raw/raw_proto.h"
30 #include "libcli/composite/composite.h"
31 #include "libcli/smb_composite/smb_composite.h"
32 #include "param/param.h"
33 #include "libcli/smb2/smb2_calls.h"
34
35 /*
36   continue after a SMB2 close
37  */
38 static void continue_close(struct smb2_request *req)
39 {
40         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
41                                                         struct composite_context);
42         NTSTATUS status;
43         struct smb2_close close_parm;
44
45         status = smb2_close_recv(req, &close_parm);
46         composite_error(ctx, status);   
47 }
48
49 /*
50   continue after the create in a composite unlink
51  */
52 static void continue_unlink(struct smb2_request *req)
53 {
54         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
55                                                         struct composite_context);
56         struct smb2_tree *tree = req->tree;
57         struct smb2_create create_parm;
58         struct smb2_close close_parm;
59         NTSTATUS status;
60
61         status = smb2_create_recv(req, ctx, &create_parm);
62         if (!NT_STATUS_IS_OK(status)) {
63                 composite_error(ctx, status);
64                 return;
65         }
66
67         ZERO_STRUCT(close_parm);
68         close_parm.in.file.handle = create_parm.out.file.handle;
69         
70         req = smb2_close_send(tree, &close_parm);
71         composite_continue_smb2(ctx, req, continue_close, ctx);
72 }
73
74 /*
75   composite SMB2 unlink call
76 */
77 struct composite_context *smb2_composite_unlink_send(struct smb2_tree *tree, 
78                                                      union smb_unlink *io)
79 {
80         struct composite_context *ctx;
81         struct smb2_create create_parm;
82         struct smb2_request *req;
83
84         ctx = composite_create(tree, tree->session->transport->socket->event.ctx);
85         if (ctx == NULL) return NULL;
86
87         /* check for wildcards - we could support these with a
88            search, but for now they aren't necessary */
89         if (strpbrk(io->unlink.in.pattern, "*?<>") != NULL) {
90                 composite_error(ctx, NT_STATUS_NOT_SUPPORTED);
91                 return ctx;
92         }
93
94         ZERO_STRUCT(create_parm);
95         create_parm.in.desired_access     = SEC_STD_DELETE;
96         create_parm.in.create_disposition = NTCREATEX_DISP_OPEN;
97         create_parm.in.share_access = 
98                 NTCREATEX_SHARE_ACCESS_DELETE|
99                 NTCREATEX_SHARE_ACCESS_READ|
100                 NTCREATEX_SHARE_ACCESS_WRITE;
101         create_parm.in.create_options = 
102                 NTCREATEX_OPTIONS_DELETE_ON_CLOSE |
103                 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
104         create_parm.in.fname = io->unlink.in.pattern;
105         if (create_parm.in.fname[0] == '\\') {
106                 create_parm.in.fname++;
107         }
108
109         req = smb2_create_send(tree, &create_parm);
110
111         composite_continue_smb2(ctx, req, continue_unlink, ctx);
112         return ctx;
113 }
114
115
116 /*
117   composite unlink call - sync interface
118 */
119 NTSTATUS smb2_composite_unlink(struct smb2_tree *tree, union smb_unlink *io)
120 {
121         struct composite_context *c = smb2_composite_unlink_send(tree, io);
122         return composite_wait_free(c);
123 }
124
125
126
127
128 /*
129   continue after the create in a composite mkdir
130  */
131 static void continue_mkdir(struct smb2_request *req)
132 {
133         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
134                                                         struct composite_context);
135         struct smb2_tree *tree = req->tree;
136         struct smb2_create create_parm;
137         struct smb2_close close_parm;
138         NTSTATUS status;
139
140         status = smb2_create_recv(req, ctx, &create_parm);
141         if (!NT_STATUS_IS_OK(status)) {
142                 composite_error(ctx, status);
143                 return;
144         }
145
146         ZERO_STRUCT(close_parm);
147         close_parm.in.file.handle = create_parm.out.file.handle;
148         
149         req = smb2_close_send(tree, &close_parm);
150         composite_continue_smb2(ctx, req, continue_close, ctx);
151 }
152
153 /*
154   composite SMB2 mkdir call
155 */
156 struct composite_context *smb2_composite_mkdir_send(struct smb2_tree *tree, 
157                                                      union smb_mkdir *io)
158 {
159         struct composite_context *ctx;
160         struct smb2_create create_parm;
161         struct smb2_request *req;
162
163         ctx = composite_create(tree, tree->session->transport->socket->event.ctx);
164         if (ctx == NULL) return NULL;
165
166         ZERO_STRUCT(create_parm);
167
168         create_parm.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
169         create_parm.in.share_access = 
170                 NTCREATEX_SHARE_ACCESS_READ|
171                 NTCREATEX_SHARE_ACCESS_WRITE;
172         create_parm.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
173         create_parm.in.file_attributes   = FILE_ATTRIBUTE_DIRECTORY;
174         create_parm.in.create_disposition = NTCREATEX_DISP_CREATE;
175         create_parm.in.fname = io->mkdir.in.path;
176         if (create_parm.in.fname[0] == '\\') {
177                 create_parm.in.fname++;
178         }
179
180         req = smb2_create_send(tree, &create_parm);
181
182         composite_continue_smb2(ctx, req, continue_mkdir, ctx);
183
184         return ctx;
185 }
186
187
188 /*
189   composite mkdir call - sync interface
190 */
191 NTSTATUS smb2_composite_mkdir(struct smb2_tree *tree, union smb_mkdir *io)
192 {
193         struct composite_context *c = smb2_composite_mkdir_send(tree, io);
194         return composite_wait_free(c);
195 }
196
197
198
199 /*
200   continue after the create in a composite rmdir
201  */
202 static void continue_rmdir(struct smb2_request *req)
203 {
204         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
205                                                         struct composite_context);
206         struct smb2_tree *tree = req->tree;
207         struct smb2_create create_parm;
208         struct smb2_close close_parm;
209         NTSTATUS status;
210
211         status = smb2_create_recv(req, ctx, &create_parm);
212         if (!NT_STATUS_IS_OK(status)) {
213                 composite_error(ctx, status);
214                 return;
215         }
216
217         ZERO_STRUCT(close_parm);
218         close_parm.in.file.handle = create_parm.out.file.handle;
219         
220         req = smb2_close_send(tree, &close_parm);
221         composite_continue_smb2(ctx, req, continue_close, ctx);
222 }
223
224 /*
225   composite SMB2 rmdir call
226 */
227 struct composite_context *smb2_composite_rmdir_send(struct smb2_tree *tree, 
228                                                     struct smb_rmdir *io)
229 {
230         struct composite_context *ctx;
231         struct smb2_create create_parm;
232         struct smb2_request *req;
233
234         ctx = composite_create(tree, tree->session->transport->socket->event.ctx);
235         if (ctx == NULL) return NULL;
236
237         ZERO_STRUCT(create_parm);
238         create_parm.in.desired_access     = SEC_STD_DELETE;
239         create_parm.in.create_disposition = NTCREATEX_DISP_OPEN;
240         create_parm.in.share_access = 
241                 NTCREATEX_SHARE_ACCESS_DELETE|
242                 NTCREATEX_SHARE_ACCESS_READ|
243                 NTCREATEX_SHARE_ACCESS_WRITE;
244         create_parm.in.create_options = 
245                 NTCREATEX_OPTIONS_DIRECTORY |
246                 NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
247         create_parm.in.fname = io->in.path;
248         if (create_parm.in.fname[0] == '\\') {
249                 create_parm.in.fname++;
250         }
251
252         req = smb2_create_send(tree, &create_parm);
253
254         composite_continue_smb2(ctx, req, continue_rmdir, ctx);
255         return ctx;
256 }
257
258
259 /*
260   composite rmdir call - sync interface
261 */
262 NTSTATUS smb2_composite_rmdir(struct smb2_tree *tree, struct smb_rmdir *io)
263 {
264         struct composite_context *c = smb2_composite_rmdir_send(tree, io);
265         return composite_wait_free(c);
266 }
267
268
269 /*
270   continue after the setfileinfo in a composite setpathinfo
271  */
272 static void continue_setpathinfo_close(struct smb2_request *req)
273 {
274         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
275                                                         struct composite_context);
276         struct smb2_tree *tree = req->tree;
277         struct smb2_close close_parm;
278         NTSTATUS status;
279         union smb_setfileinfo *io2 = talloc_get_type(ctx->private_data, 
280                                                      union smb_setfileinfo);
281
282         status = smb2_setinfo_recv(req);
283         if (!NT_STATUS_IS_OK(status)) {
284                 composite_error(ctx, status);
285                 return;
286         }
287
288         ZERO_STRUCT(close_parm);
289         close_parm.in.file.handle = io2->generic.in.file.handle;
290         
291         req = smb2_close_send(tree, &close_parm);
292         composite_continue_smb2(ctx, req, continue_close, ctx);
293 }
294
295
296 /*
297   continue after the create in a composite setpathinfo
298  */
299 static void continue_setpathinfo(struct smb2_request *req)
300 {
301         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
302                                                         struct composite_context);
303         struct smb2_tree *tree = req->tree;
304         struct smb2_create create_parm;
305         NTSTATUS status;
306         union smb_setfileinfo *io2 = talloc_get_type(ctx->private_data, 
307                                                      union smb_setfileinfo);
308
309         status = smb2_create_recv(req, ctx, &create_parm);
310         if (!NT_STATUS_IS_OK(status)) {
311                 composite_error(ctx, status);
312                 return;
313         }
314
315         io2->generic.in.file.handle = create_parm.out.file.handle;
316
317         req = smb2_setinfo_file_send(tree, io2);
318         composite_continue_smb2(ctx, req, continue_setpathinfo_close, ctx);
319 }
320
321
322 /*
323   composite SMB2 setpathinfo call
324 */
325 struct composite_context *smb2_composite_setpathinfo_send(struct smb2_tree *tree, 
326                                                           union smb_setfileinfo *io)
327 {
328         struct composite_context *ctx;
329         struct smb2_create create_parm;
330         struct smb2_request *req;
331         union smb_setfileinfo *io2;
332
333         ctx = composite_create(tree, tree->session->transport->socket->event.ctx);
334         if (ctx == NULL) return NULL;
335
336         ZERO_STRUCT(create_parm);
337         create_parm.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
338         create_parm.in.create_disposition = NTCREATEX_DISP_OPEN;
339         create_parm.in.share_access = 
340                 NTCREATEX_SHARE_ACCESS_DELETE|
341                 NTCREATEX_SHARE_ACCESS_READ|
342                 NTCREATEX_SHARE_ACCESS_WRITE;
343         create_parm.in.create_options = 0;
344         create_parm.in.fname = io->generic.in.file.path;
345         if (create_parm.in.fname[0] == '\\') {
346                 create_parm.in.fname++;
347         }
348
349         req = smb2_create_send(tree, &create_parm);
350
351         io2 = talloc(ctx, union smb_setfileinfo);
352         if (composite_nomem(io2, ctx)) {
353                 return ctx;
354         }
355         *io2 = *io;
356
357         ctx->private_data = io2;
358
359         composite_continue_smb2(ctx, req, continue_setpathinfo, ctx);
360         return ctx;
361 }
362
363
364 /*
365   composite setpathinfo call
366  */
367 NTSTATUS smb2_composite_setpathinfo(struct smb2_tree *tree, union smb_setfileinfo *io)
368 {
369         struct composite_context *c = smb2_composite_setpathinfo_send(tree, io);
370         return composite_wait_free(c);  
371 }