0a5b56b90d747da7a87cfe3c4ef6b4da562e5852
[jelmer/samba4-debian.git] / source / libcli / smb_composite / appendacl.c
1 #include "includes.h"
2 #include "libcli/raw/libcliraw.h"
3 #include "libcli/composite/composite.h"
4 #include "libcli/security/proto.h"
5 #include "libcli/smb_composite/smb_composite.h"
6
7 /* the stages of this call */
8 enum appendacl_stage {APPENDACL_OPENPATH, APPENDACL_GET, 
9                        APPENDACL_SET, APPENDACL_GETAGAIN, APPENDACL_CLOSEPATH};
10
11 static void appendacl_handler(struct smbcli_request *req);
12
13 struct appendacl_state {
14         enum appendacl_stage stage;
15         struct smb_composite_appendacl *io;
16
17         union smb_open *io_open;
18         union smb_setfileinfo *io_setfileinfo;
19         union smb_fileinfo *io_fileinfo;
20
21         struct smbcli_request *req;
22 };
23
24
25 static NTSTATUS appendacl_open(struct composite_context *c, 
26                               struct smb_composite_appendacl *io)
27 {
28         struct appendacl_state *state = talloc_get_type(c->private_data, struct appendacl_state);
29         struct smbcli_tree *tree = state->req->tree;
30         NTSTATUS status;
31
32         status = smb_raw_open_recv(state->req, c, state->io_open);
33         NT_STATUS_NOT_OK_RETURN(status);
34
35         /* setup structures for getting fileinfo */
36         state->io_fileinfo = talloc(c, union smb_fileinfo);
37         NT_STATUS_HAVE_NO_MEMORY(state->io_fileinfo);
38         
39         state->io_fileinfo->query_secdesc.level = RAW_FILEINFO_SEC_DESC;
40         state->io_fileinfo->query_secdesc.in.fnum = state->io_open->ntcreatex.out.fnum;
41         state->io_fileinfo->query_secdesc.secinfo_flags = SECINFO_DACL;
42
43         state->req = smb_raw_fileinfo_send(tree, state->io_fileinfo);
44         NT_STATUS_HAVE_NO_MEMORY(state->req);
45
46         /* set the handler */
47         state->req->async.fn = appendacl_handler;
48         state->req->async.private = c;
49         state->stage = APPENDACL_GET;
50         
51         talloc_free (state->io_open);
52
53         return NT_STATUS_OK;
54 }
55
56 static NTSTATUS appendacl_get(struct composite_context *c, 
57                                struct smb_composite_appendacl *io)
58 {
59         struct appendacl_state *state = talloc_get_type(c->private_data, struct appendacl_state);
60         struct smbcli_tree *tree = state->req->tree;
61         int i;
62         NTSTATUS status;
63         
64         status = smb_raw_fileinfo_recv(state->req, state->io_fileinfo, state->io_fileinfo);
65         NT_STATUS_NOT_OK_RETURN(status);
66         
67         /* setup structures for setting fileinfo */
68         state->io_setfileinfo = talloc(c, union smb_setfileinfo);
69         NT_STATUS_HAVE_NO_MEMORY(state->io_setfileinfo);
70         
71         state->io_setfileinfo->set_secdesc.level            = RAW_SFILEINFO_SEC_DESC;
72         state->io_setfileinfo->set_secdesc.file.fnum        = state->io_fileinfo->query_secdesc.in.fnum;
73         
74         state->io_setfileinfo->set_secdesc.in.secinfo_flags = SECINFO_DACL;
75         state->io_setfileinfo->set_secdesc.in.sd            = state->io_fileinfo->query_secdesc.out.sd;
76         talloc_steal(state->io_setfileinfo, state->io_setfileinfo->set_secdesc.in.sd);
77
78         /* append all aces from io->in.sd->dacl to new security descriptor */
79         if (io->in.sd->dacl != NULL) {
80                 for (i = 0; i < io->in.sd->dacl->num_aces; i++) {
81                         security_descriptor_dacl_add(state->io_setfileinfo->set_secdesc.in.sd,
82                                                      &(io->in.sd->dacl->aces[i]));
83                 }
84         }
85
86         status = smb_raw_setfileinfo(tree, state->io_setfileinfo);
87         NT_STATUS_NOT_OK_RETURN(status);
88
89         state->req = smb_raw_setfileinfo_send(tree, state->io_setfileinfo);
90         NT_STATUS_HAVE_NO_MEMORY(state->req);
91
92         /* call handler when done setting new security descriptor on file */
93         state->req->async.fn = appendacl_handler;
94         state->req->async.private = c;
95         state->stage = APPENDACL_SET;
96
97         talloc_free (state->io_fileinfo);
98
99         return NT_STATUS_OK;
100 }
101
102 static NTSTATUS appendacl_set(struct composite_context *c, 
103                               struct smb_composite_appendacl *io)
104 {
105         struct appendacl_state *state = talloc_get_type(c->private_data, struct appendacl_state);
106         struct smbcli_tree *tree = state->req->tree;
107         NTSTATUS status;
108
109         status = smbcli_request_simple_recv(state->req);
110         NT_STATUS_NOT_OK_RETURN(status);
111
112         /* setup structures for getting fileinfo */
113         state->io_fileinfo = talloc(c, union smb_fileinfo);
114         NT_STATUS_HAVE_NO_MEMORY(state->io_fileinfo);
115         
116
117         state->io_fileinfo->query_secdesc.level = RAW_FILEINFO_SEC_DESC;
118         state->io_fileinfo->query_secdesc.in.fnum = state->io_setfileinfo->set_secdesc.file.fnum;
119         state->io_fileinfo->query_secdesc.secinfo_flags = SECINFO_DACL;
120
121         state->req = smb_raw_fileinfo_send(tree, state->io_fileinfo);
122         NT_STATUS_HAVE_NO_MEMORY(state->req);
123
124         /* set the handler */
125         state->req->async.fn = appendacl_handler;
126         state->req->async.private = c;
127         state->stage = APPENDACL_GETAGAIN;
128         
129         talloc_free (state->io_setfileinfo);
130
131         return NT_STATUS_OK;
132 }
133
134
135 static NTSTATUS appendacl_getagain(struct composite_context *c, 
136                                    struct smb_composite_appendacl *io)
137 {
138         struct appendacl_state *state = talloc_get_type(c->private_data, struct appendacl_state);
139         struct smbcli_tree *tree = state->req->tree;
140         union smb_close *io_close;
141         NTSTATUS status;
142         
143         status = smb_raw_fileinfo_recv(state->req, c, state->io_fileinfo);
144         NT_STATUS_NOT_OK_RETURN(status);
145
146         io->out.sd = state->io_fileinfo->query_secdesc.out.sd;
147
148         /* setup structures for close */
149         io_close = talloc(c, union smb_close);
150         NT_STATUS_HAVE_NO_MEMORY(io_close);
151         
152         io_close->close.level = RAW_CLOSE_CLOSE;
153         io_close->close.in.fnum = state->io_fileinfo->query_secdesc.in.fnum;
154         io_close->close.in.write_time = 0;
155
156         state->req = smb_raw_close_send(tree, io_close);
157         NT_STATUS_HAVE_NO_MEMORY(state->req);
158
159         /* call the handler */
160         state->req->async.fn = appendacl_handler;
161         state->req->async.private = c;
162         state->stage = APPENDACL_CLOSEPATH;
163
164         talloc_free (state->io_fileinfo);
165
166         return NT_STATUS_OK;
167 }
168
169
170
171 static NTSTATUS appendacl_close(struct composite_context *c, 
172                                 struct smb_composite_appendacl *io)
173 {
174         struct appendacl_state *state = talloc_get_type(c->private_data, struct appendacl_state);
175         NTSTATUS status;
176
177         status = smbcli_request_simple_recv(state->req);
178         NT_STATUS_NOT_OK_RETURN(status);
179         
180         c->state = COMPOSITE_STATE_DONE;
181
182         return NT_STATUS_OK;
183 }
184
185 /*
186   handler for completion of a sub-request in appendacl
187 */
188 static void appendacl_handler(struct smbcli_request *req)
189 {
190         struct composite_context *c = req->async.private;
191         struct appendacl_state *state = talloc_get_type(c->private_data, struct appendacl_state);
192
193         /* when this handler is called, the stage indicates what
194            call has just finished */
195         switch (state->stage) {
196         case APPENDACL_OPENPATH:
197                 c->status = appendacl_open(c, state->io);
198                 break;
199
200         case APPENDACL_GET:
201                 c->status = appendacl_get(c, state->io);
202                 break;
203
204         case APPENDACL_SET:
205                 c->status = appendacl_set(c, state->io);
206                 break;
207
208         case APPENDACL_GETAGAIN:
209                 c->status = appendacl_getagain(c, state->io);
210                 break;
211
212         case APPENDACL_CLOSEPATH:
213                 c->status = appendacl_close(c, state->io);
214                 break;
215         }
216
217         /* We should get here if c->state >= SMBCLI_REQUEST_DONE */
218         if (!NT_STATUS_IS_OK(c->status)) {
219                 c->state = COMPOSITE_STATE_ERROR;
220         }
221
222         if (c->state >= COMPOSITE_STATE_DONE &&
223             c->async.fn) {
224                 c->async.fn(c);
225         }
226 }
227
228
229 /*
230   composite appendacl call - does an open followed by a number setfileinfo,
231   after that new acls are read with fileinfo, followed by a close
232 */
233 struct composite_context *smb_composite_appendacl_send(struct smbcli_tree *tree, 
234                                                         struct smb_composite_appendacl *io)
235 {
236         struct composite_context *c;
237         struct appendacl_state *state;
238
239         c = talloc_zero(tree, struct composite_context);
240         if (c == NULL) goto failed;
241
242         state = talloc(c, struct appendacl_state);
243         if (state == NULL) goto failed;
244
245         state->io = io;
246
247         c->private_data = state;
248         c->state = COMPOSITE_STATE_IN_PROGRESS;
249         c->event_ctx = tree->session->transport->socket->event.ctx;
250
251         /* setup structures for opening file */
252         state->io_open = talloc_zero(c, union smb_open);
253         if (state->io_open == NULL) goto failed;
254         
255         state->io_open->ntcreatex.level               = RAW_OPEN_NTCREATEX;
256         state->io_open->ntcreatex.in.root_fid = 0;
257         state->io_open->ntcreatex.in.flags            = 0;
258         state->io_open->ntcreatex.in.access_mask      = SEC_FLAG_MAXIMUM_ALLOWED;
259         state->io_open->ntcreatex.in.file_attr        = FILE_ATTRIBUTE_NORMAL;
260         state->io_open->ntcreatex.in.share_access     = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
261         state->io_open->ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
262         state->io_open->ntcreatex.in.impersonation    = NTCREATEX_IMPERSONATION_ANONYMOUS;
263         state->io_open->ntcreatex.in.security_flags   = 0;
264         state->io_open->ntcreatex.in.fname            = io->in.fname;
265
266         /* send the open on its way */
267         state->req = smb_raw_open_send(tree, state->io_open);
268         if (state->req == NULL) goto failed;
269
270         /* setup the callback handler */
271         state->req->async.fn = appendacl_handler;
272         state->req->async.private = c;
273         state->stage = APPENDACL_OPENPATH;
274
275         return c;
276
277 failed:
278         talloc_free(c);
279         return NULL;
280 }
281
282
283 /*
284   composite appendacl call - recv side
285 */
286 NTSTATUS smb_composite_appendacl_recv(struct composite_context *c, TALLOC_CTX *mem_ctx)
287 {
288         NTSTATUS status;
289
290         status = composite_wait(c);
291
292         if (NT_STATUS_IS_OK(status)) {
293                 struct appendacl_state *state = talloc_get_type(c->private_data, struct appendacl_state);
294                 state->io->out.sd = security_descriptor_copy (mem_ctx, state->io->out.sd);
295         }
296
297         talloc_free(c);
298         return status;
299 }
300
301
302 /*
303   composite appendacl call - sync interface
304 */
305 NTSTATUS smb_composite_appendacl(struct smbcli_tree *tree, 
306                                 TALLOC_CTX *mem_ctx,
307                                 struct smb_composite_appendacl *io)
308 {
309         struct composite_context *c = smb_composite_appendacl_send(tree, io);
310         return smb_composite_appendacl_recv(c, mem_ctx);
311 }
312