d71708a974ef0975304b312cb4490d1c127895eb
[ira/wip.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 "libcli/smb2/smb2_calls.h"
33
34 /*
35   continue after a SMB2 close
36  */
37 static void continue_close(struct smb2_request *req)
38 {
39         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
40                                                         struct composite_context);
41         NTSTATUS status;
42         struct smb2_close close_parm;
43
44         status = smb2_close_recv(req, &close_parm);
45         composite_error(ctx, status);   
46 }
47
48 /*
49   continue after the create in a composite unlink
50  */
51 static void continue_unlink(struct smb2_request *req)
52 {
53         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
54                                                         struct composite_context);
55         struct smb2_tree *tree = req->tree;
56         struct smb2_create create_parm;
57         struct smb2_close close_parm;
58         NTSTATUS status;
59
60         status = smb2_create_recv(req, ctx, &create_parm);
61         if (!NT_STATUS_IS_OK(status)) {
62                 composite_error(ctx, status);
63                 return;
64         }
65
66         ZERO_STRUCT(close_parm);
67         close_parm.in.file.handle = create_parm.out.file.handle;
68         
69         req = smb2_close_send(tree, &close_parm);
70         composite_continue_smb2(ctx, req, continue_close, ctx);
71 }
72
73 /*
74   composite SMB2 unlink call
75 */
76 struct composite_context *smb2_composite_unlink_send(struct smb2_tree *tree, 
77                                                      union smb_unlink *io)
78 {
79         struct composite_context *ctx;
80         struct smb2_create create_parm;
81         struct smb2_request *req;
82
83         ctx = composite_create(tree, tree->session->transport->socket->event.ctx);
84         if (ctx == NULL) return NULL;
85
86         /* check for wildcards - we could support these with a
87            search, but for now they aren't necessary */
88         if (strpbrk(io->unlink.in.pattern, "*?<>") != NULL) {
89                 composite_error(ctx, NT_STATUS_NOT_SUPPORTED);
90                 return ctx;
91         }
92
93         ZERO_STRUCT(create_parm);
94         create_parm.in.desired_access     = SEC_STD_DELETE;
95         create_parm.in.create_disposition = NTCREATEX_DISP_OPEN;
96         create_parm.in.share_access = 
97                 NTCREATEX_SHARE_ACCESS_DELETE|
98                 NTCREATEX_SHARE_ACCESS_READ|
99                 NTCREATEX_SHARE_ACCESS_WRITE;
100         create_parm.in.create_options = 
101                 NTCREATEX_OPTIONS_DELETE_ON_CLOSE |
102                 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
103         create_parm.in.fname = io->unlink.in.pattern;
104         if (create_parm.in.fname[0] == '\\') {
105                 create_parm.in.fname++;
106         }
107
108         req = smb2_create_send(tree, &create_parm);
109
110         composite_continue_smb2(ctx, req, continue_unlink, ctx);
111         return ctx;
112 }
113
114
115 /*
116   composite unlink call - sync interface
117 */
118 NTSTATUS smb2_composite_unlink(struct smb2_tree *tree, union smb_unlink *io)
119 {
120         struct composite_context *c = smb2_composite_unlink_send(tree, io);
121         return composite_wait_free(c);
122 }
123
124
125
126
127 /*
128   continue after the create in a composite mkdir
129  */
130 static void continue_mkdir(struct smb2_request *req)
131 {
132         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
133                                                         struct composite_context);
134         struct smb2_tree *tree = req->tree;
135         struct smb2_create create_parm;
136         struct smb2_close close_parm;
137         NTSTATUS status;
138
139         status = smb2_create_recv(req, ctx, &create_parm);
140         if (!NT_STATUS_IS_OK(status)) {
141                 composite_error(ctx, status);
142                 return;
143         }
144
145         ZERO_STRUCT(close_parm);
146         close_parm.in.file.handle = create_parm.out.file.handle;
147         
148         req = smb2_close_send(tree, &close_parm);
149         composite_continue_smb2(ctx, req, continue_close, ctx);
150 }
151
152 /*
153   composite SMB2 mkdir call
154 */
155 struct composite_context *smb2_composite_mkdir_send(struct smb2_tree *tree, 
156                                                      union smb_mkdir *io)
157 {
158         struct composite_context *ctx;
159         struct smb2_create create_parm;
160         struct smb2_request *req;
161
162         ctx = composite_create(tree, tree->session->transport->socket->event.ctx);
163         if (ctx == NULL) return NULL;
164
165         ZERO_STRUCT(create_parm);
166
167         create_parm.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
168         create_parm.in.share_access = 
169                 NTCREATEX_SHARE_ACCESS_READ|
170                 NTCREATEX_SHARE_ACCESS_WRITE;
171         create_parm.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
172         create_parm.in.file_attributes   = FILE_ATTRIBUTE_DIRECTORY;
173         create_parm.in.create_disposition = NTCREATEX_DISP_CREATE;
174         create_parm.in.fname = io->mkdir.in.path;
175         if (create_parm.in.fname[0] == '\\') {
176                 create_parm.in.fname++;
177         }
178
179         req = smb2_create_send(tree, &create_parm);
180
181         composite_continue_smb2(ctx, req, continue_mkdir, ctx);
182
183         return ctx;
184 }
185
186
187 /*
188   composite mkdir call - sync interface
189 */
190 NTSTATUS smb2_composite_mkdir(struct smb2_tree *tree, union smb_mkdir *io)
191 {
192         struct composite_context *c = smb2_composite_mkdir_send(tree, io);
193         return composite_wait_free(c);
194 }
195
196
197
198 /*
199   continue after the create in a composite rmdir
200  */
201 static void continue_rmdir(struct smb2_request *req)
202 {
203         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
204                                                         struct composite_context);
205         struct smb2_tree *tree = req->tree;
206         struct smb2_create create_parm;
207         struct smb2_close close_parm;
208         NTSTATUS status;
209
210         status = smb2_create_recv(req, ctx, &create_parm);
211         if (!NT_STATUS_IS_OK(status)) {
212                 composite_error(ctx, status);
213                 return;
214         }
215
216         ZERO_STRUCT(close_parm);
217         close_parm.in.file.handle = create_parm.out.file.handle;
218         
219         req = smb2_close_send(tree, &close_parm);
220         composite_continue_smb2(ctx, req, continue_close, ctx);
221 }
222
223 /*
224   composite SMB2 rmdir call
225 */
226 struct composite_context *smb2_composite_rmdir_send(struct smb2_tree *tree, 
227                                                     struct smb_rmdir *io)
228 {
229         struct composite_context *ctx;
230         struct smb2_create create_parm;
231         struct smb2_request *req;
232
233         ctx = composite_create(tree, tree->session->transport->socket->event.ctx);
234         if (ctx == NULL) return NULL;
235
236         ZERO_STRUCT(create_parm);
237         create_parm.in.desired_access     = SEC_STD_DELETE;
238         create_parm.in.create_disposition = NTCREATEX_DISP_OPEN;
239         create_parm.in.share_access = 
240                 NTCREATEX_SHARE_ACCESS_DELETE|
241                 NTCREATEX_SHARE_ACCESS_READ|
242                 NTCREATEX_SHARE_ACCESS_WRITE;
243         create_parm.in.create_options = 
244                 NTCREATEX_OPTIONS_DIRECTORY |
245                 NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
246         create_parm.in.fname = io->in.path;
247         if (create_parm.in.fname[0] == '\\') {
248                 create_parm.in.fname++;
249         }
250
251         req = smb2_create_send(tree, &create_parm);
252
253         composite_continue_smb2(ctx, req, continue_rmdir, ctx);
254         return ctx;
255 }
256
257
258 /*
259   composite rmdir call - sync interface
260 */
261 NTSTATUS smb2_composite_rmdir(struct smb2_tree *tree, struct smb_rmdir *io)
262 {
263         struct composite_context *c = smb2_composite_rmdir_send(tree, io);
264         return composite_wait_free(c);
265 }
266
267
268 /*
269   continue after the setfileinfo in a composite setpathinfo
270  */
271 static void continue_setpathinfo_close(struct smb2_request *req)
272 {
273         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
274                                                         struct composite_context);
275         struct smb2_tree *tree = req->tree;
276         struct smb2_close close_parm;
277         NTSTATUS status;
278         union smb_setfileinfo *io2 = talloc_get_type(ctx->private_data, 
279                                                      union smb_setfileinfo);
280
281         status = smb2_setinfo_recv(req);
282         if (!NT_STATUS_IS_OK(status)) {
283                 composite_error(ctx, status);
284                 return;
285         }
286
287         ZERO_STRUCT(close_parm);
288         close_parm.in.file.handle = io2->generic.in.file.handle;
289         
290         req = smb2_close_send(tree, &close_parm);
291         composite_continue_smb2(ctx, req, continue_close, ctx);
292 }
293
294
295 /*
296   continue after the create in a composite setpathinfo
297  */
298 static void continue_setpathinfo(struct smb2_request *req)
299 {
300         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
301                                                         struct composite_context);
302         struct smb2_tree *tree = req->tree;
303         struct smb2_create create_parm;
304         NTSTATUS status;
305         union smb_setfileinfo *io2 = talloc_get_type(ctx->private_data, 
306                                                      union smb_setfileinfo);
307
308         status = smb2_create_recv(req, ctx, &create_parm);
309         if (!NT_STATUS_IS_OK(status)) {
310                 composite_error(ctx, status);
311                 return;
312         }
313
314         io2->generic.in.file.handle = create_parm.out.file.handle;
315
316         req = smb2_setinfo_file_send(tree, io2);
317         composite_continue_smb2(ctx, req, continue_setpathinfo_close, ctx);
318 }
319
320
321 /*
322   composite SMB2 setpathinfo call
323 */
324 struct composite_context *smb2_composite_setpathinfo_send(struct smb2_tree *tree, 
325                                                           union smb_setfileinfo *io)
326 {
327         struct composite_context *ctx;
328         struct smb2_create create_parm;
329         struct smb2_request *req;
330         union smb_setfileinfo *io2;
331
332         ctx = composite_create(tree, tree->session->transport->socket->event.ctx);
333         if (ctx == NULL) return NULL;
334
335         ZERO_STRUCT(create_parm);
336         create_parm.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
337         create_parm.in.create_disposition = NTCREATEX_DISP_OPEN;
338         create_parm.in.share_access = 
339                 NTCREATEX_SHARE_ACCESS_DELETE|
340                 NTCREATEX_SHARE_ACCESS_READ|
341                 NTCREATEX_SHARE_ACCESS_WRITE;
342         create_parm.in.create_options = 0;
343         create_parm.in.fname = io->generic.in.file.path;
344         if (create_parm.in.fname[0] == '\\') {
345                 create_parm.in.fname++;
346         }
347
348         req = smb2_create_send(tree, &create_parm);
349
350         io2 = talloc(ctx, union smb_setfileinfo);
351         if (composite_nomem(io2, ctx)) {
352                 return ctx;
353         }
354         *io2 = *io;
355
356         ctx->private_data = io2;
357
358         composite_continue_smb2(ctx, req, continue_setpathinfo, ctx);
359         return ctx;
360 }
361
362
363 /*
364   composite setpathinfo call
365  */
366 NTSTATUS smb2_composite_setpathinfo(struct smb2_tree *tree, union smb_setfileinfo *io)
367 {
368         struct composite_context *c = smb2_composite_setpathinfo_send(tree, io);
369         return composite_wait_free(c);  
370 }