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