1 /*
2    Unix SMB/CIFS implementation.
3    smb2 lib
4    Copyright (C) Jeremy Allison 2013
5    Copyright (C) Volker Lendecke 2013
6    Copyright (C) Stefan Metzmacher 2013
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 /*
23  This code is a thin wrapper around the existing
24  cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
25  but allows the handles to be mapped to uint16_t fnums,
26  which are easier for smbclient to use.
27 */
28 
29 #include "includes.h"
30 #include "client.h"
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
34 #include "trans2.h"
35 #include "clirap.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "../librpc/gen_ndr/ndr_security.h"
41 #include "lib/util_ea.h"
42 #include "librpc/gen_ndr/ndr_ioctl.h"
43 #include "ntioctl.h"
44 #include "librpc/gen_ndr/ndr_quota.h"
45 
46 struct smb2_hnd {
47 	uint64_t fid_persistent;
48 	uint64_t fid_volatile;
49 };
50 
51 /*
52  * Handle mapping code.
53  */
54 
55 /***************************************************************
56  Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
57  Ensures handle is owned by cli struct.
58 ***************************************************************/
59 
map_smb2_handle_to_fnum(struct cli_state * cli,const struct smb2_hnd * ph,uint16_t * pfnum)60 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
61 				const struct smb2_hnd *ph,	/* In */
62 				uint16_t *pfnum)		/* Out */
63 {
64 	int ret;
65 	struct idr_context *idp = cli->smb2.open_handles;
66 	struct smb2_hnd *owned_h = talloc_memdup(cli,
67 						ph,
68 						sizeof(struct smb2_hnd));
69 
70 	if (owned_h == NULL) {
71 		return NT_STATUS_NO_MEMORY;
72 	}
73 
74 	if (idp == NULL) {
75 		/* Lazy init */
76 		cli->smb2.open_handles = idr_init(cli);
77 		if (cli->smb2.open_handles == NULL) {
78 			TALLOC_FREE(owned_h);
79 			return NT_STATUS_NO_MEMORY;
80 		}
81 		idp = cli->smb2.open_handles;
82 	}
83 
84 	ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
85 	if (ret == -1) {
86 		TALLOC_FREE(owned_h);
87 		return NT_STATUS_NO_MEMORY;
88 	}
89 
90 	*pfnum = (uint16_t)ret;
91 	return NT_STATUS_OK;
92 }
93 
94 /***************************************************************
95  Return the smb2_hnd pointer associated with the given fnum.
96 ***************************************************************/
97 
map_fnum_to_smb2_handle(struct cli_state * cli,uint16_t fnum,struct smb2_hnd ** pph)98 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
99 				uint16_t fnum,		/* In */
100 				struct smb2_hnd **pph)	/* Out */
101 {
102 	struct idr_context *idp = cli->smb2.open_handles;
103 
104 	if (idp == NULL) {
105 		return NT_STATUS_INVALID_PARAMETER;
106 	}
107 	*pph = (struct smb2_hnd *)idr_find(idp, fnum);
108 	if (*pph == NULL) {
109 		return NT_STATUS_INVALID_HANDLE;
110 	}
111 	return NT_STATUS_OK;
112 }
113 
114 /***************************************************************
115  Delete the fnum to smb2_hnd mapping. Zeros out handle on
116  successful return.
117 ***************************************************************/
118 
delete_smb2_handle_mapping(struct cli_state * cli,struct smb2_hnd ** pph,uint16_t fnum)119 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
120 				struct smb2_hnd **pph,	/* In */
121 				uint16_t fnum)			/* In */
122 {
123 	struct idr_context *idp = cli->smb2.open_handles;
124 	struct smb2_hnd *ph;
125 
126 	if (idp == NULL) {
127 		return NT_STATUS_INVALID_PARAMETER;
128 	}
129 
130 	ph = (struct smb2_hnd *)idr_find(idp, fnum);
131 	if (ph != *pph) {
132 		return NT_STATUS_INVALID_PARAMETER;
133 	}
134 	idr_remove(idp, fnum);
135 	TALLOC_FREE(*pph);
136 	return NT_STATUS_OK;
137 }
138 
139 /***************************************************************
140  Oplock mapping code.
141 ***************************************************************/
142 
flags_to_smb2_oplock(uint32_t create_flags)143 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
144 {
145 	if (create_flags & REQUEST_BATCH_OPLOCK) {
146 		return SMB2_OPLOCK_LEVEL_BATCH;
147 	} else if (create_flags & REQUEST_OPLOCK) {
148 		return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
149 	}
150 
151 	/* create_flags doesn't do a level2 request. */
152 	return SMB2_OPLOCK_LEVEL_NONE;
153 }
154 
155 /***************************************************************
156  Small wrapper that allows SMB2 create to return a uint16_t fnum.
157 ***************************************************************/
158 
159 struct cli_smb2_create_fnum_state {
160 	struct cli_state *cli;
161 	struct smb2_create_blobs in_cblobs;
162 	struct smb2_create_blobs out_cblobs;
163 	struct smb_create_returns cr;
164 	uint16_t fnum;
165 	struct tevent_req *subreq;
166 };
167 
168 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
169 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
170 
cli_smb2_create_fnum_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,const char * fname,uint32_t create_flags,uint32_t impersonation_level,uint32_t desired_access,uint32_t file_attributes,uint32_t share_access,uint32_t create_disposition,uint32_t create_options,const struct smb2_create_blobs * in_cblobs)171 struct tevent_req *cli_smb2_create_fnum_send(
172 	TALLOC_CTX *mem_ctx,
173 	struct tevent_context *ev,
174 	struct cli_state *cli,
175 	const char *fname,
176 	uint32_t create_flags,
177 	uint32_t impersonation_level,
178 	uint32_t desired_access,
179 	uint32_t file_attributes,
180 	uint32_t share_access,
181 	uint32_t create_disposition,
182 	uint32_t create_options,
183 	const struct smb2_create_blobs *in_cblobs)
184 {
185 	struct tevent_req *req, *subreq;
186 	struct cli_smb2_create_fnum_state *state;
187 	size_t fname_len = 0;
188 	const char *startp = NULL;
189 	const char *endp = NULL;
190 	time_t tstamp = (time_t)0;
191 	NTSTATUS status;
192 
193 	req = tevent_req_create(mem_ctx, &state,
194 				struct cli_smb2_create_fnum_state);
195 	if (req == NULL) {
196 		return NULL;
197 	}
198 	state->cli = cli;
199 
200 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
201 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
202 		return tevent_req_post(req, ev);
203 	}
204 
205 	if (cli->backup_intent) {
206 		create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
207 	}
208 
209 	/* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
210 	fname_len = strlen(fname);
211 	if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
212 		size_t len_before_gmt = startp - fname;
213 		size_t len_after_gmt = fname + fname_len - endp;
214 		DATA_BLOB twrp_blob;
215 		NTTIME ntt;
216 
217 		char *new_fname = talloc_array(state, char,
218 				len_before_gmt + len_after_gmt + 1);
219 
220 		if (tevent_req_nomem(new_fname, req)) {
221 			return tevent_req_post(req, ev);
222 		}
223 
224 		memcpy(new_fname, fname, len_before_gmt);
225 		memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
226 		fname = new_fname;
227 		fname_len = len_before_gmt + len_after_gmt;
228 
229 		unix_to_nt_time(&ntt, tstamp);
230 		twrp_blob = data_blob_const((const void *)&ntt, 8);
231 
232 		status = smb2_create_blob_add(
233 			state,
234 			&state->in_cblobs,
235 			SMB2_CREATE_TAG_TWRP,
236 			twrp_blob);
237 		if (!NT_STATUS_IS_OK(status)) {
238 			tevent_req_nterror(req, status);
239 			return tevent_req_post(req, ev);
240 		}
241 	}
242 
243 	if (in_cblobs != NULL) {
244 		uint32_t i;
245 		for (i=0; i<in_cblobs->num_blobs; i++) {
246 			struct smb2_create_blob *b = &in_cblobs->blobs[i];
247 			status = smb2_create_blob_add(
248 				state, &state->in_cblobs, b->tag, b->data);
249 			if (!NT_STATUS_IS_OK(status)) {
250 				tevent_req_nterror(req, status);
251 				return tevent_req_post(req, ev);
252 			}
253 		}
254 	}
255 
256 	/* SMB2 is pickier about pathnames. Ensure it doesn't
257 	   start in a '\' */
258 	if (*fname == '\\') {
259 		fname++;
260 		fname_len--;
261 	}
262 
263 	/* Or end in a '\' */
264 	if (fname_len > 0 && fname[fname_len-1] == '\\') {
265 		char *new_fname = talloc_strdup(state, fname);
266 		if (tevent_req_nomem(new_fname, req)) {
267 			return tevent_req_post(req, ev);
268 		}
269 		new_fname[fname_len-1] = '\0';
270 		fname = new_fname;
271 	}
272 
273 	subreq = smb2cli_create_send(state, ev,
274 				     cli->conn,
275 				     cli->timeout,
276 				     cli->smb2.session,
277 				     cli->smb2.tcon,
278 				     fname,
279 				     flags_to_smb2_oplock(create_flags),
280 				     impersonation_level,
281 				     desired_access,
282 				     file_attributes,
283 				     share_access,
284 				     create_disposition,
285 				     create_options,
286 				     &state->in_cblobs);
287 	if (tevent_req_nomem(subreq, req)) {
288 		return tevent_req_post(req, ev);
289 	}
290 	tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
291 
292 	state->subreq = subreq;
293 	tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
294 
295 	return req;
296 }
297 
cli_smb2_create_fnum_done(struct tevent_req * subreq)298 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
299 {
300 	struct tevent_req *req = tevent_req_callback_data(
301 		subreq, struct tevent_req);
302 	struct cli_smb2_create_fnum_state *state = tevent_req_data(
303 		req, struct cli_smb2_create_fnum_state);
304 	struct smb2_hnd h;
305 	NTSTATUS status;
306 
307 	status = smb2cli_create_recv(
308 		subreq,
309 		&h.fid_persistent,
310 		&h.fid_volatile, &state->cr,
311 		state,
312 		&state->out_cblobs);
313 	TALLOC_FREE(subreq);
314 	if (tevent_req_nterror(req, status)) {
315 		return;
316 	}
317 
318 	status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
319 	if (tevent_req_nterror(req, status)) {
320 		return;
321 	}
322 	tevent_req_done(req);
323 }
324 
cli_smb2_create_fnum_cancel(struct tevent_req * req)325 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
326 {
327 	struct cli_smb2_create_fnum_state *state = tevent_req_data(
328 		req, struct cli_smb2_create_fnum_state);
329 	return tevent_req_cancel(state->subreq);
330 }
331 
cli_smb2_create_fnum_recv(struct tevent_req * req,uint16_t * pfnum,struct smb_create_returns * cr,TALLOC_CTX * mem_ctx,struct smb2_create_blobs * out_cblobs)332 NTSTATUS cli_smb2_create_fnum_recv(
333 	struct tevent_req *req,
334 	uint16_t *pfnum,
335 	struct smb_create_returns *cr,
336 	TALLOC_CTX *mem_ctx,
337 	struct smb2_create_blobs *out_cblobs)
338 {
339 	struct cli_smb2_create_fnum_state *state = tevent_req_data(
340 		req, struct cli_smb2_create_fnum_state);
341 	NTSTATUS status;
342 
343 	if (tevent_req_is_nterror(req, &status)) {
344 		state->cli->raw_status = status;
345 		return status;
346 	}
347 	if (pfnum != NULL) {
348 		*pfnum = state->fnum;
349 	}
350 	if (cr != NULL) {
351 		*cr = state->cr;
352 	}
353 	if (out_cblobs != NULL) {
354 		*out_cblobs = (struct smb2_create_blobs) {
355 			.num_blobs = state->out_cblobs.num_blobs,
356 			.blobs = talloc_move(
357 				mem_ctx, &state->out_cblobs.blobs),
358 		};
359 	}
360 	state->cli->raw_status = NT_STATUS_OK;
361 	return NT_STATUS_OK;
362 }
363 
cli_smb2_create_fnum(struct cli_state * cli,const char * fname,uint32_t create_flags,uint32_t impersonation_level,uint32_t desired_access,uint32_t file_attributes,uint32_t share_access,uint32_t create_disposition,uint32_t create_options,const struct smb2_create_blobs * in_cblobs,uint16_t * pfid,struct smb_create_returns * cr,TALLOC_CTX * mem_ctx,struct smb2_create_blobs * out_cblobs)364 NTSTATUS cli_smb2_create_fnum(
365 	struct cli_state *cli,
366 	const char *fname,
367 	uint32_t create_flags,
368 	uint32_t impersonation_level,
369 	uint32_t desired_access,
370 	uint32_t file_attributes,
371 	uint32_t share_access,
372 	uint32_t create_disposition,
373 	uint32_t create_options,
374 	const struct smb2_create_blobs *in_cblobs,
375 	uint16_t *pfid,
376 	struct smb_create_returns *cr,
377 	TALLOC_CTX *mem_ctx,
378 	struct smb2_create_blobs *out_cblobs)
379 {
380 	TALLOC_CTX *frame = talloc_stackframe();
381 	struct tevent_context *ev;
382 	struct tevent_req *req;
383 	NTSTATUS status = NT_STATUS_NO_MEMORY;
384 
385 	if (smbXcli_conn_has_async_calls(cli->conn)) {
386 		/*
387 		 * Can't use sync call while an async call is in flight
388 		 */
389 		status = NT_STATUS_INVALID_PARAMETER;
390 		goto fail;
391 	}
392 	ev = samba_tevent_context_init(frame);
393 	if (ev == NULL) {
394 		goto fail;
395 	}
396 	req = cli_smb2_create_fnum_send(
397 		frame,
398 		ev,
399 		cli,
400 		fname,
401 		create_flags,
402 		impersonation_level,
403 		desired_access,
404 		file_attributes,
405 		share_access,
406 		create_disposition,
407 		create_options,
408 		in_cblobs);
409 	if (req == NULL) {
410 		goto fail;
411 	}
412 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
413 		goto fail;
414 	}
415 	status = cli_smb2_create_fnum_recv(req, pfid, cr, mem_ctx, out_cblobs);
416  fail:
417 	TALLOC_FREE(frame);
418 	return status;
419 }
420 
421 /***************************************************************
422  Small wrapper that allows SMB2 close to use a uint16_t fnum.
423 ***************************************************************/
424 
425 struct cli_smb2_close_fnum_state {
426 	struct cli_state *cli;
427 	uint16_t fnum;
428 	struct smb2_hnd *ph;
429 };
430 
431 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
432 
cli_smb2_close_fnum_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum)433 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
434 					    struct tevent_context *ev,
435 					    struct cli_state *cli,
436 					    uint16_t fnum)
437 {
438 	struct tevent_req *req, *subreq;
439 	struct cli_smb2_close_fnum_state *state;
440 	NTSTATUS status;
441 
442 	req = tevent_req_create(mem_ctx, &state,
443 				struct cli_smb2_close_fnum_state);
444 	if (req == NULL) {
445 		return NULL;
446 	}
447 	state->cli = cli;
448 	state->fnum = fnum;
449 
450 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
451 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
452 		return tevent_req_post(req, ev);
453 	}
454 
455 	status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
456 	if (tevent_req_nterror(req, status)) {
457 		return tevent_req_post(req, ev);
458 	}
459 
460 	subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
461 				    cli->smb2.session, cli->smb2.tcon,
462 				    0, state->ph->fid_persistent,
463 				    state->ph->fid_volatile);
464 	if (tevent_req_nomem(subreq, req)) {
465 		return tevent_req_post(req, ev);
466 	}
467 	tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
468 	return req;
469 }
470 
cli_smb2_close_fnum_done(struct tevent_req * subreq)471 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
472 {
473 	struct tevent_req *req = tevent_req_callback_data(
474 		subreq, struct tevent_req);
475 	struct cli_smb2_close_fnum_state *state = tevent_req_data(
476 		req, struct cli_smb2_close_fnum_state);
477 	NTSTATUS status;
478 
479 	status = smb2cli_close_recv(subreq);
480 	if (tevent_req_nterror(req, status)) {
481 		return;
482 	}
483 
484 	/* Delete the fnum -> handle mapping. */
485 	status = delete_smb2_handle_mapping(state->cli, &state->ph,
486 					    state->fnum);
487 	if (tevent_req_nterror(req, status)) {
488 		return;
489 	}
490 	tevent_req_done(req);
491 }
492 
cli_smb2_close_fnum_recv(struct tevent_req * req)493 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
494 {
495 	struct cli_smb2_close_fnum_state *state = tevent_req_data(
496 		req, struct cli_smb2_close_fnum_state);
497 	NTSTATUS status = NT_STATUS_OK;
498 
499 	if (tevent_req_is_nterror(req, &status)) {
500 		state->cli->raw_status = status;
501 	}
502 	tevent_req_received(req);
503 	return status;
504 }
505 
cli_smb2_close_fnum(struct cli_state * cli,uint16_t fnum)506 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
507 {
508 	TALLOC_CTX *frame = talloc_stackframe();
509 	struct tevent_context *ev;
510 	struct tevent_req *req;
511 	NTSTATUS status = NT_STATUS_NO_MEMORY;
512 
513 	if (smbXcli_conn_has_async_calls(cli->conn)) {
514 		/*
515 		 * Can't use sync call while an async call is in flight
516 		 */
517 		status = NT_STATUS_INVALID_PARAMETER;
518 		goto fail;
519 	}
520 	ev = samba_tevent_context_init(frame);
521 	if (ev == NULL) {
522 		goto fail;
523 	}
524 	req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
525 	if (req == NULL) {
526 		goto fail;
527 	}
528 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
529 		goto fail;
530 	}
531 	status = cli_smb2_close_fnum_recv(req);
532  fail:
533 	TALLOC_FREE(frame);
534 	return status;
535 }
536 
537 struct cli_smb2_set_info_fnum_state {
538 	uint8_t dummy;
539 };
540 
541 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq);
542 
cli_smb2_set_info_fnum_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum,uint8_t in_info_type,uint8_t in_info_class,const DATA_BLOB * in_input_buffer,uint32_t in_additional_info)543 struct tevent_req *cli_smb2_set_info_fnum_send(
544 	TALLOC_CTX *mem_ctx,
545 	struct tevent_context *ev,
546 	struct cli_state *cli,
547 	uint16_t fnum,
548 	uint8_t in_info_type,
549 	uint8_t in_info_class,
550 	const DATA_BLOB *in_input_buffer,
551 	uint32_t in_additional_info)
552 {
553 	struct tevent_req *req = NULL, *subreq = NULL;
554 	struct cli_smb2_set_info_fnum_state *state = NULL;
555 	struct smb2_hnd *ph = NULL;
556 	NTSTATUS status;
557 
558 	req = tevent_req_create(
559 		mem_ctx, &state, struct cli_smb2_set_info_fnum_state);
560 	if (req == NULL) {
561 		return NULL;
562 	}
563 
564 	status = map_fnum_to_smb2_handle(cli, fnum, &ph);
565 	if (tevent_req_nterror(req, status)) {
566 		return tevent_req_post(req, ev);
567 	}
568 
569 	subreq = smb2cli_set_info_send(
570 		state,
571 		ev,
572 		cli->conn,
573 		cli->timeout,
574 		cli->smb2.session,
575 		cli->smb2.tcon,
576 		in_info_type,
577 		in_info_class,
578 		in_input_buffer,
579 		in_additional_info,
580 		ph->fid_persistent,
581 		ph->fid_volatile);
582 	if (tevent_req_nomem(subreq, req)) {
583 		return tevent_req_post(req, ev);
584 	}
585 	tevent_req_set_callback(subreq, cli_smb2_set_info_fnum_done, req);
586 	return req;
587 }
588 
cli_smb2_set_info_fnum_done(struct tevent_req * subreq)589 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq)
590 {
591 	NTSTATUS status = smb2cli_set_info_recv(subreq);
592 	tevent_req_simple_finish_ntstatus(subreq, status);
593 }
594 
cli_smb2_set_info_fnum_recv(struct tevent_req * req)595 NTSTATUS cli_smb2_set_info_fnum_recv(struct tevent_req *req)
596 {
597 	return tevent_req_simple_recv_ntstatus(req);
598 }
599 
cli_smb2_set_info_fnum(struct cli_state * cli,uint16_t fnum,uint8_t in_info_type,uint8_t in_info_class,const DATA_BLOB * in_input_buffer,uint32_t in_additional_info)600 NTSTATUS cli_smb2_set_info_fnum(
601 	struct cli_state *cli,
602 	uint16_t fnum,
603 	uint8_t in_info_type,
604 	uint8_t in_info_class,
605 	const DATA_BLOB *in_input_buffer,
606 	uint32_t in_additional_info)
607 {
608 	TALLOC_CTX *frame = talloc_stackframe();
609 	struct tevent_context *ev = NULL;
610 	struct tevent_req *req = NULL;
611 	NTSTATUS status = NT_STATUS_NO_MEMORY;
612 	bool ok;
613 
614 	if (smbXcli_conn_has_async_calls(cli->conn)) {
615 		/*
616 		 * Can't use sync call while an async call is in flight
617 		 */
618 		status = NT_STATUS_INVALID_PARAMETER;
619 		goto fail;
620 	}
621 	ev = samba_tevent_context_init(frame);
622 	if (ev == NULL) {
623 		goto fail;
624 	}
625 	req = cli_smb2_set_info_fnum_send(
626 		frame,
627 		ev,
628 		cli,
629 		fnum,
630 		in_info_type,
631 		in_info_class,
632 		in_input_buffer,
633 		in_additional_info);
634 	if (req == NULL) {
635 		goto fail;
636 	}
637 	ok = tevent_req_poll_ntstatus(req, ev, &status);
638 	if (!ok) {
639 		goto fail;
640 	}
641 	status = cli_smb2_set_info_fnum_recv(req);
642 fail:
643 	TALLOC_FREE(frame);
644 	return status;
645 }
646 
647 struct cli_smb2_delete_on_close_state {
648 	struct cli_state *cli;
649 	uint8_t data[1];
650 	DATA_BLOB inbuf;
651 };
652 
653 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
654 
cli_smb2_delete_on_close_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum,bool flag)655 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
656 					struct tevent_context *ev,
657 					struct cli_state *cli,
658 					uint16_t fnum,
659 					bool flag)
660 {
661 	struct tevent_req *req = NULL;
662 	struct cli_smb2_delete_on_close_state *state = NULL;
663 	struct tevent_req *subreq = NULL;
664 	uint8_t in_info_type;
665 	uint8_t in_file_info_class;
666 
667 	req = tevent_req_create(mem_ctx, &state,
668 				struct cli_smb2_delete_on_close_state);
669 	if (req == NULL) {
670 		return NULL;
671 	}
672 	state->cli = cli;
673 
674 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
675 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
676 		return tevent_req_post(req, ev);
677 	}
678 
679 	/*
680 	 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
681 	 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
682 	 */
683 	in_info_type = 1;
684 	in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
685 	/* Setup data array. */
686 	SCVAL(&state->data[0], 0, flag ? 1 : 0);
687 	state->inbuf.data = &state->data[0];
688 	state->inbuf.length = 1;
689 
690 	subreq = cli_smb2_set_info_fnum_send(
691 		state,
692 		ev,
693 		cli,
694 		fnum,
695 		in_info_type,
696 		in_file_info_class,
697 		&state->inbuf,
698 		0);
699 	if (tevent_req_nomem(subreq, req)) {
700 		return tevent_req_post(req, ev);
701 	}
702 	tevent_req_set_callback(subreq,
703 				cli_smb2_delete_on_close_done,
704 				req);
705 	return req;
706 }
707 
cli_smb2_delete_on_close_done(struct tevent_req * subreq)708 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
709 {
710 	NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
711 	tevent_req_simple_finish_ntstatus(subreq, status);
712 }
713 
cli_smb2_delete_on_close_recv(struct tevent_req * req)714 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
715 {
716 	struct cli_smb2_delete_on_close_state *state =
717 		tevent_req_data(req,
718 		struct cli_smb2_delete_on_close_state);
719 	NTSTATUS status;
720 
721 	if (tevent_req_is_nterror(req, &status)) {
722 		state->cli->raw_status = status;
723 		tevent_req_received(req);
724 		return status;
725 	}
726 
727 	state->cli->raw_status = NT_STATUS_OK;
728 	tevent_req_received(req);
729 	return NT_STATUS_OK;
730 }
731 
cli_smb2_delete_on_close(struct cli_state * cli,uint16_t fnum,bool flag)732 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
733 {
734 	TALLOC_CTX *frame = talloc_stackframe();
735 	struct tevent_context *ev;
736 	struct tevent_req *req;
737 	NTSTATUS status = NT_STATUS_NO_MEMORY;
738 
739 	if (smbXcli_conn_has_async_calls(cli->conn)) {
740 		/*
741 		 * Can't use sync call while an async call is in flight
742 		 */
743 		status = NT_STATUS_INVALID_PARAMETER;
744 		goto fail;
745 	}
746 	ev = samba_tevent_context_init(frame);
747 	if (ev == NULL) {
748 		goto fail;
749 	}
750 	req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
751 	if (req == NULL) {
752 		goto fail;
753 	}
754 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
755 		goto fail;
756 	}
757 	status = cli_smb2_delete_on_close_recv(req);
758  fail:
759 	TALLOC_FREE(frame);
760 	return status;
761 }
762 
763 /***************************************************************
764  Small wrapper that allows SMB2 to create a directory
765  Synchronous only.
766 ***************************************************************/
767 
cli_smb2_mkdir(struct cli_state * cli,const char * dname)768 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
769 {
770 	NTSTATUS status;
771 	uint16_t fnum;
772 
773 	if (smbXcli_conn_has_async_calls(cli->conn)) {
774 		/*
775 		 * Can't use sync call while an async call is in flight
776 		 */
777 		return NT_STATUS_INVALID_PARAMETER;
778 	}
779 
780 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
781 		return NT_STATUS_INVALID_PARAMETER;
782 	}
783 
784 	status = cli_smb2_create_fnum(cli,
785 			dname,
786 			0,			/* create_flags */
787 			SMB2_IMPERSONATION_IMPERSONATION,
788 			FILE_READ_ATTRIBUTES,	/* desired_access */
789 			FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
790 			FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
791 			FILE_CREATE,		/* create_disposition */
792 			FILE_DIRECTORY_FILE,	/* create_options */
793 			NULL,
794 			&fnum,
795 			NULL,
796 			NULL,
797 			NULL);
798 
799 	if (!NT_STATUS_IS_OK(status)) {
800 		return status;
801 	}
802 	return cli_smb2_close_fnum(cli, fnum);
803 }
804 
805 struct cli_smb2_rmdir_state {
806 	struct tevent_context *ev;
807 	struct cli_state *cli;
808 	const char *dname;
809 	const struct smb2_create_blobs *in_cblobs;
810 	uint16_t fnum;
811 	NTSTATUS status;
812 };
813 
814 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq);
815 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq);
816 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq);
817 static void cli_smb2_rmdir_closed(struct tevent_req *subreq);
818 
cli_smb2_rmdir_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,const char * dname,const struct smb2_create_blobs * in_cblobs)819 struct tevent_req *cli_smb2_rmdir_send(
820 	TALLOC_CTX *mem_ctx,
821 	struct tevent_context *ev,
822 	struct cli_state *cli,
823 	const char *dname,
824 	const struct smb2_create_blobs *in_cblobs)
825 {
826 	struct tevent_req *req = NULL, *subreq = NULL;
827 	struct cli_smb2_rmdir_state *state = NULL;
828 
829 	req = tevent_req_create(mem_ctx, &state, struct cli_smb2_rmdir_state);
830 	if (req == NULL) {
831 		return NULL;
832 	}
833 	state->ev = ev;
834 	state->cli = cli;
835 	state->dname = dname;
836 	state->in_cblobs = in_cblobs;
837 
838 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
839 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
840 		return tevent_req_post(req, ev);
841 	}
842 
843 	subreq = cli_smb2_create_fnum_send(
844 		state,
845 		state->ev,
846 		state->cli,
847 		state->dname,
848 		0,			/* create_flags */
849 		SMB2_IMPERSONATION_IMPERSONATION,
850 		DELETE_ACCESS,		/* desired_access */
851 		FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
852 		FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
853 		FILE_OPEN,		/* create_disposition */
854 		FILE_DIRECTORY_FILE,	/* create_options */
855 		state->in_cblobs);	/* in_cblobs */
856 	if (tevent_req_nomem(subreq, req)) {
857 		return tevent_req_post(req, ev);
858 	}
859 	tevent_req_set_callback(subreq, cli_smb2_rmdir_opened1, req);
860 	return req;
861 }
862 
cli_smb2_rmdir_opened1(struct tevent_req * subreq)863 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq)
864 {
865 	struct tevent_req *req = tevent_req_callback_data(
866 		subreq, struct tevent_req);
867 	struct cli_smb2_rmdir_state *state = tevent_req_data(
868 		req, struct cli_smb2_rmdir_state);
869 	NTSTATUS status;
870 
871 	status = cli_smb2_create_fnum_recv(
872 		subreq, &state->fnum, NULL, NULL, NULL);
873 	TALLOC_FREE(subreq);
874 
875 	if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
876 		/*
877 		 * Naive option to match our SMB1 code. Assume the
878 		 * symlink path that tripped us up was the last
879 		 * component and try again. Eventually we will have to
880 		 * deal with the returned path unprocessed component. JRA.
881 		 */
882 		subreq = cli_smb2_create_fnum_send(
883 			state,
884 			state->ev,
885 			state->cli,
886 			state->dname,
887 			0,			/* create_flags */
888 			SMB2_IMPERSONATION_IMPERSONATION,
889 			DELETE_ACCESS,		/* desired_access */
890 			FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
891 			FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
892 			FILE_OPEN,		/* create_disposition */
893 			FILE_DIRECTORY_FILE|
894 			FILE_DELETE_ON_CLOSE|
895 			FILE_OPEN_REPARSE_POINT, /* create_options */
896 			state->in_cblobs);	 /* in_cblobs */
897 		if (tevent_req_nomem(subreq, req)) {
898 			return;
899 		}
900 		tevent_req_set_callback(subreq, cli_smb2_rmdir_opened2, req);
901 		return;
902 	}
903 
904 	if (tevent_req_nterror(req, status)) {
905 		return;
906 	}
907 
908 	subreq = cli_smb2_delete_on_close_send(
909 		state, state->ev, state->cli, state->fnum, true);
910 	if (tevent_req_nomem(subreq, req)) {
911 		return;
912 	}
913 	tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
914 }
915 
cli_smb2_rmdir_opened2(struct tevent_req * subreq)916 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq)
917 {
918 	struct tevent_req *req = tevent_req_callback_data(
919 		subreq, struct tevent_req);
920 	struct cli_smb2_rmdir_state *state = tevent_req_data(
921 		req, struct cli_smb2_rmdir_state);
922 	NTSTATUS status;
923 
924 	status = cli_smb2_create_fnum_recv(
925 		subreq, &state->fnum, NULL, NULL, NULL);
926 	TALLOC_FREE(subreq);
927 	if (tevent_req_nterror(req, status)) {
928 		return;
929 	}
930 
931 	subreq = cli_smb2_delete_on_close_send(
932 		state, state->ev, state->cli, state->fnum, true);
933 	if (tevent_req_nomem(subreq, req)) {
934 		return;
935 	}
936 	tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
937 }
938 
cli_smb2_rmdir_disp_set(struct tevent_req * subreq)939 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq)
940 {
941 	struct tevent_req *req = tevent_req_callback_data(
942 		subreq, struct tevent_req);
943 	struct cli_smb2_rmdir_state *state = tevent_req_data(
944 		req, struct cli_smb2_rmdir_state);
945 
946 	state->status = cli_smb2_delete_on_close_recv(subreq);
947 	TALLOC_FREE(subreq);
948 
949 	/*
950 	 * Close the fd even if the set_disp failed
951 	 */
952 
953 	subreq = cli_smb2_close_fnum_send(
954 		state, state->ev, state->cli, state->fnum);
955 	if (tevent_req_nomem(subreq, req)) {
956 		return;
957 	}
958 	tevent_req_set_callback(subreq, cli_smb2_rmdir_closed, req);
959 }
960 
cli_smb2_rmdir_closed(struct tevent_req * subreq)961 static void cli_smb2_rmdir_closed(struct tevent_req *subreq)
962 {
963 	NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
964 	tevent_req_simple_finish_ntstatus(subreq, status);
965 }
966 
cli_smb2_rmdir_recv(struct tevent_req * req)967 NTSTATUS cli_smb2_rmdir_recv(struct tevent_req *req)
968 {
969 	struct cli_smb2_rmdir_state *state = tevent_req_data(
970 		req, struct cli_smb2_rmdir_state);
971 	NTSTATUS status;
972 
973 	if (tevent_req_is_nterror(req, &status)) {
974 		return status;
975 	}
976 	return state->status;
977 }
978 
cli_smb2_rmdir(struct cli_state * cli,const char * dname,const struct smb2_create_blobs * in_cblobs)979 NTSTATUS cli_smb2_rmdir(
980 	struct cli_state *cli,
981 	const char *dname,
982 	const struct smb2_create_blobs *in_cblobs)
983 {
984 	TALLOC_CTX *frame = talloc_stackframe();
985 	struct tevent_context *ev;
986 	struct tevent_req *req;
987 	NTSTATUS status = NT_STATUS_NO_MEMORY;
988 	bool ok;
989 
990 	if (smbXcli_conn_has_async_calls(cli->conn)) {
991 		/*
992 		 * Can't use sync call while an async call is in flight
993 		 */
994 		status = NT_STATUS_INVALID_PARAMETER;
995 		goto fail;
996 	}
997 	ev = samba_tevent_context_init(frame);
998 	if (ev == NULL) {
999 		goto fail;
1000 	}
1001 	req = cli_smb2_rmdir_send(frame, ev, cli, dname, in_cblobs);
1002 	if (req == NULL) {
1003 		goto fail;
1004 	}
1005 	ok = tevent_req_poll_ntstatus(req, ev, &status);
1006 	if (!ok) {
1007 		goto fail;
1008 	}
1009 	status = cli_smb2_rmdir_recv(req);
1010 fail:
1011 	cli->raw_status = status;
1012 	TALLOC_FREE(frame);
1013 	return status;
1014 }
1015 
1016 /***************************************************************
1017  Small wrapper that allows SMB2 to unlink a pathname.
1018  Synchronous only.
1019 ***************************************************************/
1020 
1021 struct cli_smb2_unlink_state {
1022 	struct tevent_context *ev;
1023 	struct cli_state *cli;
1024 	const char *fname;
1025 	const struct smb2_create_blobs *in_cblobs;
1026 };
1027 
1028 static void cli_smb2_unlink_opened1(struct tevent_req *subreq);
1029 static void cli_smb2_unlink_opened2(struct tevent_req *subreq);
1030 static void cli_smb2_unlink_closed(struct tevent_req *subreq);
1031 
cli_smb2_unlink_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,const char * fname,const struct smb2_create_blobs * in_cblobs)1032 struct tevent_req *cli_smb2_unlink_send(
1033 	TALLOC_CTX *mem_ctx,
1034 	struct tevent_context *ev,
1035 	struct cli_state *cli,
1036 	const char *fname,
1037 	const struct smb2_create_blobs *in_cblobs)
1038 {
1039 	struct tevent_req *req = NULL, *subreq = NULL;
1040 	struct cli_smb2_unlink_state *state = NULL;
1041 
1042 	req = tevent_req_create(mem_ctx, &state, struct cli_smb2_unlink_state);
1043 	if (req == NULL) {
1044 		return NULL;
1045 	}
1046 	state->ev = ev;
1047 	state->cli = cli;
1048 	state->fname = fname;
1049 	state->in_cblobs = in_cblobs;
1050 
1051 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1052 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1053 		return tevent_req_post(req, ev);
1054 	}
1055 
1056 	subreq = cli_smb2_create_fnum_send(
1057 		state,		/* mem_ctx */
1058 		state->ev,	/* tevent_context */
1059 		state->cli,	/* cli_struct */
1060 		state->fname,	/* filename */
1061 		0,			/* create_flags */
1062 		SMB2_IMPERSONATION_IMPERSONATION,
1063 		DELETE_ACCESS,		/* desired_access */
1064 		FILE_ATTRIBUTE_NORMAL, /* file attributes */
1065 		FILE_SHARE_READ|
1066 		FILE_SHARE_WRITE|
1067 		FILE_SHARE_DELETE, /* share_access */
1068 		FILE_OPEN,		/* create_disposition */
1069 		FILE_DELETE_ON_CLOSE,	/* create_options */
1070 		state->in_cblobs);	/* in_cblobs */
1071 	if (tevent_req_nomem(subreq, req)) {
1072 		return tevent_req_post(req, ev);
1073 	}
1074 	tevent_req_set_callback(subreq, cli_smb2_unlink_opened1, req);
1075 	return req;
1076 }
1077 
cli_smb2_unlink_opened1(struct tevent_req * subreq)1078 static void cli_smb2_unlink_opened1(struct tevent_req *subreq)
1079 {
1080 	struct tevent_req *req = tevent_req_callback_data(
1081 		subreq, struct tevent_req);
1082 	struct cli_smb2_unlink_state *state = tevent_req_data(
1083 		req, struct cli_smb2_unlink_state);
1084 	uint16_t fnum;
1085 	NTSTATUS status;
1086 
1087 	status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1088 	TALLOC_FREE(subreq);
1089 
1090 	if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1091 		/*
1092 		 * Naive option to match our SMB1 code. Assume the
1093 		 * symlink path that tripped us up was the last
1094 		 * component and try again. Eventually we will have to
1095 		 * deal with the returned path unprocessed component. JRA.
1096 		 */
1097 		subreq = cli_smb2_create_fnum_send(
1098 			state,		/* mem_ctx */
1099 			state->ev,	/* tevent_context */
1100 			state->cli,	/* cli_struct */
1101 			state->fname,	/* filename */
1102 			0,			/* create_flags */
1103 			SMB2_IMPERSONATION_IMPERSONATION,
1104 			DELETE_ACCESS,		/* desired_access */
1105 			FILE_ATTRIBUTE_NORMAL, /* file attributes */
1106 			FILE_SHARE_READ|
1107 			FILE_SHARE_WRITE|
1108 			FILE_SHARE_DELETE, /* share_access */
1109 			FILE_OPEN,		/* create_disposition */
1110 			FILE_DELETE_ON_CLOSE|
1111 			FILE_OPEN_REPARSE_POINT, /* create_options */
1112 			state->in_cblobs);	 /* in_cblobs */
1113 		if (tevent_req_nomem(subreq, req)) {
1114 			return;
1115 		}
1116 		tevent_req_set_callback(subreq, cli_smb2_unlink_opened2, req);
1117 		return;
1118 	}
1119 
1120 	if (tevent_req_nterror(req, status)) {
1121 		return;
1122 	}
1123 
1124 	subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1125 	if (tevent_req_nomem(subreq, req)) {
1126 		return;
1127 	}
1128 	tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1129 }
1130 
cli_smb2_unlink_opened2(struct tevent_req * subreq)1131 static void cli_smb2_unlink_opened2(struct tevent_req *subreq)
1132 {
1133 	struct tevent_req *req = tevent_req_callback_data(
1134 		subreq, struct tevent_req);
1135 	struct cli_smb2_unlink_state *state = tevent_req_data(
1136 		req, struct cli_smb2_unlink_state);
1137 	uint16_t fnum;
1138 	NTSTATUS status;
1139 
1140 	status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1141 	TALLOC_FREE(subreq);
1142 	if (tevent_req_nterror(req, status)) {
1143 		return;
1144 	}
1145 
1146 	subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1147 	if (tevent_req_nomem(subreq, req)) {
1148 		return;
1149 	}
1150 	tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1151 }
1152 
cli_smb2_unlink_closed(struct tevent_req * subreq)1153 static void cli_smb2_unlink_closed(struct tevent_req *subreq)
1154 {
1155 	NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1156 	tevent_req_simple_finish_ntstatus(subreq, status);
1157 }
1158 
cli_smb2_unlink_recv(struct tevent_req * req)1159 NTSTATUS cli_smb2_unlink_recv(struct tevent_req *req)
1160 {
1161 	return tevent_req_simple_recv_ntstatus(req);
1162 }
1163 
cli_smb2_unlink(struct cli_state * cli,const char * fname,const struct smb2_create_blobs * in_cblobs)1164 NTSTATUS cli_smb2_unlink(
1165 	struct cli_state *cli,
1166 	const char *fname,
1167 	const struct smb2_create_blobs *in_cblobs)
1168 {
1169 	TALLOC_CTX *frame = talloc_stackframe();
1170 	struct tevent_context *ev;
1171 	struct tevent_req *req;
1172 	NTSTATUS status = NT_STATUS_NO_MEMORY;
1173 	bool ok;
1174 
1175 	if (smbXcli_conn_has_async_calls(cli->conn)) {
1176 		/*
1177 		 * Can't use sync call while an async call is in flight
1178 		 */
1179 		status = NT_STATUS_INVALID_PARAMETER;
1180 		goto fail;
1181 	}
1182 	ev = samba_tevent_context_init(frame);
1183 	if (ev == NULL) {
1184 		goto fail;
1185 	}
1186 	req = cli_smb2_unlink_send(frame, ev, cli, fname, in_cblobs);
1187 	if (req == NULL) {
1188 		goto fail;
1189 	}
1190 	ok = tevent_req_poll_ntstatus(req, ev, &status);
1191 	if (!ok) {
1192 		goto fail;
1193 	}
1194 	status = cli_smb2_unlink_recv(req);
1195 fail:
1196 	cli->raw_status = status;
1197 	TALLOC_FREE(frame);
1198 	return status;
1199 }
1200 
1201 /***************************************************************
1202  Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1203 ***************************************************************/
1204 
parse_finfo_id_both_directory_info(uint8_t * dir_data,uint32_t dir_data_length,struct file_info * finfo,uint32_t * next_offset)1205 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
1206 				uint32_t dir_data_length,
1207 				struct file_info *finfo,
1208 				uint32_t *next_offset)
1209 {
1210 	size_t namelen = 0;
1211 	size_t slen = 0;
1212 	size_t ret = 0;
1213 
1214 	if (dir_data_length < 4) {
1215 		return NT_STATUS_INFO_LENGTH_MISMATCH;
1216 	}
1217 
1218 	*next_offset = IVAL(dir_data, 0);
1219 
1220 	if (*next_offset > dir_data_length) {
1221 		return NT_STATUS_INFO_LENGTH_MISMATCH;
1222 	}
1223 
1224 	if (*next_offset != 0) {
1225 		/* Ensure we only read what in this record. */
1226 		dir_data_length = *next_offset;
1227 	}
1228 
1229 	if (dir_data_length < 105) {
1230 		return NT_STATUS_INFO_LENGTH_MISMATCH;
1231 	}
1232 
1233 	finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
1234 	finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
1235 	finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
1236 	finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
1237 	finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
1238 	finfo->allocated_size = IVAL2_TO_SMB_BIG_UINT(dir_data + 48, 0);
1239 	/* NB. We need to enlarge finfo->mode to be 32-bits. */
1240 	finfo->mode = (uint16_t)IVAL(dir_data + 56, 0);
1241 	finfo->ino = IVAL2_TO_SMB_BIG_UINT(dir_data + 96, 0);
1242 	namelen = IVAL(dir_data + 60,0);
1243 	if (namelen > (dir_data_length - 104)) {
1244 		return NT_STATUS_INFO_LENGTH_MISMATCH;
1245 	}
1246 	slen = CVAL(dir_data + 68, 0);
1247 	if (slen > 24) {
1248 		return NT_STATUS_INFO_LENGTH_MISMATCH;
1249 	}
1250 	ret = pull_string_talloc(finfo,
1251 				dir_data,
1252 				FLAGS2_UNICODE_STRINGS,
1253 				&finfo->short_name,
1254 				dir_data + 70,
1255 				slen,
1256 				STR_UNICODE);
1257 	if (ret == (size_t)-1) {
1258 		/* Bad conversion. */
1259 		return NT_STATUS_INVALID_NETWORK_RESPONSE;
1260 	}
1261 
1262 	ret = pull_string_talloc(finfo,
1263 				dir_data,
1264 				FLAGS2_UNICODE_STRINGS,
1265 				&finfo->name,
1266 				dir_data + 104,
1267 				namelen,
1268 				STR_UNICODE);
1269 	if (ret == (size_t)-1) {
1270 		/* Bad conversion. */
1271 		return NT_STATUS_INVALID_NETWORK_RESPONSE;
1272 	}
1273 
1274 	if (finfo->name == NULL) {
1275 		/* Bad conversion. */
1276 		return NT_STATUS_INVALID_NETWORK_RESPONSE;
1277 	}
1278 
1279 	return NT_STATUS_OK;
1280 }
1281 
1282 /*******************************************************************
1283  Given a filename - get its directory name
1284 ********************************************************************/
1285 
windows_parent_dirname(TALLOC_CTX * mem_ctx,const char * dir,char ** parent,const char ** name)1286 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
1287 				const char *dir,
1288 				char **parent,
1289 				const char **name)
1290 {
1291 	char *p;
1292 	ptrdiff_t len;
1293 
1294 	p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
1295 
1296 	if (p == NULL) {
1297 		if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
1298 			return false;
1299 		}
1300 		if (name) {
1301 			*name = dir;
1302 		}
1303 		return true;
1304 	}
1305 
1306 	len = p-dir;
1307 
1308 	if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
1309 		return false;
1310 	}
1311 	(*parent)[len] = '\0';
1312 
1313 	if (name) {
1314 		*name = p+1;
1315 	}
1316 	return true;
1317 }
1318 
1319 /***************************************************************
1320  Wrapper that allows SMB2 to list a directory.
1321  Synchronous only.
1322 ***************************************************************/
1323 
cli_smb2_list(struct cli_state * cli,const char * pathname,uint16_t attribute,NTSTATUS (* fn)(const char *,struct file_info *,const char *,void *),void * state)1324 NTSTATUS cli_smb2_list(struct cli_state *cli,
1325 			const char *pathname,
1326 			uint16_t attribute,
1327 			NTSTATUS (*fn)(const char *,
1328 				struct file_info *,
1329 				const char *,
1330 				void *),
1331 			void *state)
1332 {
1333 	NTSTATUS status;
1334 	uint16_t fnum = 0xffff;
1335 	char *parent_dir = NULL;
1336 	const char *mask = NULL;
1337 	struct smb2_hnd *ph = NULL;
1338 	bool processed_file = false;
1339 	TALLOC_CTX *frame = talloc_stackframe();
1340 	TALLOC_CTX *subframe = NULL;
1341 	bool mask_has_wild;
1342 	uint32_t max_trans;
1343 	uint32_t max_avail_len;
1344 	bool ok;
1345 
1346 	if (smbXcli_conn_has_async_calls(cli->conn)) {
1347 		/*
1348 		 * Can't use sync call while an async call is in flight
1349 		 */
1350 		status = NT_STATUS_INVALID_PARAMETER;
1351 		goto fail;
1352 	}
1353 
1354 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1355 		status = NT_STATUS_INVALID_PARAMETER;
1356 		goto fail;
1357 	}
1358 
1359 	/* Get the directory name. */
1360 	if (!windows_parent_dirname(frame,
1361 				pathname,
1362 				&parent_dir,
1363 				&mask)) {
1364                 status = NT_STATUS_NO_MEMORY;
1365 		goto fail;
1366         }
1367 
1368 	mask_has_wild = ms_has_wild(mask);
1369 
1370 	status = cli_smb2_create_fnum(cli,
1371 			parent_dir,
1372 			0,			/* create_flags */
1373 			SMB2_IMPERSONATION_IMPERSONATION,
1374 			SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
1375 			FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1376 			FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
1377 			FILE_OPEN,		/* create_disposition */
1378 			FILE_DIRECTORY_FILE,	/* create_options */
1379 			NULL,
1380 			&fnum,
1381 			NULL,
1382 			NULL,
1383 			NULL);
1384 
1385 	if (!NT_STATUS_IS_OK(status)) {
1386 		goto fail;
1387 	}
1388 
1389 	status = map_fnum_to_smb2_handle(cli,
1390 					fnum,
1391 					&ph);
1392 	if (!NT_STATUS_IS_OK(status)) {
1393 		goto fail;
1394 	}
1395 
1396 	/*
1397 	 * ideally, use the max transaction size, but don't send a request
1398 	 * bigger than we have credits available for
1399 	 */
1400 	max_trans = smb2cli_conn_max_trans_size(cli->conn);
1401 	ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
1402 	if (ok) {
1403 		max_trans = MIN(max_trans, max_avail_len);
1404 	}
1405 
1406 	do {
1407 		uint8_t *dir_data = NULL;
1408 		uint32_t dir_data_length = 0;
1409 		uint32_t next_offset = 0;
1410 		subframe = talloc_stackframe();
1411 
1412 		status = smb2cli_query_directory(cli->conn,
1413 					cli->timeout,
1414 					cli->smb2.session,
1415 					cli->smb2.tcon,
1416 					SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
1417 					0,	/* flags */
1418 					0,	/* file_index */
1419 					ph->fid_persistent,
1420 					ph->fid_volatile,
1421 					mask,
1422 					max_trans,
1423 					subframe,
1424 					&dir_data,
1425 					&dir_data_length);
1426 
1427 		if (!NT_STATUS_IS_OK(status)) {
1428 			if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1429 				break;
1430 			}
1431 			goto fail;
1432 		}
1433 
1434 		do {
1435 			struct file_info *finfo = talloc_zero(subframe,
1436 							struct file_info);
1437 
1438 			if (finfo == NULL) {
1439 				status = NT_STATUS_NO_MEMORY;
1440 				goto fail;
1441 			}
1442 
1443 			status = parse_finfo_id_both_directory_info(dir_data,
1444 						dir_data_length,
1445 						finfo,
1446 						&next_offset);
1447 
1448 			if (!NT_STATUS_IS_OK(status)) {
1449 				goto fail;
1450 			}
1451 
1452 			/* Protect against server attack. */
1453 			status = is_bad_finfo_name(cli, finfo);
1454 			if (!NT_STATUS_IS_OK(status)) {
1455 				smbXcli_conn_disconnect(cli->conn, status);
1456 				goto fail;
1457 			}
1458 
1459 			if (dir_check_ftype((uint32_t)finfo->mode,
1460 					(uint32_t)attribute)) {
1461 				/*
1462 				 * Only process if attributes match.
1463 				 * On SMB1 server does this, so on
1464 				 * SMB2 we need to emulate in the
1465 				 * client.
1466 				 *
1467 				 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1468 				 */
1469 				processed_file = true;
1470 
1471 				status = fn(cli->dfs_mountpoint,
1472 					finfo,
1473 					pathname,
1474 					state);
1475 
1476 				if (!NT_STATUS_IS_OK(status)) {
1477 					break;
1478 				}
1479 			}
1480 
1481 			TALLOC_FREE(finfo);
1482 
1483 			/* Move to next entry. */
1484 			if (next_offset) {
1485 				dir_data += next_offset;
1486 				dir_data_length -= next_offset;
1487 			}
1488 		} while (next_offset != 0);
1489 
1490 		TALLOC_FREE(subframe);
1491 
1492 		if (!mask_has_wild) {
1493 			/*
1494 			 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1495 			 * when handed a non-wildcard path. Do it
1496 			 * for the server (with a non-wildcard path
1497 			 * there should only ever be one file returned.
1498 			 */
1499 			status = STATUS_NO_MORE_FILES;
1500 			break;
1501 		}
1502 
1503 	} while (NT_STATUS_IS_OK(status));
1504 
1505 	if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1506 		status = NT_STATUS_OK;
1507 	}
1508 
1509 	if (NT_STATUS_IS_OK(status) && !processed_file) {
1510 		/*
1511 		 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1512 		 * if no files match. Emulate this in the client.
1513 		 */
1514 		status = NT_STATUS_NO_SUCH_FILE;
1515 	}
1516 
1517   fail:
1518 
1519 	if (fnum != 0xffff) {
1520 		cli_smb2_close_fnum(cli, fnum);
1521 	}
1522 
1523 	cli->raw_status = status;
1524 
1525 	TALLOC_FREE(subframe);
1526 	TALLOC_FREE(frame);
1527 	return status;
1528 }
1529 
1530 /***************************************************************
1531  Wrapper that allows SMB2 to query a path info (basic level).
1532  Synchronous only.
1533 ***************************************************************/
1534 
cli_smb2_qpathinfo_basic(struct cli_state * cli,const char * name,SMB_STRUCT_STAT * sbuf,uint32_t * attributes)1535 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1536 				const char *name,
1537 				SMB_STRUCT_STAT *sbuf,
1538 				uint32_t *attributes)
1539 {
1540 	NTSTATUS status;
1541 	struct smb_create_returns cr;
1542 	uint16_t fnum = 0xffff;
1543 	size_t namelen = strlen(name);
1544 
1545 	if (smbXcli_conn_has_async_calls(cli->conn)) {
1546 		/*
1547 		 * Can't use sync call while an async call is in flight
1548 		 */
1549 		return NT_STATUS_INVALID_PARAMETER;
1550 	}
1551 
1552 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1553 		return NT_STATUS_INVALID_PARAMETER;
1554 	}
1555 
1556 	/* SMB2 is pickier about pathnames. Ensure it doesn't
1557 	   end in a '\' */
1558 	if (namelen > 0 && name[namelen-1] == '\\') {
1559 		char *modname = talloc_strdup(talloc_tos(), name);
1560 		modname[namelen-1] = '\0';
1561 		name = modname;
1562 	}
1563 
1564 	/* This is commonly used as a 'cd'. Try qpathinfo on
1565 	   a directory handle first. */
1566 
1567 	status = cli_smb2_create_fnum(cli,
1568 			name,
1569 			0,			/* create_flags */
1570 			SMB2_IMPERSONATION_IMPERSONATION,
1571 			FILE_READ_ATTRIBUTES,	/* desired_access */
1572 			FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1573 			FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1574 			FILE_OPEN,		/* create_disposition */
1575 			FILE_DIRECTORY_FILE,	/* create_options */
1576 			NULL,
1577 			&fnum,
1578 			&cr,
1579 			NULL,
1580 			NULL);
1581 
1582 	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1583 		/* Maybe a file ? */
1584 		status = cli_smb2_create_fnum(cli,
1585 			name,
1586 			0,			/* create_flags */
1587 			SMB2_IMPERSONATION_IMPERSONATION,
1588 			FILE_READ_ATTRIBUTES,		/* desired_access */
1589 			0, /* file attributes */
1590 			FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1591 			FILE_OPEN,		/* create_disposition */
1592 			0,	/* create_options */
1593 			NULL,
1594 			&fnum,
1595 			&cr,
1596 			NULL,
1597 			NULL);
1598 	}
1599 
1600 	if (!NT_STATUS_IS_OK(status)) {
1601 		return status;
1602 	}
1603 
1604 	status = cli_smb2_close_fnum(cli, fnum);
1605 
1606 	ZERO_STRUCTP(sbuf);
1607 
1608 	sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1609 	sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1610 	sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1611 	sbuf->st_ex_size = cr.end_of_file;
1612 	*attributes = cr.file_attributes;
1613 
1614 	return status;
1615 }
1616 
1617 /***************************************************************
1618  Wrapper that allows SMB2 to check if a path is a directory.
1619  Synchronous only.
1620 ***************************************************************/
1621 
cli_smb2_chkpath(struct cli_state * cli,const char * name)1622 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1623 				const char *name)
1624 {
1625 	NTSTATUS status;
1626 	uint16_t fnum = 0xffff;
1627 
1628 	if (smbXcli_conn_has_async_calls(cli->conn)) {
1629 		/*
1630 		 * Can't use sync call while an async call is in flight
1631 		 */
1632 		return NT_STATUS_INVALID_PARAMETER;
1633 	}
1634 
1635 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1636 		return NT_STATUS_INVALID_PARAMETER;
1637 	}
1638 
1639 	/* Ensure this is a directory. */
1640 	status = cli_smb2_create_fnum(cli,
1641 			name,
1642 			0,			/* create_flags */
1643 			SMB2_IMPERSONATION_IMPERSONATION,
1644 			FILE_READ_ATTRIBUTES,	/* desired_access */
1645 			FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1646 			FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1647 			FILE_OPEN,		/* create_disposition */
1648 			FILE_DIRECTORY_FILE,	/* create_options */
1649 			NULL,
1650 			&fnum,
1651 			NULL,
1652 			NULL,
1653 			NULL);
1654 
1655 	if (!NT_STATUS_IS_OK(status)) {
1656 		return status;
1657 	}
1658 
1659 	return cli_smb2_close_fnum(cli, fnum);
1660 }
1661 
1662 struct cli_smb2_query_info_fnum_state {
1663 	DATA_BLOB outbuf;
1664 };
1665 
1666 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq);
1667 
cli_smb2_query_info_fnum_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum,uint8_t in_info_type,uint8_t in_info_class,uint32_t in_max_output_length,const DATA_BLOB * in_input_buffer,uint32_t in_additional_info,uint32_t in_flags)1668 struct tevent_req *cli_smb2_query_info_fnum_send(
1669 	TALLOC_CTX *mem_ctx,
1670 	struct tevent_context *ev,
1671 	struct cli_state *cli,
1672 	uint16_t fnum,
1673 	uint8_t in_info_type,
1674 	uint8_t in_info_class,
1675 	uint32_t in_max_output_length,
1676 	const DATA_BLOB *in_input_buffer,
1677 	uint32_t in_additional_info,
1678 	uint32_t in_flags)
1679 {
1680 	struct tevent_req *req = NULL, *subreq = NULL;
1681 	struct cli_smb2_query_info_fnum_state *state = NULL;
1682 	struct smb2_hnd *ph = NULL;
1683 	NTSTATUS status;
1684 
1685 	req = tevent_req_create(
1686 		mem_ctx, &state, struct cli_smb2_query_info_fnum_state);
1687 	if (req == NULL) {
1688 		return req;
1689 	}
1690 
1691 	status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1692 	if (tevent_req_nterror(req, status)) {
1693 		return tevent_req_post(req, ev);
1694 	}
1695 
1696 	subreq = smb2cli_query_info_send(
1697 		state,
1698 		ev,
1699 		cli->conn,
1700 		cli->timeout,
1701 		cli->smb2.session,
1702 		cli->smb2.tcon,
1703 		in_info_type,
1704 		in_info_class,
1705 		in_max_output_length,
1706 		in_input_buffer,
1707 		in_additional_info,
1708 		in_flags,
1709 		ph->fid_persistent,
1710 		ph->fid_volatile);
1711 	if (tevent_req_nomem(subreq, req)) {
1712 		return tevent_req_post(req, ev);
1713 	}
1714 	tevent_req_set_callback(subreq, cli_smb2_query_info_fnum_done, req);
1715 	return req;
1716 }
1717 
cli_smb2_query_info_fnum_done(struct tevent_req * subreq)1718 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq)
1719 {
1720 	struct tevent_req *req = tevent_req_callback_data(
1721 		subreq, struct tevent_req);
1722 	struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1723 		req, struct cli_smb2_query_info_fnum_state);
1724 	DATA_BLOB outbuf;
1725 	NTSTATUS status;
1726 
1727 	status = smb2cli_query_info_recv(subreq, state, &outbuf);
1728 	TALLOC_FREE(subreq);
1729 	if (tevent_req_nterror(req, status)) {
1730 		return;
1731 	}
1732 
1733 	/*
1734 	 * We have to dup the memory here because outbuf.data is not
1735 	 * returned as a talloc object by smb2cli_query_info_recv.
1736 	 * It's a pointer into the received buffer.
1737 	 */
1738 	state->outbuf = data_blob_dup_talloc(state, outbuf);
1739 
1740 	if ((outbuf.length != 0) &&
1741 	    tevent_req_nomem(state->outbuf.data, req)) {
1742 		return;
1743 	}
1744 	tevent_req_done(req);
1745 }
1746 
cli_smb2_query_info_fnum_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,DATA_BLOB * outbuf)1747 NTSTATUS cli_smb2_query_info_fnum_recv(
1748 	struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf)
1749 {
1750 	struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1751 		req, struct cli_smb2_query_info_fnum_state);
1752 	NTSTATUS status;
1753 
1754 	if (tevent_req_is_nterror(req, &status)) {
1755 		return status;
1756 	}
1757 	*outbuf = (DATA_BLOB) {
1758 		.data = talloc_move(mem_ctx, &state->outbuf.data),
1759 		.length = state->outbuf.length,
1760 	};
1761 	return NT_STATUS_OK;
1762 }
1763 
cli_smb2_query_info_fnum(struct cli_state * cli,uint16_t fnum,uint8_t in_info_type,uint8_t in_info_class,uint32_t in_max_output_length,const DATA_BLOB * in_input_buffer,uint32_t in_additional_info,uint32_t in_flags,TALLOC_CTX * mem_ctx,DATA_BLOB * outbuf)1764 NTSTATUS cli_smb2_query_info_fnum(
1765 	struct cli_state *cli,
1766 	uint16_t fnum,
1767 	uint8_t in_info_type,
1768 	uint8_t in_info_class,
1769 	uint32_t in_max_output_length,
1770 	const DATA_BLOB *in_input_buffer,
1771 	uint32_t in_additional_info,
1772 	uint32_t in_flags,
1773 	TALLOC_CTX *mem_ctx,
1774 	DATA_BLOB *outbuf)
1775 {
1776 	TALLOC_CTX *frame = talloc_stackframe();
1777 	struct tevent_context *ev = NULL;
1778 	struct tevent_req *req = NULL;
1779 	NTSTATUS status = NT_STATUS_NO_MEMORY;
1780 	bool ok;
1781 
1782 	if (smbXcli_conn_has_async_calls(cli->conn)) {
1783 		/*
1784 		 * Can't use sync call while an async call is in flight
1785 		 */
1786 		status = NT_STATUS_INVALID_PARAMETER;
1787 		goto fail;
1788 	}
1789 	ev = samba_tevent_context_init(frame);
1790 	if (ev == NULL) {
1791 		goto fail;
1792 	}
1793 	req = cli_smb2_query_info_fnum_send(
1794 		frame,
1795 		ev,
1796 		cli,
1797 		fnum,
1798 		in_info_type,
1799 		in_info_class,
1800 		in_max_output_length,
1801 		in_input_buffer,
1802 		in_additional_info,
1803 		in_flags);
1804 	if (req == NULL) {
1805 		goto fail;
1806 	}
1807 	ok = tevent_req_poll_ntstatus(req, ev, &status);
1808 	if (!ok) {
1809 		goto fail;
1810 	}
1811 	status = cli_smb2_query_info_fnum_recv(req, mem_ctx, outbuf);
1812 fail:
1813 	TALLOC_FREE(frame);
1814 	return status;
1815 }
1816 
1817 /***************************************************************
1818  Helper function for pathname operations.
1819 ***************************************************************/
1820 
get_fnum_from_path(struct cli_state * cli,const char * name,uint32_t desired_access,uint16_t * pfnum)1821 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1822 				const char *name,
1823 				uint32_t desired_access,
1824 				uint16_t *pfnum)
1825 {
1826 	NTSTATUS status;
1827 	size_t namelen = strlen(name);
1828 	TALLOC_CTX *frame = talloc_stackframe();
1829 	uint32_t create_options = 0;
1830 
1831 	/* SMB2 is pickier about pathnames. Ensure it doesn't
1832 	   end in a '\' */
1833 	if (namelen > 0 && name[namelen-1] == '\\') {
1834 		char *modname = talloc_strdup(frame, name);
1835 		if (modname == NULL) {
1836 			status = NT_STATUS_NO_MEMORY;
1837 			goto fail;
1838 		}
1839 		modname[namelen-1] = '\0';
1840 		name = modname;
1841 	}
1842 
1843 	/* Try to open a file handle first. */
1844 	status = cli_smb2_create_fnum(cli,
1845 			name,
1846 			0,			/* create_flags */
1847 			SMB2_IMPERSONATION_IMPERSONATION,
1848 			desired_access,
1849 			0, /* file attributes */
1850 			FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1851 			FILE_OPEN,		/* create_disposition */
1852 			create_options,
1853 			NULL,
1854 			pfnum,
1855 			NULL,
1856 			NULL,
1857 			NULL);
1858 
1859 	if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1860 		/*
1861 		 * Naive option to match our SMB1 code. Assume the
1862 		 * symlink path that tripped us up was the last
1863 		 * component and try again. Eventually we will have to
1864 		 * deal with the returned path unprocessed component. JRA.
1865 		 */
1866 		create_options |= FILE_OPEN_REPARSE_POINT;
1867 		status = cli_smb2_create_fnum(cli,
1868 			name,
1869 			0,			/* create_flags */
1870 			SMB2_IMPERSONATION_IMPERSONATION,
1871 			desired_access,
1872 			0, /* file attributes */
1873 			FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1874 			FILE_OPEN,		/* create_disposition */
1875 			create_options,
1876 			NULL,
1877 			pfnum,
1878 			NULL,
1879 			NULL,
1880 			NULL);
1881 	}
1882 
1883 	if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1884 		create_options |= FILE_DIRECTORY_FILE;
1885 		status = cli_smb2_create_fnum(cli,
1886 			name,
1887 			0,			/* create_flags */
1888 			SMB2_IMPERSONATION_IMPERSONATION,
1889 			desired_access,
1890 			FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1891 			FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1892 			FILE_OPEN,		/* create_disposition */
1893 			create_options,		/* create_options */
1894 			NULL,
1895 			pfnum,
1896 			NULL,
1897 			NULL,
1898 			NULL);
1899 	}
1900 
1901   fail:
1902 
1903 	TALLOC_FREE(frame);
1904 	return status;
1905 }
1906 
1907 /***************************************************************
1908  Wrapper that allows SMB2 to query a path info (ALTNAME level).
1909  Synchronous only.
1910 ***************************************************************/
1911 
cli_smb2_qpathinfo_alt_name(struct cli_state * cli,const char * name,fstring alt_name)1912 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1913 				const char *name,
1914 				fstring alt_name)
1915 {
1916 	NTSTATUS status;
1917 	DATA_BLOB outbuf = data_blob_null;
1918 	uint16_t fnum = 0xffff;
1919 	uint32_t altnamelen = 0;
1920 	TALLOC_CTX *frame = talloc_stackframe();
1921 
1922 	if (smbXcli_conn_has_async_calls(cli->conn)) {
1923 		/*
1924 		 * Can't use sync call while an async call is in flight
1925 		 */
1926 		status = NT_STATUS_INVALID_PARAMETER;
1927 		goto fail;
1928 	}
1929 
1930 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1931 		status = NT_STATUS_INVALID_PARAMETER;
1932 		goto fail;
1933 	}
1934 
1935 	status = get_fnum_from_path(cli,
1936 				name,
1937 				FILE_READ_ATTRIBUTES,
1938 				&fnum);
1939 
1940 	if (!NT_STATUS_IS_OK(status)) {
1941 		goto fail;
1942 	}
1943 
1944 	status = cli_smb2_query_info_fnum(
1945 		cli,
1946 		fnum,
1947 		1, /* in_info_type */
1948 		(SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1949 		0xFFFF, /* in_max_output_length */
1950 		NULL, /* in_input_buffer */
1951 		0, /* in_additional_info */
1952 		0, /* in_flags */
1953 		frame,
1954 		&outbuf);
1955 
1956 	if (!NT_STATUS_IS_OK(status)) {
1957 		goto fail;
1958 	}
1959 
1960 	/* Parse the reply. */
1961 	if (outbuf.length < 4) {
1962 		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1963 		goto fail;
1964 	}
1965 
1966 	altnamelen = IVAL(outbuf.data, 0);
1967 	if (altnamelen > outbuf.length - 4) {
1968 		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1969 		goto fail;
1970 	}
1971 
1972 	if (altnamelen > 0) {
1973 		size_t ret = 0;
1974 		char *short_name = NULL;
1975 		ret = pull_string_talloc(frame,
1976 				outbuf.data,
1977 				FLAGS2_UNICODE_STRINGS,
1978 				&short_name,
1979 				outbuf.data + 4,
1980 				altnamelen,
1981 				STR_UNICODE);
1982 		if (ret == (size_t)-1) {
1983 			/* Bad conversion. */
1984 			status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1985 			goto fail;
1986 		}
1987 
1988 	        fstrcpy(alt_name, short_name);
1989 	} else {
1990 		alt_name[0] = '\0';
1991 	}
1992 
1993 	status = NT_STATUS_OK;
1994 
1995   fail:
1996 
1997 	if (fnum != 0xffff) {
1998 		cli_smb2_close_fnum(cli, fnum);
1999 	}
2000 
2001 	cli->raw_status = status;
2002 
2003 	TALLOC_FREE(frame);
2004 	return status;
2005 }
2006 
2007 
2008 /***************************************************************
2009  Wrapper that allows SMB2 to query a fnum info (basic level).
2010  Synchronous only.
2011 ***************************************************************/
2012 
cli_smb2_qfileinfo_basic(struct cli_state * cli,uint16_t fnum,uint16_t * mode,off_t * size,struct timespec * create_time,struct timespec * access_time,struct timespec * write_time,struct timespec * change_time,SMB_INO_T * ino)2013 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
2014 			uint16_t fnum,
2015 			uint16_t *mode,
2016 			off_t *size,
2017 			struct timespec *create_time,
2018 			struct timespec *access_time,
2019 			struct timespec *write_time,
2020 			struct timespec *change_time,
2021 			SMB_INO_T *ino)
2022 {
2023 	NTSTATUS status;
2024 	DATA_BLOB outbuf = data_blob_null;
2025 	TALLOC_CTX *frame = talloc_stackframe();
2026 
2027 	if (smbXcli_conn_has_async_calls(cli->conn)) {
2028 		/*
2029 		 * Can't use sync call while an async call is in flight
2030 		 */
2031 		status = NT_STATUS_INVALID_PARAMETER;
2032 		goto fail;
2033 	}
2034 
2035 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2036 		status = NT_STATUS_INVALID_PARAMETER;
2037 		goto fail;
2038 	}
2039 
2040 	/* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2041 	   level 0x12 (SMB2_FILE_ALL_INFORMATION). */
2042 
2043 	status = cli_smb2_query_info_fnum(
2044 		cli,
2045 		fnum,
2046 		1, /* in_info_type */
2047 		(SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
2048 		0xFFFF, /* in_max_output_length */
2049 		NULL, /* in_input_buffer */
2050 		0, /* in_additional_info */
2051 		0, /* in_flags */
2052 		frame,
2053 		&outbuf);
2054 	if (!NT_STATUS_IS_OK(status)) {
2055 		goto fail;
2056 	}
2057 
2058 	/* Parse the reply. */
2059 	if (outbuf.length < 0x60) {
2060 		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2061 		goto fail;
2062 	}
2063 
2064 	if (create_time) {
2065 		*create_time = interpret_long_date((const char *)outbuf.data + 0x0);
2066 	}
2067 	if (access_time) {
2068 		*access_time = interpret_long_date((const char *)outbuf.data + 0x8);
2069 	}
2070 	if (write_time) {
2071 		*write_time = interpret_long_date((const char *)outbuf.data + 0x10);
2072 	}
2073 	if (change_time) {
2074 		*change_time = interpret_long_date((const char *)outbuf.data + 0x18);
2075 	}
2076 	if (mode) {
2077 		uint32_t attr = IVAL(outbuf.data, 0x20);
2078 		*mode = (uint16_t)attr;
2079 	}
2080 	if (size) {
2081 		uint64_t file_size = BVAL(outbuf.data, 0x30);
2082 		*size = (off_t)file_size;
2083 	}
2084 	if (ino) {
2085 		uint64_t file_index = BVAL(outbuf.data, 0x40);
2086 		*ino = (SMB_INO_T)file_index;
2087 	}
2088 
2089   fail:
2090 
2091 	cli->raw_status = status;
2092 
2093 	TALLOC_FREE(frame);
2094 	return status;
2095 }
2096 
2097 /***************************************************************
2098  Wrapper that allows SMB2 to query an fnum.
2099  Implement on top of cli_smb2_qfileinfo_basic().
2100  Synchronous only.
2101 ***************************************************************/
2102 
cli_smb2_getattrE(struct cli_state * cli,uint16_t fnum,uint16_t * attr,off_t * size,time_t * change_time,time_t * access_time,time_t * write_time)2103 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
2104 			uint16_t fnum,
2105 			uint16_t *attr,
2106 			off_t *size,
2107 			time_t *change_time,
2108 			time_t *access_time,
2109 			time_t *write_time)
2110 {
2111 	struct timespec access_time_ts;
2112 	struct timespec write_time_ts;
2113 	struct timespec change_time_ts;
2114 	NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
2115 					fnum,
2116 					attr,
2117 					size,
2118 					NULL,
2119 					&access_time_ts,
2120 					&write_time_ts,
2121 					&change_time_ts,
2122                                         NULL);
2123 
2124 	cli->raw_status = status;
2125 
2126 	if (!NT_STATUS_IS_OK(status)) {
2127 		return status;
2128 	}
2129 
2130 	if (change_time) {
2131 		*change_time = change_time_ts.tv_sec;
2132 	}
2133 	if (access_time) {
2134 		*access_time = access_time_ts.tv_sec;
2135 	}
2136 	if (write_time) {
2137 		*write_time = write_time_ts.tv_sec;
2138 	}
2139 	return NT_STATUS_OK;
2140 }
2141 
2142 /***************************************************************
2143  Wrapper that allows SMB2 to get pathname attributes.
2144  Synchronous only.
2145 ***************************************************************/
2146 
cli_smb2_getatr(struct cli_state * cli,const char * name,uint16_t * attr,off_t * size,time_t * write_time)2147 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
2148 			const char *name,
2149 			uint16_t *attr,
2150 			off_t *size,
2151 			time_t *write_time)
2152 {
2153 	NTSTATUS status;
2154 	uint16_t fnum = 0xffff;
2155 	struct smb2_hnd *ph = NULL;
2156 	TALLOC_CTX *frame = talloc_stackframe();
2157 
2158 	if (smbXcli_conn_has_async_calls(cli->conn)) {
2159 		/*
2160 		 * Can't use sync call while an async call is in flight
2161 		 */
2162 		status = NT_STATUS_INVALID_PARAMETER;
2163 		goto fail;
2164 	}
2165 
2166 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2167 		status = NT_STATUS_INVALID_PARAMETER;
2168 		goto fail;
2169 	}
2170 
2171 	status = get_fnum_from_path(cli,
2172 				name,
2173 				FILE_READ_ATTRIBUTES,
2174 				&fnum);
2175 
2176 	if (!NT_STATUS_IS_OK(status)) {
2177 		goto fail;
2178 	}
2179 
2180 	status = map_fnum_to_smb2_handle(cli,
2181 					fnum,
2182 					&ph);
2183 	if (!NT_STATUS_IS_OK(status)) {
2184 		goto fail;
2185 	}
2186 	status = cli_smb2_getattrE(cli,
2187 				fnum,
2188 				attr,
2189 				size,
2190 				NULL,
2191 				NULL,
2192 				write_time);
2193 	if (!NT_STATUS_IS_OK(status)) {
2194 		goto fail;
2195 	}
2196 
2197   fail:
2198 
2199 	if (fnum != 0xffff) {
2200 		cli_smb2_close_fnum(cli, fnum);
2201 	}
2202 
2203 	cli->raw_status = status;
2204 
2205 	TALLOC_FREE(frame);
2206 	return status;
2207 }
2208 
2209 /***************************************************************
2210  Wrapper that allows SMB2 to query a pathname info (basic level).
2211  Implement on top of cli_smb2_qfileinfo_basic().
2212  Synchronous only.
2213 ***************************************************************/
2214 
cli_smb2_qpathinfo2(struct cli_state * cli,const char * name,struct timespec * create_time,struct timespec * access_time,struct timespec * write_time,struct timespec * change_time,off_t * size,uint16_t * mode,SMB_INO_T * ino)2215 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
2216 			const char *name,
2217 			struct timespec *create_time,
2218 			struct timespec *access_time,
2219 			struct timespec *write_time,
2220 			struct timespec *change_time,
2221 			off_t *size,
2222 			uint16_t *mode,
2223 			SMB_INO_T *ino)
2224 {
2225 	NTSTATUS status;
2226 	struct smb2_hnd *ph = NULL;
2227 	uint16_t fnum = 0xffff;
2228 	TALLOC_CTX *frame = talloc_stackframe();
2229 
2230 	if (smbXcli_conn_has_async_calls(cli->conn)) {
2231 		/*
2232 		 * Can't use sync call while an async call is in flight
2233 		 */
2234 		status = NT_STATUS_INVALID_PARAMETER;
2235 		goto fail;
2236 	}
2237 
2238 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2239 		status = NT_STATUS_INVALID_PARAMETER;
2240 		goto fail;
2241 	}
2242 
2243 	status = get_fnum_from_path(cli,
2244 					name,
2245 					FILE_READ_ATTRIBUTES,
2246 					&fnum);
2247 
2248 	if (!NT_STATUS_IS_OK(status)) {
2249 		goto fail;
2250 	}
2251 
2252 	status = map_fnum_to_smb2_handle(cli,
2253 					fnum,
2254 					&ph);
2255 	if (!NT_STATUS_IS_OK(status)) {
2256 		goto fail;
2257 	}
2258 
2259 	status = cli_smb2_qfileinfo_basic(cli,
2260 					fnum,
2261 					mode,
2262 					size,
2263 					create_time,
2264 					access_time,
2265 					write_time,
2266 					change_time,
2267 					ino);
2268 
2269   fail:
2270 
2271 	if (fnum != 0xffff) {
2272 		cli_smb2_close_fnum(cli, fnum);
2273 	}
2274 
2275 	cli->raw_status = status;
2276 
2277 	TALLOC_FREE(frame);
2278 	return status;
2279 }
2280 
2281 /***************************************************************
2282  Wrapper that allows SMB2 to query pathname streams.
2283  Synchronous only.
2284 ***************************************************************/
2285 
cli_smb2_qpathinfo_streams(struct cli_state * cli,const char * name,TALLOC_CTX * mem_ctx,unsigned int * pnum_streams,struct stream_struct ** pstreams)2286 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
2287 				const char *name,
2288 				TALLOC_CTX *mem_ctx,
2289 				unsigned int *pnum_streams,
2290 				struct stream_struct **pstreams)
2291 {
2292 	NTSTATUS status;
2293 	uint16_t fnum = 0xffff;
2294 	DATA_BLOB outbuf = data_blob_null;
2295 	TALLOC_CTX *frame = talloc_stackframe();
2296 
2297 	if (smbXcli_conn_has_async_calls(cli->conn)) {
2298 		/*
2299 		 * Can't use sync call while an async call is in flight
2300 		 */
2301 		status = NT_STATUS_INVALID_PARAMETER;
2302 		goto fail;
2303 	}
2304 
2305 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2306 		status = NT_STATUS_INVALID_PARAMETER;
2307 		goto fail;
2308 	}
2309 
2310 	status = get_fnum_from_path(cli,
2311 				name,
2312 				FILE_READ_ATTRIBUTES,
2313 				&fnum);
2314 
2315 	if (!NT_STATUS_IS_OK(status)) {
2316 		goto fail;
2317 	}
2318 
2319 	/* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2320 	   level 22 (SMB2_FILE_STREAM_INFORMATION). */
2321 
2322 	status = cli_smb2_query_info_fnum(
2323 		cli,
2324 		fnum,
2325 		1, /* in_info_type */
2326 		(SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
2327 		0xFFFF, /* in_max_output_length */
2328 		NULL, /* in_input_buffer */
2329 		0, /* in_additional_info */
2330 		0, /* in_flags */
2331 		frame,
2332 		&outbuf);
2333 
2334 	if (!NT_STATUS_IS_OK(status)) {
2335 		goto fail;
2336 	}
2337 
2338 	/* Parse the reply. */
2339 	if (!parse_streams_blob(mem_ctx,
2340 				outbuf.data,
2341 				outbuf.length,
2342 				pnum_streams,
2343 				pstreams)) {
2344 		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2345 		goto fail;
2346 	}
2347 
2348   fail:
2349 
2350 	if (fnum != 0xffff) {
2351 		cli_smb2_close_fnum(cli, fnum);
2352 	}
2353 
2354 	cli->raw_status = status;
2355 
2356 	TALLOC_FREE(frame);
2357 	return status;
2358 }
2359 
2360 /***************************************************************
2361  Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2362  a pathname.
2363  Synchronous only.
2364 ***************************************************************/
2365 
cli_smb2_setpathinfo(struct cli_state * cli,const char * name,uint8_t in_info_type,uint8_t in_file_info_class,const DATA_BLOB * p_in_data)2366 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
2367 			const char *name,
2368 			uint8_t in_info_type,
2369 			uint8_t in_file_info_class,
2370 			const DATA_BLOB *p_in_data)
2371 {
2372 	NTSTATUS status;
2373 	uint16_t fnum = 0xffff;
2374 	TALLOC_CTX *frame = talloc_stackframe();
2375 
2376 	if (smbXcli_conn_has_async_calls(cli->conn)) {
2377 		/*
2378 		 * Can't use sync call while an async call is in flight
2379 		 */
2380 		status = NT_STATUS_INVALID_PARAMETER;
2381 		goto fail;
2382 	}
2383 
2384 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2385 		status = NT_STATUS_INVALID_PARAMETER;
2386 		goto fail;
2387 	}
2388 
2389 	status = get_fnum_from_path(cli,
2390 				name,
2391 				FILE_WRITE_ATTRIBUTES,
2392 				&fnum);
2393 
2394 	if (!NT_STATUS_IS_OK(status)) {
2395 		goto fail;
2396 	}
2397 
2398 	status = cli_smb2_set_info_fnum(
2399 		cli,
2400 		fnum,
2401 		in_info_type,
2402 		in_file_info_class,
2403 		p_in_data,	   /* in_input_buffer */
2404 		0);		   /* in_additional_info */
2405   fail:
2406 
2407 	if (fnum != 0xffff) {
2408 		cli_smb2_close_fnum(cli, fnum);
2409 	}
2410 
2411 	cli->raw_status = status;
2412 
2413 	TALLOC_FREE(frame);
2414 	return status;
2415 }
2416 
2417 
2418 /***************************************************************
2419  Wrapper that allows SMB2 to set pathname attributes.
2420  Synchronous only.
2421 ***************************************************************/
2422 
cli_smb2_setatr(struct cli_state * cli,const char * name,uint16_t attr,time_t mtime)2423 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2424 			const char *name,
2425 			uint16_t attr,
2426 			time_t mtime)
2427 {
2428 	uint8_t inbuf_store[40];
2429 	DATA_BLOB inbuf = data_blob_null;
2430 
2431 	/* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2432 	   level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2433 
2434 	inbuf.data = inbuf_store;
2435 	inbuf.length = sizeof(inbuf_store);
2436 	data_blob_clear(&inbuf);
2437 
2438 	/*
2439 	 * SMB1 uses attr == 0 to clear all attributes
2440 	 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2441 	 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2442 	 * request attribute change.
2443 	 *
2444 	 * SMB2 uses exactly the reverse. Unfortunately as the
2445 	 * cli_setatr() ABI is exposed inside libsmbclient,
2446 	 * we must make the SMB2 cli_smb2_setatr() call
2447 	 * export the same ABI as the SMB1 cli_setatr()
2448 	 * which calls it. This means reversing the sense
2449 	 * of the requested attr argument if it's zero
2450 	 * or FILE_ATTRIBUTE_NORMAL.
2451 	 *
2452 	 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2453 	 */
2454 
2455 	if (attr == 0) {
2456 		attr = FILE_ATTRIBUTE_NORMAL;
2457 	} else if (attr == FILE_ATTRIBUTE_NORMAL) {
2458 		attr = 0;
2459 	}
2460 
2461 	SSVAL(inbuf.data, 32, attr);
2462 	if (mtime != 0) {
2463 		put_long_date((char *)inbuf.data + 16,mtime);
2464 	}
2465 	/* Set all the other times to -1. */
2466 	SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2467 	SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2468 	SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2469 
2470 	return cli_smb2_setpathinfo(cli,
2471 				name,
2472 				1, /* in_info_type */
2473 				/* in_file_info_class */
2474 				SMB_FILE_BASIC_INFORMATION - 1000,
2475 				&inbuf);
2476 }
2477 
2478 
2479 /***************************************************************
2480  Wrapper that allows SMB2 to set file handle times.
2481  Synchronous only.
2482 ***************************************************************/
2483 
cli_smb2_setattrE(struct cli_state * cli,uint16_t fnum,time_t change_time,time_t access_time,time_t write_time)2484 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2485 			uint16_t fnum,
2486 			time_t change_time,
2487 			time_t access_time,
2488 			time_t write_time)
2489 {
2490 	uint8_t inbuf_store[40];
2491 	DATA_BLOB inbuf = data_blob_null;
2492 
2493 	if (smbXcli_conn_has_async_calls(cli->conn)) {
2494 		/*
2495 		 * Can't use sync call while an async call is in flight
2496 		 */
2497 		return NT_STATUS_INVALID_PARAMETER;
2498 	}
2499 
2500 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2501 		return NT_STATUS_INVALID_PARAMETER;
2502 	}
2503 
2504 	/* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2505 	   level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2506 
2507 	inbuf.data = inbuf_store;
2508 	inbuf.length = sizeof(inbuf_store);
2509 	data_blob_clear(&inbuf);
2510 
2511 	SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2512 	if (change_time != 0) {
2513 		put_long_date((char *)inbuf.data + 24, change_time);
2514 	}
2515 	if (access_time != 0) {
2516 		put_long_date((char *)inbuf.data + 8, access_time);
2517 	}
2518 	if (write_time != 0) {
2519 		put_long_date((char *)inbuf.data + 16, write_time);
2520 	}
2521 
2522 	cli->raw_status = cli_smb2_set_info_fnum(
2523 		cli,
2524 		fnum,
2525 		1,		/* in_info_type */
2526 		SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
2527 		&inbuf,		   /* in_input_buffer */
2528 		0);		   /* in_additional_info */
2529 
2530 	return cli->raw_status;
2531 }
2532 
2533 /***************************************************************
2534  Wrapper that allows SMB2 to query disk attributes (size).
2535  Synchronous only.
2536 ***************************************************************/
2537 
cli_smb2_dskattr(struct cli_state * cli,const char * path,uint64_t * bsize,uint64_t * total,uint64_t * avail)2538 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2539 			  uint64_t *bsize, uint64_t *total, uint64_t *avail)
2540 {
2541 	NTSTATUS status;
2542 	uint16_t fnum = 0xffff;
2543 	DATA_BLOB outbuf = data_blob_null;
2544 	uint32_t sectors_per_unit = 0;
2545 	uint32_t bytes_per_sector = 0;
2546 	uint64_t total_size = 0;
2547 	uint64_t size_free = 0;
2548 	TALLOC_CTX *frame = talloc_stackframe();
2549 
2550 	if (smbXcli_conn_has_async_calls(cli->conn)) {
2551 		/*
2552 		 * Can't use sync call while an async call is in flight
2553 		 */
2554 		status = NT_STATUS_INVALID_PARAMETER;
2555 		goto fail;
2556 	}
2557 
2558 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2559 		status = NT_STATUS_INVALID_PARAMETER;
2560 		goto fail;
2561 	}
2562 
2563 	/* First open the top level directory. */
2564 	status = cli_smb2_create_fnum(cli,
2565 			path,
2566 			0,			/* create_flags */
2567 			SMB2_IMPERSONATION_IMPERSONATION,
2568 			FILE_READ_ATTRIBUTES,	/* desired_access */
2569 			FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2570 			FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2571 			FILE_OPEN,		/* create_disposition */
2572 			FILE_DIRECTORY_FILE,	/* create_options */
2573 			NULL,
2574 			&fnum,
2575 			NULL,
2576 			NULL,
2577 			NULL);
2578 
2579 	if (!NT_STATUS_IS_OK(status)) {
2580 		goto fail;
2581 	}
2582 
2583 	/* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2584 	   level 3 (SMB_FS_SIZE_INFORMATION). */
2585 
2586 	status = cli_smb2_query_info_fnum(
2587 		cli,
2588 		fnum,
2589 		2, /* in_info_type */
2590 		3, /* in_file_info_class */
2591 		0xFFFF, /* in_max_output_length */
2592 		NULL, /* in_input_buffer */
2593 		0, /* in_additional_info */
2594 		0, /* in_flags */
2595 		frame,
2596 		&outbuf);
2597 	if (!NT_STATUS_IS_OK(status)) {
2598 		goto fail;
2599 	}
2600 
2601 	/* Parse the reply. */
2602 	if (outbuf.length != 24) {
2603 		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2604 		goto fail;
2605 	}
2606 
2607 	total_size = BVAL(outbuf.data, 0);
2608 	size_free = BVAL(outbuf.data, 8);
2609 	sectors_per_unit = IVAL(outbuf.data, 16);
2610 	bytes_per_sector = IVAL(outbuf.data, 20);
2611 
2612 	if (bsize) {
2613 		*bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2614 	}
2615 	if (total) {
2616 		*total = total_size;
2617 	}
2618 	if (avail) {
2619 		*avail = size_free;
2620 	}
2621 
2622 	status = NT_STATUS_OK;
2623 
2624   fail:
2625 
2626 	if (fnum != 0xffff) {
2627 		cli_smb2_close_fnum(cli, fnum);
2628 	}
2629 
2630 	cli->raw_status = status;
2631 
2632 	TALLOC_FREE(frame);
2633 	return status;
2634 }
2635 
2636 /***************************************************************
2637  Wrapper that allows SMB2 to query file system sizes.
2638  Synchronous only.
2639 ***************************************************************/
2640 
cli_smb2_get_fs_full_size_info(struct cli_state * cli,uint64_t * total_allocation_units,uint64_t * caller_allocation_units,uint64_t * actual_allocation_units,uint64_t * sectors_per_allocation_unit,uint64_t * bytes_per_sector)2641 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2642 				uint64_t *total_allocation_units,
2643 				uint64_t *caller_allocation_units,
2644 				uint64_t *actual_allocation_units,
2645 				uint64_t *sectors_per_allocation_unit,
2646 				uint64_t *bytes_per_sector)
2647 {
2648 	NTSTATUS status;
2649 	uint16_t fnum = 0xffff;
2650 	DATA_BLOB outbuf = data_blob_null;
2651 	TALLOC_CTX *frame = talloc_stackframe();
2652 
2653 	if (smbXcli_conn_has_async_calls(cli->conn)) {
2654 		/*
2655 		 * Can't use sync call while an async call is in flight
2656 		 */
2657 		status = NT_STATUS_INVALID_PARAMETER;
2658 		goto fail;
2659 	}
2660 
2661 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2662 		status = NT_STATUS_INVALID_PARAMETER;
2663 		goto fail;
2664 	}
2665 
2666 	/* First open the top level directory. */
2667 	status =
2668 	    cli_smb2_create_fnum(cli, "", 0,		   /* create_flags */
2669 				 SMB2_IMPERSONATION_IMPERSONATION,
2670 				 FILE_READ_ATTRIBUTES,     /* desired_access */
2671 				 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2672 				 FILE_SHARE_READ | FILE_SHARE_WRITE |
2673 				     FILE_SHARE_DELETE, /* share_access */
2674 				 FILE_OPEN,		/* create_disposition */
2675 				 FILE_DIRECTORY_FILE,   /* create_options */
2676 				 NULL,
2677 				 &fnum,
2678 				 NULL,
2679 				 NULL,
2680 				 NULL);
2681 
2682 	if (!NT_STATUS_IS_OK(status)) {
2683 		goto fail;
2684 	}
2685 
2686 	/* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2687 	   level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2688 
2689 	status = cli_smb2_query_info_fnum(
2690 		cli,
2691 		fnum,
2692 		SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2693 		SMB_FS_FULL_SIZE_INFORMATION - 1000, /* in_file_info_class */
2694 		0xFFFF, /* in_max_output_length */
2695 		NULL, /* in_input_buffer */
2696 		0, /* in_additional_info */
2697 		0, /* in_flags */
2698 		frame,
2699 		&outbuf);
2700 	if (!NT_STATUS_IS_OK(status)) {
2701 		goto fail;
2702 	}
2703 
2704 	if (outbuf.length < 32) {
2705 		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2706 		goto fail;
2707 	}
2708 
2709 	*total_allocation_units = BIG_UINT(outbuf.data, 0);
2710 	*caller_allocation_units = BIG_UINT(outbuf.data, 8);
2711 	*actual_allocation_units = BIG_UINT(outbuf.data, 16);
2712 	*sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2713 	*bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2714 
2715 fail:
2716 
2717 	if (fnum != 0xffff) {
2718 		cli_smb2_close_fnum(cli, fnum);
2719 	}
2720 
2721 	cli->raw_status = status;
2722 
2723 	TALLOC_FREE(frame);
2724 	return status;
2725 }
2726 
2727 /***************************************************************
2728  Wrapper that allows SMB2 to query file system attributes.
2729  Synchronous only.
2730 ***************************************************************/
2731 
cli_smb2_get_fs_attr_info(struct cli_state * cli,uint32_t * fs_attr)2732 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2733 {
2734 	NTSTATUS status;
2735 	uint16_t fnum = 0xffff;
2736 	DATA_BLOB outbuf = data_blob_null;
2737 	TALLOC_CTX *frame = talloc_stackframe();
2738 
2739 	if (smbXcli_conn_has_async_calls(cli->conn)) {
2740 		/*
2741 		 * Can't use sync call while an async call is in flight
2742 		 */
2743 		status = NT_STATUS_INVALID_PARAMETER;
2744 		goto fail;
2745 	}
2746 
2747 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2748 		status = NT_STATUS_INVALID_PARAMETER;
2749 		goto fail;
2750 	}
2751 
2752 	/* First open the top level directory. */
2753 	status =
2754 	    cli_smb2_create_fnum(cli, "", 0,		   /* create_flags */
2755 				 SMB2_IMPERSONATION_IMPERSONATION,
2756 				 FILE_READ_ATTRIBUTES,     /* desired_access */
2757 				 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2758 				 FILE_SHARE_READ | FILE_SHARE_WRITE |
2759 				     FILE_SHARE_DELETE, /* share_access */
2760 				 FILE_OPEN,		/* create_disposition */
2761 				 FILE_DIRECTORY_FILE,   /* create_options */
2762 				 NULL,
2763 				 &fnum,
2764 				 NULL,
2765 				 NULL,
2766 				 NULL);
2767 
2768 	if (!NT_STATUS_IS_OK(status)) {
2769 		goto fail;
2770 	}
2771 
2772 	status = cli_smb2_query_info_fnum(
2773 		cli,
2774 		fnum,
2775 		2, /* in_info_type */
2776 		5,		       /* in_file_info_class */
2777 		0xFFFF, /* in_max_output_length */
2778 		NULL,   /* in_input_buffer */
2779 		0,      /* in_additional_info */
2780 		0,      /* in_flags */
2781 		frame,
2782 		&outbuf);
2783 	if (!NT_STATUS_IS_OK(status)) {
2784 		goto fail;
2785 	}
2786 
2787 	if (outbuf.length < 12) {
2788 		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2789 		goto fail;
2790 	}
2791 
2792 	*fs_attr = IVAL(outbuf.data, 0);
2793 
2794 fail:
2795 
2796 	if (fnum != 0xffff) {
2797 		cli_smb2_close_fnum(cli, fnum);
2798 	}
2799 
2800 	cli->raw_status = status;
2801 
2802 	TALLOC_FREE(frame);
2803 	return status;
2804 }
2805 
2806 /***************************************************************
2807  Wrapper that allows SMB2 to query file system volume info.
2808  Synchronous only.
2809 ***************************************************************/
2810 
cli_smb2_get_fs_volume_info(struct cli_state * cli,TALLOC_CTX * mem_ctx,char ** _volume_name,uint32_t * pserial_number,time_t * pdate)2811 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2812                                 TALLOC_CTX *mem_ctx,
2813                                 char **_volume_name,
2814                                 uint32_t *pserial_number,
2815                                 time_t *pdate)
2816 {
2817 	NTSTATUS status;
2818 	uint16_t fnum = 0xffff;
2819 	DATA_BLOB outbuf = data_blob_null;
2820 	uint32_t nlen;
2821 	char *volume_name = NULL;
2822 	TALLOC_CTX *frame = talloc_stackframe();
2823 
2824 	if (smbXcli_conn_has_async_calls(cli->conn)) {
2825 		/*
2826 		 * Can't use sync call while an async call is in flight
2827 		 */
2828 		status = NT_STATUS_INVALID_PARAMETER;
2829 		goto fail;
2830 	}
2831 
2832 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2833 		status = NT_STATUS_INVALID_PARAMETER;
2834 		goto fail;
2835 	}
2836 
2837 	/* First open the top level directory. */
2838 	status =
2839 	    cli_smb2_create_fnum(cli, "", 0,		   /* create_flags */
2840 				 SMB2_IMPERSONATION_IMPERSONATION,
2841 				 FILE_READ_ATTRIBUTES,     /* desired_access */
2842 				 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2843 				 FILE_SHARE_READ | FILE_SHARE_WRITE |
2844 				     FILE_SHARE_DELETE, /* share_access */
2845 				 FILE_OPEN,		/* create_disposition */
2846 				 FILE_DIRECTORY_FILE,   /* create_options */
2847 				 NULL,
2848 				 &fnum,
2849 				 NULL,
2850 				 NULL,
2851 				 NULL);
2852 
2853 	if (!NT_STATUS_IS_OK(status)) {
2854 		goto fail;
2855 	}
2856 
2857 	/* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2858 	   level 1 (SMB_FS_VOLUME_INFORMATION). */
2859 
2860 	status = cli_smb2_query_info_fnum(
2861 		cli,
2862 		fnum,
2863 		SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2864 		/* in_file_info_class */
2865 		SMB_FS_VOLUME_INFORMATION - 1000,
2866 		0xFFFF, /* in_max_output_length */
2867 		NULL, /* in_input_buffer */
2868 		0, /* in_additional_info */
2869 		0, /* in_flags */
2870 		frame,
2871 		&outbuf);
2872 	if (!NT_STATUS_IS_OK(status)) {
2873 		goto fail;
2874 	}
2875 
2876 	if (outbuf.length < 24) {
2877 		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2878 		goto fail;
2879 	}
2880 
2881 	if (pdate) {
2882 		struct timespec ts;
2883 		ts = interpret_long_date((char *)outbuf.data);
2884 		*pdate = ts.tv_sec;
2885 	}
2886 	if (pserial_number) {
2887 		*pserial_number = IVAL(outbuf.data,8);
2888 	}
2889 	nlen = IVAL(outbuf.data,12);
2890 	if (nlen + 18 < 18) {
2891 		/* Integer wrap. */
2892 		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2893 		goto fail;
2894 	}
2895 	/*
2896 	 * The next check is safe as we know outbuf.length >= 24
2897 	 * from above.
2898 	 */
2899 	if (nlen > (outbuf.length - 18)) {
2900 		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2901 		goto fail;
2902 	}
2903 
2904 	clistr_pull_talloc(mem_ctx,
2905 			(const char *)outbuf.data,
2906 			0,
2907 			&volume_name,
2908 			outbuf.data + 18,
2909 			nlen,
2910 			STR_UNICODE);
2911 	if (volume_name == NULL) {
2912 		status = map_nt_error_from_unix(errno);
2913 		goto fail;
2914 	}
2915 
2916 	*_volume_name = volume_name;
2917 
2918 fail:
2919 
2920 	if (fnum != 0xffff) {
2921 		cli_smb2_close_fnum(cli, fnum);
2922 	}
2923 
2924 	cli->raw_status = status;
2925 
2926 	TALLOC_FREE(frame);
2927 	return status;
2928 }
2929 
2930 
2931 /***************************************************************
2932  Wrapper that allows SMB2 to query a security descriptor.
2933  Synchronous only.
2934 ***************************************************************/
2935 
cli_smb2_query_security_descriptor(struct cli_state * cli,uint16_t fnum,uint32_t sec_info,TALLOC_CTX * mem_ctx,struct security_descriptor ** ppsd)2936 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2937 					uint16_t fnum,
2938 					uint32_t sec_info,
2939 					TALLOC_CTX *mem_ctx,
2940 					struct security_descriptor **ppsd)
2941 {
2942 	NTSTATUS status;
2943 	DATA_BLOB outbuf = data_blob_null;
2944 	struct security_descriptor *lsd = NULL;
2945 	TALLOC_CTX *frame = talloc_stackframe();
2946 
2947 	if (smbXcli_conn_has_async_calls(cli->conn)) {
2948 		/*
2949 		 * Can't use sync call while an async call is in flight
2950 		 */
2951 		status = NT_STATUS_INVALID_PARAMETER;
2952 		goto fail;
2953 	}
2954 
2955 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2956 		status = NT_STATUS_INVALID_PARAMETER;
2957 		goto fail;
2958 	}
2959 
2960 	/* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2961 
2962 	status = cli_smb2_query_info_fnum(
2963 		cli,
2964 		fnum,
2965 		3, /* in_info_type */
2966 		0, /* in_file_info_class */
2967 		0xFFFF, /* in_max_output_length */
2968 		NULL, /* in_input_buffer */
2969 		sec_info, /* in_additional_info */
2970 		0, /* in_flags */
2971 		frame,
2972 		&outbuf);
2973 
2974 	if (!NT_STATUS_IS_OK(status)) {
2975 		goto fail;
2976 	}
2977 
2978 	/* Parse the reply. */
2979 	status = unmarshall_sec_desc(mem_ctx,
2980 				outbuf.data,
2981 				outbuf.length,
2982 				&lsd);
2983 
2984 	if (!NT_STATUS_IS_OK(status)) {
2985 		goto fail;
2986 	}
2987 
2988 	if (ppsd != NULL) {
2989 		*ppsd = lsd;
2990 	} else {
2991 		TALLOC_FREE(lsd);
2992 	}
2993 
2994   fail:
2995 
2996 	cli->raw_status = status;
2997 
2998 	TALLOC_FREE(frame);
2999 	return status;
3000 }
3001 
3002 /***************************************************************
3003  Wrapper that allows SMB2 to set a security descriptor.
3004  Synchronous only.
3005 ***************************************************************/
3006 
cli_smb2_set_security_descriptor(struct cli_state * cli,uint16_t fnum,uint32_t sec_info,const struct security_descriptor * sd)3007 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
3008 					uint16_t fnum,
3009 					uint32_t sec_info,
3010 					const struct security_descriptor *sd)
3011 {
3012 	NTSTATUS status;
3013 	DATA_BLOB inbuf = data_blob_null;
3014 	TALLOC_CTX *frame = talloc_stackframe();
3015 
3016 	if (smbXcli_conn_has_async_calls(cli->conn)) {
3017 		/*
3018 		 * Can't use sync call while an async call is in flight
3019 		 */
3020 		status = NT_STATUS_INVALID_PARAMETER;
3021 		goto fail;
3022 	}
3023 
3024 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3025 		status = NT_STATUS_INVALID_PARAMETER;
3026 		goto fail;
3027 	}
3028 
3029 	status = marshall_sec_desc(frame,
3030 				sd,
3031 				&inbuf.data,
3032 				&inbuf.length);
3033 
3034         if (!NT_STATUS_IS_OK(status)) {
3035 		goto fail;
3036         }
3037 
3038 	/* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
3039 
3040 	status = cli_smb2_set_info_fnum(
3041 		cli,
3042 		fnum,
3043 		3,			  /* in_info_type */
3044 		0,			  /* in_file_info_class */
3045 		&inbuf,			  /* in_input_buffer */
3046 		sec_info);		  /* in_additional_info */
3047 
3048   fail:
3049 
3050 	cli->raw_status = status;
3051 
3052 	TALLOC_FREE(frame);
3053 	return status;
3054 }
3055 
3056 /***************************************************************
3057  Wrapper that allows SMB2 to query a security descriptor.
3058  Synchronous only.
3059 
3060 ***************************************************************/
3061 
3062 struct cli_smb2_mxac_state {
3063 	struct tevent_context *ev;
3064 	struct cli_state *cli;
3065 	const char *fname;
3066 	struct smb2_create_blobs in_cblobs;
3067 	uint16_t fnum;
3068 	NTSTATUS status;
3069 	uint32_t mxac;
3070 };
3071 
3072 static void cli_smb2_mxac_opened(struct tevent_req *subreq);
3073 static void cli_smb2_mxac_closed(struct tevent_req *subreq);
3074 
cli_smb2_query_mxac_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,const char * fname)3075 struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
3076 					    struct tevent_context *ev,
3077 					    struct cli_state *cli,
3078 					    const char *fname)
3079 {
3080 	struct tevent_req *req = NULL, *subreq = NULL;
3081 	struct cli_smb2_mxac_state *state = NULL;
3082 	NTSTATUS status;
3083 
3084 	req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
3085 	if (req == NULL) {
3086 		return NULL;
3087 	}
3088 	*state = (struct cli_smb2_mxac_state) {
3089 		.ev = ev,
3090 		.cli = cli,
3091 		.fname = fname,
3092 	};
3093 
3094 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3095 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3096 		return tevent_req_post(req, ev);
3097 	}
3098 
3099 	status = smb2_create_blob_add(state,
3100 				      &state->in_cblobs,
3101 				      SMB2_CREATE_TAG_MXAC,
3102 				      data_blob(NULL, 0));
3103 	if (tevent_req_nterror(req, status)) {
3104 		return tevent_req_post(req, ev);
3105 	}
3106 
3107 	subreq = cli_smb2_create_fnum_send(
3108 		state,
3109 		state->ev,
3110 		state->cli,
3111 		state->fname,
3112 		0,			/* create_flags */
3113 		SMB2_IMPERSONATION_IMPERSONATION,
3114 		FILE_READ_ATTRIBUTES,
3115 		0,			/* file attributes */
3116 		FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
3117 		FILE_OPEN,
3118 		0,			/* create_options */
3119 		&state->in_cblobs);
3120 	if (tevent_req_nomem(subreq, req)) {
3121 		return tevent_req_post(req, ev);
3122 	}
3123 	tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
3124 	return req;
3125 }
3126 
cli_smb2_mxac_opened(struct tevent_req * subreq)3127 static void cli_smb2_mxac_opened(struct tevent_req *subreq)
3128 {
3129 	struct tevent_req *req = tevent_req_callback_data(
3130 		subreq, struct tevent_req);
3131 	struct cli_smb2_mxac_state *state = tevent_req_data(
3132 		req, struct cli_smb2_mxac_state);
3133 	struct smb2_create_blobs out_cblobs = {0};
3134 	struct smb2_create_blob *mxac_blob = NULL;
3135 	NTSTATUS status;
3136 
3137 	status = cli_smb2_create_fnum_recv(
3138 		subreq, &state->fnum, NULL, state, &out_cblobs);
3139 	TALLOC_FREE(subreq);
3140 
3141 	if (tevent_req_nterror(req, status)) {
3142 		return;
3143 	}
3144 
3145 	mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
3146 	if (mxac_blob == NULL) {
3147 		state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3148 		goto close;
3149 	}
3150 	if (mxac_blob->data.length != 8) {
3151 		state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3152 		goto close;
3153 	}
3154 
3155 	state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
3156 	state->mxac = IVAL(mxac_blob->data.data, 4);
3157 
3158 close:
3159 	subreq = cli_smb2_close_fnum_send(
3160 		state, state->ev, state->cli, state->fnum);
3161 	if (tevent_req_nomem(subreq, req)) {
3162 		return;
3163 	}
3164 	tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
3165 
3166 	return;
3167 }
3168 
cli_smb2_mxac_closed(struct tevent_req * subreq)3169 static void cli_smb2_mxac_closed(struct tevent_req *subreq)
3170 {
3171 	struct tevent_req *req = tevent_req_callback_data(
3172 		subreq, struct tevent_req);
3173 	NTSTATUS status;
3174 
3175 	status = cli_smb2_close_fnum_recv(subreq);
3176 	if (tevent_req_nterror(req, status)) {
3177 		return;
3178 	}
3179 
3180 	tevent_req_done(req);
3181 }
3182 
cli_smb2_query_mxac_recv(struct tevent_req * req,uint32_t * mxac)3183 NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
3184 {
3185 	struct cli_smb2_mxac_state *state = tevent_req_data(
3186 		req, struct cli_smb2_mxac_state);
3187 	NTSTATUS status;
3188 
3189 	if (tevent_req_is_nterror(req, &status)) {
3190 		return status;
3191 	}
3192 
3193 	if (!NT_STATUS_IS_OK(state->status)) {
3194 		return state->status;
3195 	}
3196 
3197 	*mxac = state->mxac;
3198 	return NT_STATUS_OK;
3199 }
3200 
cli_smb2_query_mxac(struct cli_state * cli,const char * fname,uint32_t * _mxac)3201 NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
3202 			     const char *fname,
3203 			     uint32_t *_mxac)
3204 {
3205 	TALLOC_CTX *frame = talloc_stackframe();
3206 	struct tevent_context *ev = NULL;
3207 	struct tevent_req *req = NULL;
3208 	NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3209 	bool ok;
3210 
3211 	if (smbXcli_conn_has_async_calls(cli->conn)) {
3212 		/*
3213 		 * Can't use sync call while an async call is in flight
3214 		 */
3215 		status = NT_STATUS_INVALID_PARAMETER;
3216 		goto fail;
3217 	}
3218 
3219 	ev = samba_tevent_context_init(frame);
3220 	if (ev == NULL) {
3221 		goto fail;
3222 	}
3223 	req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
3224 	if (req == NULL) {
3225 		goto fail;
3226 	}
3227 	ok = tevent_req_poll_ntstatus(req, ev, &status);
3228 	if (!ok) {
3229 		goto fail;
3230 	}
3231 	status = cli_smb2_query_mxac_recv(req, _mxac);
3232 
3233 fail:
3234 	cli->raw_status = status;
3235 	TALLOC_FREE(frame);
3236 	return status;
3237 }
3238 
3239 /***************************************************************
3240  Wrapper that allows SMB2 to rename a file.
3241  Synchronous only.
3242 ***************************************************************/
3243 
cli_smb2_rename(struct cli_state * cli,const char * fname_src,const char * fname_dst,bool replace)3244 NTSTATUS cli_smb2_rename(struct cli_state *cli,
3245 			 const char *fname_src,
3246 			 const char *fname_dst,
3247 			 bool replace)
3248 {
3249 	NTSTATUS status;
3250 	DATA_BLOB inbuf = data_blob_null;
3251 	uint16_t fnum = 0xffff;
3252 	smb_ucs2_t *converted_str = NULL;
3253 	size_t converted_size_bytes = 0;
3254 	size_t namelen = 0;
3255 	size_t inbuf_size;
3256 	TALLOC_CTX *frame = talloc_stackframe();
3257 
3258 	if (smbXcli_conn_has_async_calls(cli->conn)) {
3259 		/*
3260 		 * Can't use sync call while an async call is in flight
3261 		 */
3262 		status = NT_STATUS_INVALID_PARAMETER;
3263 		goto fail;
3264 	}
3265 
3266 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3267 		status = NT_STATUS_INVALID_PARAMETER;
3268 		goto fail;
3269 	}
3270 
3271 	status = get_fnum_from_path(cli,
3272 				fname_src,
3273 				DELETE_ACCESS,
3274 				&fnum);
3275 
3276 	if (!NT_STATUS_IS_OK(status)) {
3277 		goto fail;
3278 	}
3279 
3280 	/* SMB2 is pickier about pathnames. Ensure it doesn't
3281 	   start in a '\' */
3282 	if (*fname_dst == '\\') {
3283 		fname_dst++;
3284 	}
3285 
3286 	/* SMB2 is pickier about pathnames. Ensure it doesn't
3287 	   end in a '\' */
3288 	namelen = strlen(fname_dst);
3289 	if (namelen > 0 && fname_dst[namelen-1] == '\\') {
3290 		char *modname = talloc_strdup(frame, fname_dst);
3291 		modname[namelen-1] = '\0';
3292 		fname_dst = modname;
3293 	}
3294 
3295 	if (!push_ucs2_talloc(frame,
3296 				&converted_str,
3297 				fname_dst,
3298 				&converted_size_bytes)) {
3299 		status = NT_STATUS_INVALID_PARAMETER;
3300 		goto fail;
3301 	}
3302 
3303 	/* W2K8 insists the dest name is not null
3304 	   terminated. Remove the last 2 zero bytes
3305 	   and reduce the name length. */
3306 
3307 	if (converted_size_bytes < 2) {
3308 		status = NT_STATUS_INVALID_PARAMETER;
3309 		goto fail;
3310 	}
3311 	converted_size_bytes -= 2;
3312 
3313 	inbuf_size = 20 + converted_size_bytes;
3314 	if (inbuf_size < 20) {
3315 		/* Integer wrap check. */
3316 		status = NT_STATUS_INVALID_PARAMETER;
3317 		goto fail;
3318 	}
3319 
3320 	/*
3321 	 * The Windows 10 SMB2 server has a minimum length
3322 	 * for a SMB2_FILE_RENAME_INFORMATION buffer of
3323 	 * 24 bytes. It returns NT_STATUS_INFO_LENGTH_MISMATCH
3324 	 * if the length is less. This isn't an alignment
3325 	 * issue as Windows client happily 2-byte align
3326 	 * for larget target name sizes. Also the Windows 10
3327 	 * SMB1 server doesn't have this restriction.
3328 	 *
3329 	 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14403
3330 	 */
3331 	if (inbuf_size < 24) {
3332 		inbuf_size = 24;
3333 	}
3334 
3335 	inbuf = data_blob_talloc_zero(frame, inbuf_size);
3336 	if (inbuf.data == NULL) {
3337 		status = NT_STATUS_NO_MEMORY;
3338 		goto fail;
3339 	}
3340 
3341 	if (replace) {
3342 		SCVAL(inbuf.data, 0, 1);
3343 	}
3344 
3345 	SIVAL(inbuf.data, 16, converted_size_bytes);
3346 	memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
3347 
3348 	/* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3349 	   level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3350 
3351 	status = cli_smb2_set_info_fnum(
3352 		cli,
3353 		fnum,
3354 		1,		/* in_info_type */
3355 		SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
3356 		&inbuf,		   /* in_input_buffer */
3357 		0);		   /* in_additional_info */
3358 
3359   fail:
3360 
3361 	if (fnum != 0xffff) {
3362 		cli_smb2_close_fnum(cli, fnum);
3363 	}
3364 
3365 	cli->raw_status = status;
3366 
3367 	TALLOC_FREE(frame);
3368 	return status;
3369 }
3370 
3371 /***************************************************************
3372  Wrapper that allows SMB2 to set an EA on a fnum.
3373  Synchronous only.
3374 ***************************************************************/
3375 
cli_smb2_set_ea_fnum(struct cli_state * cli,uint16_t fnum,const char * ea_name,const char * ea_val,size_t ea_len)3376 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
3377 			uint16_t fnum,
3378 			const char *ea_name,
3379 			const char *ea_val,
3380 			size_t ea_len)
3381 {
3382 	NTSTATUS status;
3383 	DATA_BLOB inbuf = data_blob_null;
3384 	size_t bloblen = 0;
3385 	char *ea_name_ascii = NULL;
3386 	size_t namelen = 0;
3387 	TALLOC_CTX *frame = talloc_stackframe();
3388 
3389 	if (smbXcli_conn_has_async_calls(cli->conn)) {
3390 		/*
3391 		 * Can't use sync call while an async call is in flight
3392 		 */
3393 		status = NT_STATUS_INVALID_PARAMETER;
3394 		goto fail;
3395 	}
3396 
3397 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3398 		status = NT_STATUS_INVALID_PARAMETER;
3399 		goto fail;
3400 	}
3401 
3402 	/* Marshall the SMB2 EA data. */
3403 	if (ea_len > 0xFFFF) {
3404 		status = NT_STATUS_INVALID_PARAMETER;
3405 		goto fail;
3406 	}
3407 
3408 	if (!push_ascii_talloc(frame,
3409 				&ea_name_ascii,
3410 				ea_name,
3411 				&namelen)) {
3412 		status = NT_STATUS_INVALID_PARAMETER;
3413 		goto fail;
3414 	}
3415 
3416 	if (namelen < 2 || namelen > 0xFF) {
3417 		status = NT_STATUS_INVALID_PARAMETER;
3418 		goto fail;
3419 	}
3420 
3421 	bloblen = 8 + ea_len + namelen;
3422 	/* Round up to a 4 byte boundary. */
3423 	bloblen = ((bloblen + 3)&~3);
3424 
3425 	inbuf = data_blob_talloc_zero(frame, bloblen);
3426 	if (inbuf.data == NULL) {
3427 		status = NT_STATUS_NO_MEMORY;
3428 		goto fail;
3429 	}
3430 	/* namelen doesn't include the NULL byte. */
3431 	SCVAL(inbuf.data, 5, namelen - 1);
3432 	SSVAL(inbuf.data, 6, ea_len);
3433 	memcpy(inbuf.data + 8, ea_name_ascii, namelen);
3434 	memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
3435 
3436 	/* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3437 	   level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3438 
3439 	status = cli_smb2_set_info_fnum(
3440 		cli,
3441 		fnum,
3442 		1,		/* in_info_type */
3443 		SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3444 		&inbuf,		/* in_input_buffer */
3445 		0);		/* in_additional_info */
3446 
3447   fail:
3448 
3449 	cli->raw_status = status;
3450 
3451 	TALLOC_FREE(frame);
3452 	return status;
3453 }
3454 
3455 /***************************************************************
3456  Wrapper that allows SMB2 to set an EA on a pathname.
3457  Synchronous only.
3458 ***************************************************************/
3459 
cli_smb2_set_ea_path(struct cli_state * cli,const char * name,const char * ea_name,const char * ea_val,size_t ea_len)3460 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3461 			const char *name,
3462 			const char *ea_name,
3463 			const char *ea_val,
3464 			size_t ea_len)
3465 {
3466 	NTSTATUS status;
3467 	uint16_t fnum = 0xffff;
3468 
3469 	if (smbXcli_conn_has_async_calls(cli->conn)) {
3470 		/*
3471 		 * Can't use sync call while an async call is in flight
3472 		 */
3473 		status = NT_STATUS_INVALID_PARAMETER;
3474 		goto fail;
3475 	}
3476 
3477 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3478 		status = NT_STATUS_INVALID_PARAMETER;
3479 		goto fail;
3480 	}
3481 
3482 	status = get_fnum_from_path(cli,
3483 				name,
3484 				FILE_WRITE_EA,
3485 				&fnum);
3486 
3487 	if (!NT_STATUS_IS_OK(status)) {
3488 		goto fail;
3489 	}
3490 
3491 	status = cli_set_ea_fnum(cli,
3492 				fnum,
3493 				ea_name,
3494 				ea_val,
3495 				ea_len);
3496 	if (!NT_STATUS_IS_OK(status)) {
3497 		goto fail;
3498 	}
3499 
3500   fail:
3501 
3502 	if (fnum != 0xffff) {
3503 		cli_smb2_close_fnum(cli, fnum);
3504 	}
3505 
3506 	cli->raw_status = status;
3507 
3508 	return status;
3509 }
3510 
3511 /***************************************************************
3512  Wrapper that allows SMB2 to get an EA list on a pathname.
3513  Synchronous only.
3514 ***************************************************************/
3515 
cli_smb2_get_ea_list_path(struct cli_state * cli,const char * name,TALLOC_CTX * ctx,size_t * pnum_eas,struct ea_struct ** pea_array)3516 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
3517 				const char *name,
3518 				TALLOC_CTX *ctx,
3519 				size_t *pnum_eas,
3520 				struct ea_struct **pea_array)
3521 {
3522 	NTSTATUS status;
3523 	uint16_t fnum = 0xffff;
3524 	DATA_BLOB outbuf = data_blob_null;
3525 	struct ea_list *ea_list = NULL;
3526 	struct ea_list *eal = NULL;
3527 	size_t ea_count = 0;
3528 	TALLOC_CTX *frame = talloc_stackframe();
3529 
3530 	*pnum_eas = 0;
3531 	*pea_array = NULL;
3532 
3533 	if (smbXcli_conn_has_async_calls(cli->conn)) {
3534 		/*
3535 		 * Can't use sync call while an async call is in flight
3536 		 */
3537 		status = NT_STATUS_INVALID_PARAMETER;
3538 		goto fail;
3539 	}
3540 
3541 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3542 		status = NT_STATUS_INVALID_PARAMETER;
3543 		goto fail;
3544 	}
3545 
3546 	status = get_fnum_from_path(cli,
3547 				name,
3548 				FILE_READ_EA,
3549 				&fnum);
3550 
3551 	if (!NT_STATUS_IS_OK(status)) {
3552 		goto fail;
3553 	}
3554 
3555 	/* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3556 	   level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3557 
3558 	status = cli_smb2_query_info_fnum(
3559 		cli,
3560 		fnum,
3561 		1, /* in_info_type */
3562 		SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3563 		0xFFFF, /* in_max_output_length */
3564 		NULL, /* in_input_buffer */
3565 		0, /* in_additional_info */
3566 		0, /* in_flags */
3567 		frame,
3568 		&outbuf);
3569 
3570 	if (!NT_STATUS_IS_OK(status)) {
3571 		goto fail;
3572 	}
3573 
3574 	/* Parse the reply. */
3575 	ea_list = read_nttrans_ea_list(ctx,
3576 				(const char *)outbuf.data,
3577 				outbuf.length);
3578 	if (ea_list == NULL) {
3579 		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3580 		goto fail;
3581 	}
3582 
3583 	/* Convert to an array. */
3584 	for (eal = ea_list; eal; eal = eal->next) {
3585 		ea_count++;
3586 	}
3587 
3588 	if (ea_count) {
3589 		*pea_array = talloc_array(ctx, struct ea_struct, ea_count);
3590 		if (*pea_array == NULL) {
3591 			status = NT_STATUS_NO_MEMORY;
3592 			goto fail;
3593 		}
3594 		ea_count = 0;
3595 		for (eal = ea_list; eal; eal = eal->next) {
3596 			(*pea_array)[ea_count++] = eal->ea;
3597 		}
3598 		*pnum_eas = ea_count;
3599 	}
3600 
3601   fail:
3602 
3603 	if (fnum != 0xffff) {
3604 		cli_smb2_close_fnum(cli, fnum);
3605 	}
3606 
3607 	cli->raw_status = status;
3608 
3609 	TALLOC_FREE(frame);
3610 	return status;
3611 }
3612 
3613 /***************************************************************
3614  Wrapper that allows SMB2 to get user quota.
3615  Synchronous only.
3616 ***************************************************************/
3617 
cli_smb2_get_user_quota(struct cli_state * cli,int quota_fnum,SMB_NTQUOTA_STRUCT * pqt)3618 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
3619 				 int quota_fnum,
3620 				 SMB_NTQUOTA_STRUCT *pqt)
3621 {
3622 	NTSTATUS status;
3623 	DATA_BLOB inbuf = data_blob_null;
3624 	DATA_BLOB info_blob = data_blob_null;
3625 	DATA_BLOB outbuf = data_blob_null;
3626 	TALLOC_CTX *frame = talloc_stackframe();
3627 	unsigned sid_len;
3628 	unsigned int offset;
3629 	struct smb2_query_quota_info query = {0};
3630 	struct file_get_quota_info info = {0};
3631 	enum ndr_err_code err;
3632 	struct ndr_push *ndr_push = NULL;
3633 
3634 	if (smbXcli_conn_has_async_calls(cli->conn)) {
3635 		/*
3636 		 * Can't use sync call while an async call is in flight
3637 		 */
3638 		status = NT_STATUS_INVALID_PARAMETER;
3639 		goto fail;
3640 	}
3641 
3642 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3643 		status = NT_STATUS_INVALID_PARAMETER;
3644 		goto fail;
3645 	}
3646 
3647 	sid_len = ndr_size_dom_sid(&pqt->sid, 0);
3648 
3649 	query.return_single = 1;
3650 
3651 	info.next_entry_offset = 0;
3652 	info.sid_length = sid_len;
3653 	info.sid = pqt->sid;
3654 
3655 	err = ndr_push_struct_blob(
3656 			&info_blob,
3657 			frame,
3658 			&info,
3659 			(ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3660 
3661 	if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3662 		status = NT_STATUS_INTERNAL_ERROR;
3663 		goto fail;
3664 	}
3665 
3666 	query.sid_list_length = info_blob.length;
3667 	ndr_push = ndr_push_init_ctx(frame);
3668 	if (!ndr_push) {
3669 		status = NT_STATUS_NO_MEMORY;
3670 		goto fail;
3671 	}
3672 
3673 	err = ndr_push_smb2_query_quota_info(ndr_push,
3674 					     NDR_SCALARS | NDR_BUFFERS,
3675 					     &query);
3676 
3677 	if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3678 		status = NT_STATUS_INTERNAL_ERROR;
3679 		goto fail;
3680 	}
3681 
3682 	err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3683 				   info_blob.length);
3684 
3685 	if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3686 		status = NT_STATUS_INTERNAL_ERROR;
3687 		goto fail;
3688 	}
3689 	inbuf.data = ndr_push->data;
3690 	inbuf.length = ndr_push->offset;
3691 
3692 	status = cli_smb2_query_info_fnum(
3693 		cli,
3694 		quota_fnum,
3695 		4, /* in_info_type */
3696 		0,		       /* in_file_info_class */
3697 		0xFFFF, /* in_max_output_length */
3698 		&inbuf, /* in_input_buffer */
3699 		0,      /* in_additional_info */
3700 		0,      /* in_flags */
3701 		frame,
3702 		&outbuf);
3703 
3704 	if (!NT_STATUS_IS_OK(status)) {
3705 		goto fail;
3706 	}
3707 
3708 	if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3709 				     pqt)) {
3710 		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3711 		DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3712 	}
3713 
3714 fail:
3715 	cli->raw_status = status;
3716 
3717 	TALLOC_FREE(frame);
3718 	return status;
3719 }
3720 
3721 /***************************************************************
3722  Wrapper that allows SMB2 to list user quota.
3723  Synchronous only.
3724 ***************************************************************/
3725 
cli_smb2_list_user_quota_step(struct cli_state * cli,TALLOC_CTX * mem_ctx,int quota_fnum,SMB_NTQUOTA_LIST ** pqt_list,bool first)3726 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3727 				       TALLOC_CTX *mem_ctx,
3728 				       int quota_fnum,
3729 				       SMB_NTQUOTA_LIST **pqt_list,
3730 				       bool first)
3731 {
3732 	NTSTATUS status;
3733 	DATA_BLOB inbuf = data_blob_null;
3734 	DATA_BLOB outbuf = data_blob_null;
3735 	TALLOC_CTX *frame = talloc_stackframe();
3736 	struct smb2_query_quota_info info = {0};
3737 	enum ndr_err_code err;
3738 
3739 	if (smbXcli_conn_has_async_calls(cli->conn)) {
3740 		/*
3741 		 * Can't use sync call while an async call is in flight
3742 		 */
3743 		status = NT_STATUS_INVALID_PARAMETER;
3744 		goto cleanup;
3745 	}
3746 
3747 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3748 		status = NT_STATUS_INVALID_PARAMETER;
3749 		goto cleanup;
3750 	}
3751 
3752 	info.restart_scan = first ? 1 : 0;
3753 
3754 	err = ndr_push_struct_blob(
3755 			&inbuf,
3756 			frame,
3757 			&info,
3758 			(ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3759 
3760 	if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3761 		status = NT_STATUS_INTERNAL_ERROR;
3762 		goto cleanup;
3763 	}
3764 
3765 	status = cli_smb2_query_info_fnum(
3766 		cli,
3767 		quota_fnum,
3768 		4, /* in_info_type */
3769 		0, /* in_file_info_class */
3770 		0xFFFF, /* in_max_output_length */
3771 		&inbuf, /* in_input_buffer */
3772 		0,      /* in_additional_info */
3773 		0,      /* in_flags */
3774 		frame,
3775 		&outbuf);
3776 
3777 	/*
3778 	 * safeguard against panic from calling parse_user_quota_list with
3779 	 * NULL buffer
3780 	 */
3781 	if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3782 		status = NT_STATUS_NO_MORE_ENTRIES;
3783 	}
3784 
3785 	if (!NT_STATUS_IS_OK(status)) {
3786 		goto cleanup;
3787 	}
3788 
3789 	status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3790 				       pqt_list);
3791 
3792 cleanup:
3793 	cli->raw_status = status;
3794 
3795 	TALLOC_FREE(frame);
3796 	return status;
3797 }
3798 
3799 /***************************************************************
3800  Wrapper that allows SMB2 to get file system quota.
3801  Synchronous only.
3802 ***************************************************************/
3803 
cli_smb2_get_fs_quota_info(struct cli_state * cli,int quota_fnum,SMB_NTQUOTA_STRUCT * pqt)3804 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3805 				    int quota_fnum,
3806 				    SMB_NTQUOTA_STRUCT *pqt)
3807 {
3808 	NTSTATUS status;
3809 	DATA_BLOB outbuf = data_blob_null;
3810 	TALLOC_CTX *frame = talloc_stackframe();
3811 
3812 	if (smbXcli_conn_has_async_calls(cli->conn)) {
3813 		/*
3814 		 * Can't use sync call while an async call is in flight
3815 		 */
3816 		status = NT_STATUS_INVALID_PARAMETER;
3817 		goto cleanup;
3818 	}
3819 
3820 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3821 		status = NT_STATUS_INVALID_PARAMETER;
3822 		goto cleanup;
3823 	}
3824 
3825 	status = cli_smb2_query_info_fnum(
3826 		cli,
3827 		quota_fnum,
3828 		2,				     /* in_info_type */
3829 		SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3830 		0xFFFF,			     /* in_max_output_length */
3831 		NULL,			     /* in_input_buffer */
3832 		0,				     /* in_additional_info */
3833 		0,				     /* in_flags */
3834 		frame,
3835 		&outbuf);
3836 
3837 	if (!NT_STATUS_IS_OK(status)) {
3838 		goto cleanup;
3839 	}
3840 
3841 	status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3842 
3843 cleanup:
3844 	cli->raw_status = status;
3845 
3846 	TALLOC_FREE(frame);
3847 	return status;
3848 }
3849 
3850 /***************************************************************
3851  Wrapper that allows SMB2 to set user quota.
3852  Synchronous only.
3853 ***************************************************************/
3854 
cli_smb2_set_user_quota(struct cli_state * cli,int quota_fnum,SMB_NTQUOTA_LIST * qtl)3855 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3856 				 int quota_fnum,
3857 				 SMB_NTQUOTA_LIST *qtl)
3858 {
3859 	NTSTATUS status;
3860 	DATA_BLOB inbuf = data_blob_null;
3861 	TALLOC_CTX *frame = talloc_stackframe();
3862 
3863 	if (smbXcli_conn_has_async_calls(cli->conn)) {
3864 		/*
3865 		 * Can't use sync call while an async call is in flight
3866 		 */
3867 		status = NT_STATUS_INVALID_PARAMETER;
3868 		goto cleanup;
3869 	}
3870 
3871 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3872 		status = NT_STATUS_INVALID_PARAMETER;
3873 		goto cleanup;
3874 	}
3875 
3876 	status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3877 	if (!NT_STATUS_IS_OK(status)) {
3878 		goto cleanup;
3879 	}
3880 
3881 	status = cli_smb2_set_info_fnum(
3882 		cli,
3883 		quota_fnum,
3884 		4,			  /* in_info_type */
3885 		0,			  /* in_file_info_class */
3886 		&inbuf,			  /* in_input_buffer */
3887 		0);			  /* in_additional_info */
3888 cleanup:
3889 
3890 	cli->raw_status = status;
3891 
3892 	TALLOC_FREE(frame);
3893 
3894 	return status;
3895 }
3896 
cli_smb2_set_fs_quota_info(struct cli_state * cli,int quota_fnum,SMB_NTQUOTA_STRUCT * pqt)3897 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3898 				    int quota_fnum,
3899 				    SMB_NTQUOTA_STRUCT *pqt)
3900 {
3901 	NTSTATUS status;
3902 	DATA_BLOB inbuf = data_blob_null;
3903 	TALLOC_CTX *frame = talloc_stackframe();
3904 
3905 	if (smbXcli_conn_has_async_calls(cli->conn)) {
3906 		/*
3907 		 * Can't use sync call while an async call is in flight
3908 		 */
3909 		status = NT_STATUS_INVALID_PARAMETER;
3910 		goto cleanup;
3911 	}
3912 
3913 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3914 		status = NT_STATUS_INVALID_PARAMETER;
3915 		goto cleanup;
3916 	}
3917 
3918 	status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3919 	if (!NT_STATUS_IS_OK(status)) {
3920 		goto cleanup;
3921 	}
3922 
3923 	status = cli_smb2_set_info_fnum(
3924 		cli,
3925 		quota_fnum,
3926 		2,			     /* in_info_type */
3927 		SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3928 		&inbuf,			     /* in_input_buffer */
3929 		0);			     /* in_additional_info */
3930 cleanup:
3931 	cli->raw_status = status;
3932 
3933 	TALLOC_FREE(frame);
3934 	return status;
3935 }
3936 
3937 struct cli_smb2_read_state {
3938 	struct tevent_context *ev;
3939 	struct cli_state *cli;
3940 	struct smb2_hnd *ph;
3941 	uint64_t start_offset;
3942 	uint32_t size;
3943 	uint32_t received;
3944 	uint8_t *buf;
3945 };
3946 
3947 static void cli_smb2_read_done(struct tevent_req *subreq);
3948 
cli_smb2_read_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum,off_t offset,size_t size)3949 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3950 				struct tevent_context *ev,
3951 				struct cli_state *cli,
3952 				uint16_t fnum,
3953 				off_t offset,
3954 				size_t size)
3955 {
3956 	NTSTATUS status;
3957 	struct tevent_req *req, *subreq;
3958 	struct cli_smb2_read_state *state;
3959 
3960 	req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3961 	if (req == NULL) {
3962 		return NULL;
3963 	}
3964 	state->ev = ev;
3965 	state->cli = cli;
3966 	state->start_offset = (uint64_t)offset;
3967 	state->size = (uint32_t)size;
3968 	state->received = 0;
3969 	state->buf = NULL;
3970 
3971 	status = map_fnum_to_smb2_handle(cli,
3972 					fnum,
3973 					&state->ph);
3974 	if (tevent_req_nterror(req, status)) {
3975 		return tevent_req_post(req, ev);
3976 	}
3977 
3978 	subreq = smb2cli_read_send(state,
3979 				state->ev,
3980 				state->cli->conn,
3981 				state->cli->timeout,
3982 				state->cli->smb2.session,
3983 				state->cli->smb2.tcon,
3984 				state->size,
3985 				state->start_offset,
3986 				state->ph->fid_persistent,
3987 				state->ph->fid_volatile,
3988 				0, /* minimum_count */
3989 				0); /* remaining_bytes */
3990 
3991 	if (tevent_req_nomem(subreq, req)) {
3992 		return tevent_req_post(req, ev);
3993 	}
3994 	tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3995 	return req;
3996 }
3997 
cli_smb2_read_done(struct tevent_req * subreq)3998 static void cli_smb2_read_done(struct tevent_req *subreq)
3999 {
4000 	struct tevent_req *req = tevent_req_callback_data(
4001 		subreq, struct tevent_req);
4002 	struct cli_smb2_read_state *state = tevent_req_data(
4003 		req, struct cli_smb2_read_state);
4004 	NTSTATUS status;
4005 
4006 	status = smb2cli_read_recv(subreq, state,
4007 				   &state->buf, &state->received);
4008 	if (tevent_req_nterror(req, status)) {
4009 		return;
4010 	}
4011 
4012 	if (state->received > state->size) {
4013 		tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4014 		return;
4015 	}
4016 
4017 	tevent_req_done(req);
4018 }
4019 
cli_smb2_read_recv(struct tevent_req * req,ssize_t * received,uint8_t ** rcvbuf)4020 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
4021 				ssize_t *received,
4022 				uint8_t **rcvbuf)
4023 {
4024 	NTSTATUS status;
4025 	struct cli_smb2_read_state *state = tevent_req_data(
4026 				req, struct cli_smb2_read_state);
4027 
4028 	if (tevent_req_is_nterror(req, &status)) {
4029 		state->cli->raw_status = status;
4030 		return status;
4031 	}
4032 	/*
4033 	 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
4034 	 * better make sure that you copy it away before you talloc_free(req).
4035 	 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
4036 	 */
4037 	*received = (ssize_t)state->received;
4038 	*rcvbuf = state->buf;
4039 	state->cli->raw_status = NT_STATUS_OK;
4040 	return NT_STATUS_OK;
4041 }
4042 
4043 struct cli_smb2_write_state {
4044 	struct tevent_context *ev;
4045 	struct cli_state *cli;
4046 	struct smb2_hnd *ph;
4047 	uint32_t flags;
4048 	const uint8_t *buf;
4049 	uint64_t offset;
4050 	uint32_t size;
4051 	uint32_t written;
4052 };
4053 
4054 static void cli_smb2_write_written(struct tevent_req *req);
4055 
cli_smb2_write_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum,uint16_t mode,const uint8_t * buf,off_t offset,size_t size)4056 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
4057 					struct tevent_context *ev,
4058 					struct cli_state *cli,
4059 					uint16_t fnum,
4060 					uint16_t mode,
4061 					const uint8_t *buf,
4062 					off_t offset,
4063 					size_t size)
4064 {
4065 	NTSTATUS status;
4066 	struct tevent_req *req, *subreq = NULL;
4067 	struct cli_smb2_write_state *state = NULL;
4068 
4069 	req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
4070 	if (req == NULL) {
4071 		return NULL;
4072 	}
4073 	state->ev = ev;
4074 	state->cli = cli;
4075 	/* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4076 	state->flags = (uint32_t)mode;
4077 	state->buf = buf;
4078 	state->offset = (uint64_t)offset;
4079 	state->size = (uint32_t)size;
4080 	state->written = 0;
4081 
4082 	status = map_fnum_to_smb2_handle(cli,
4083 					fnum,
4084 					&state->ph);
4085 	if (tevent_req_nterror(req, status)) {
4086 		return tevent_req_post(req, ev);
4087 	}
4088 
4089 	subreq = smb2cli_write_send(state,
4090 				state->ev,
4091 				state->cli->conn,
4092 				state->cli->timeout,
4093 				state->cli->smb2.session,
4094 				state->cli->smb2.tcon,
4095 				state->size,
4096 				state->offset,
4097 				state->ph->fid_persistent,
4098 				state->ph->fid_volatile,
4099 				0, /* remaining_bytes */
4100 				state->flags, /* flags */
4101 				state->buf);
4102 
4103 	if (tevent_req_nomem(subreq, req)) {
4104 		return tevent_req_post(req, ev);
4105 	}
4106 	tevent_req_set_callback(subreq, cli_smb2_write_written, req);
4107 	return req;
4108 }
4109 
cli_smb2_write_written(struct tevent_req * subreq)4110 static void cli_smb2_write_written(struct tevent_req *subreq)
4111 {
4112 	struct tevent_req *req = tevent_req_callback_data(
4113 		subreq, struct tevent_req);
4114 	struct cli_smb2_write_state *state = tevent_req_data(
4115 		req, struct cli_smb2_write_state);
4116         NTSTATUS status;
4117 	uint32_t written;
4118 
4119 	status = smb2cli_write_recv(subreq, &written);
4120 	TALLOC_FREE(subreq);
4121 	if (tevent_req_nterror(req, status)) {
4122 		return;
4123 	}
4124 
4125 	state->written = written;
4126 
4127 	tevent_req_done(req);
4128 }
4129 
cli_smb2_write_recv(struct tevent_req * req,size_t * pwritten)4130 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
4131 			     size_t *pwritten)
4132 {
4133 	struct cli_smb2_write_state *state = tevent_req_data(
4134 		req, struct cli_smb2_write_state);
4135 	NTSTATUS status;
4136 
4137 	if (tevent_req_is_nterror(req, &status)) {
4138 		state->cli->raw_status = status;
4139 		tevent_req_received(req);
4140 		return status;
4141 	}
4142 
4143 	if (pwritten != NULL) {
4144 		*pwritten = (size_t)state->written;
4145 	}
4146 	state->cli->raw_status = NT_STATUS_OK;
4147 	tevent_req_received(req);
4148 	return NT_STATUS_OK;
4149 }
4150 
4151 /***************************************************************
4152  Wrapper that allows SMB2 async write using an fnum.
4153  This is mostly cut-and-paste from Volker's code inside
4154  source3/libsmb/clireadwrite.c, adapted for SMB2.
4155 
4156  Done this way so I can reuse all the logic inside cli_push()
4157  for free :-).
4158 ***************************************************************/
4159 
4160 struct cli_smb2_writeall_state {
4161 	struct tevent_context *ev;
4162 	struct cli_state *cli;
4163 	struct smb2_hnd *ph;
4164 	uint32_t flags;
4165 	const uint8_t *buf;
4166 	uint64_t offset;
4167 	uint32_t size;
4168 	uint32_t written;
4169 };
4170 
4171 static void cli_smb2_writeall_written(struct tevent_req *req);
4172 
cli_smb2_writeall_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum,uint16_t mode,const uint8_t * buf,off_t offset,size_t size)4173 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
4174 					struct tevent_context *ev,
4175 					struct cli_state *cli,
4176 					uint16_t fnum,
4177 					uint16_t mode,
4178 					const uint8_t *buf,
4179 					off_t offset,
4180 					size_t size)
4181 {
4182 	NTSTATUS status;
4183 	struct tevent_req *req, *subreq = NULL;
4184 	struct cli_smb2_writeall_state *state = NULL;
4185 	uint32_t to_write;
4186 	uint32_t max_size;
4187 	bool ok;
4188 
4189 	req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
4190 	if (req == NULL) {
4191 		return NULL;
4192 	}
4193 	state->ev = ev;
4194 	state->cli = cli;
4195 	/* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4196 	state->flags = (uint32_t)mode;
4197 	state->buf = buf;
4198 	state->offset = (uint64_t)offset;
4199 	state->size = (uint32_t)size;
4200 	state->written = 0;
4201 
4202 	status = map_fnum_to_smb2_handle(cli,
4203 					fnum,
4204 					&state->ph);
4205 	if (tevent_req_nterror(req, status)) {
4206 		return tevent_req_post(req, ev);
4207 	}
4208 
4209 	to_write = state->size;
4210 	max_size = smb2cli_conn_max_write_size(state->cli->conn);
4211 	to_write = MIN(max_size, to_write);
4212 	ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4213 	if (ok) {
4214 		to_write = MIN(max_size, to_write);
4215 	}
4216 
4217 	subreq = smb2cli_write_send(state,
4218 				state->ev,
4219 				state->cli->conn,
4220 				state->cli->timeout,
4221 				state->cli->smb2.session,
4222 				state->cli->smb2.tcon,
4223 				to_write,
4224 				state->offset,
4225 				state->ph->fid_persistent,
4226 				state->ph->fid_volatile,
4227 				0, /* remaining_bytes */
4228 				state->flags, /* flags */
4229 				state->buf + state->written);
4230 
4231 	if (tevent_req_nomem(subreq, req)) {
4232 		return tevent_req_post(req, ev);
4233 	}
4234 	tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4235 	return req;
4236 }
4237 
cli_smb2_writeall_written(struct tevent_req * subreq)4238 static void cli_smb2_writeall_written(struct tevent_req *subreq)
4239 {
4240 	struct tevent_req *req = tevent_req_callback_data(
4241 		subreq, struct tevent_req);
4242 	struct cli_smb2_writeall_state *state = tevent_req_data(
4243 		req, struct cli_smb2_writeall_state);
4244         NTSTATUS status;
4245 	uint32_t written, to_write;
4246 	uint32_t max_size;
4247 	bool ok;
4248 
4249 	status = smb2cli_write_recv(subreq, &written);
4250 	TALLOC_FREE(subreq);
4251 	if (tevent_req_nterror(req, status)) {
4252 		return;
4253 	}
4254 
4255 	state->written += written;
4256 
4257 	if (state->written > state->size) {
4258 		tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4259 		return;
4260 	}
4261 
4262 	to_write = state->size - state->written;
4263 
4264 	if (to_write == 0) {
4265 		tevent_req_done(req);
4266 		return;
4267 	}
4268 
4269 	max_size = smb2cli_conn_max_write_size(state->cli->conn);
4270 	to_write = MIN(max_size, to_write);
4271 	ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4272 	if (ok) {
4273 		to_write = MIN(max_size, to_write);
4274 	}
4275 
4276 	subreq = smb2cli_write_send(state,
4277 				state->ev,
4278 				state->cli->conn,
4279 				state->cli->timeout,
4280 				state->cli->smb2.session,
4281 				state->cli->smb2.tcon,
4282 				to_write,
4283 				state->offset + state->written,
4284 				state->ph->fid_persistent,
4285 				state->ph->fid_volatile,
4286 				0, /* remaining_bytes */
4287 				state->flags, /* flags */
4288 				state->buf + state->written);
4289 
4290 	if (tevent_req_nomem(subreq, req)) {
4291 		return;
4292 	}
4293 	tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4294 }
4295 
cli_smb2_writeall_recv(struct tevent_req * req,size_t * pwritten)4296 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
4297 				size_t *pwritten)
4298 {
4299 	struct cli_smb2_writeall_state *state = tevent_req_data(
4300 		req, struct cli_smb2_writeall_state);
4301 	NTSTATUS status;
4302 
4303 	if (tevent_req_is_nterror(req, &status)) {
4304 		state->cli->raw_status = status;
4305 		return status;
4306 	}
4307 	if (pwritten != NULL) {
4308 		*pwritten = (size_t)state->written;
4309 	}
4310 	state->cli->raw_status = NT_STATUS_OK;
4311 	return NT_STATUS_OK;
4312 }
4313 
4314 struct cli_smb2_splice_state {
4315 	struct tevent_context *ev;
4316 	struct cli_state *cli;
4317 	struct smb2_hnd *src_ph;
4318 	struct smb2_hnd *dst_ph;
4319 	int (*splice_cb)(off_t n, void *priv);
4320 	void *priv;
4321 	off_t written;
4322 	off_t size;
4323 	off_t src_offset;
4324 	off_t dst_offset;
4325 	bool resized;
4326 	struct req_resume_key_rsp resume_rsp;
4327 	struct srv_copychunk_copy cc_copy;
4328 };
4329 
4330 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4331 				      struct tevent_req *req);
4332 
cli_splice_copychunk_done(struct tevent_req * subreq)4333 static void cli_splice_copychunk_done(struct tevent_req *subreq)
4334 {
4335 	struct tevent_req *req = tevent_req_callback_data(
4336 		subreq, struct tevent_req);
4337 	struct cli_smb2_splice_state *state =
4338 		tevent_req_data(req,
4339 		struct cli_smb2_splice_state);
4340 	struct smbXcli_conn *conn = state->cli->conn;
4341 	DATA_BLOB out_input_buffer = data_blob_null;
4342 	DATA_BLOB out_output_buffer = data_blob_null;
4343 	struct srv_copychunk_rsp cc_copy_rsp;
4344 	enum ndr_err_code ndr_ret;
4345 	NTSTATUS status;
4346 
4347 	status = smb2cli_ioctl_recv(subreq, state,
4348 				    &out_input_buffer,
4349 				    &out_output_buffer);
4350 	TALLOC_FREE(subreq);
4351 	if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
4352 	     state->resized) && tevent_req_nterror(req, status)) {
4353 		return;
4354 	}
4355 
4356 	ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
4357 			(ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
4358 	if (ndr_ret != NDR_ERR_SUCCESS) {
4359 		DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4360 		tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4361 		return;
4362 	}
4363 
4364 	if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
4365 		uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
4366 			     cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
4367 		if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
4368 		     max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
4369 		     tevent_req_nterror(req, status)) {
4370 			return;
4371 		}
4372 
4373 		state->resized = true;
4374 		smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
4375 		smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
4376 	} else {
4377 		if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4378 		    (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4379 		    (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
4380 			tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4381 			return;
4382 		}
4383 		state->src_offset += cc_copy_rsp.total_bytes_written;
4384 		state->dst_offset += cc_copy_rsp.total_bytes_written;
4385 		state->written += cc_copy_rsp.total_bytes_written;
4386 		if (!state->splice_cb(state->written, state->priv)) {
4387 			tevent_req_nterror(req, NT_STATUS_CANCELLED);
4388 			return;
4389 		}
4390 	}
4391 
4392 	cli_splice_copychunk_send(state, req);
4393 }
4394 
cli_splice_copychunk_send(struct cli_smb2_splice_state * state,struct tevent_req * req)4395 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4396 				      struct tevent_req *req)
4397 {
4398 	struct tevent_req *subreq;
4399 	enum ndr_err_code ndr_ret;
4400 	struct smbXcli_conn *conn = state->cli->conn;
4401 	struct srv_copychunk_copy *cc_copy = &state->cc_copy;
4402 	off_t src_offset = state->src_offset;
4403 	off_t dst_offset = state->dst_offset;
4404 	uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
4405 			       state->size - state->written);
4406 	DATA_BLOB in_input_buffer = data_blob_null;
4407 	DATA_BLOB in_output_buffer = data_blob_null;
4408 
4409 	if (state->size - state->written == 0) {
4410 		tevent_req_done(req);
4411 		return;
4412 	}
4413 
4414 	cc_copy->chunk_count = 0;
4415 	while (req_len) {
4416 		cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
4417 		cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
4418 		cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
4419 				                                   smb2cli_conn_cc_chunk_len(conn));
4420 		if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
4421 			tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4422 			return;
4423 		}
4424 		req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
4425 		if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
4426 		    (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
4427 			tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4428 			return;
4429 		}
4430 		src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4431 		dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4432 		cc_copy->chunk_count++;
4433 	}
4434 
4435 	ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
4436 				       (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
4437 	if (ndr_ret != NDR_ERR_SUCCESS) {
4438 		DEBUG(0, ("failed to marshall copy chunk req\n"));
4439 		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4440 		return;
4441 	}
4442 
4443 	subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
4444 			       state->cli->timeout,
4445 			       state->cli->smb2.session,
4446 			       state->cli->smb2.tcon,
4447 			       state->dst_ph->fid_persistent, /* in_fid_persistent */
4448 			       state->dst_ph->fid_volatile, /* in_fid_volatile */
4449 			       FSCTL_SRV_COPYCHUNK_WRITE,
4450 			       0, /* in_max_input_length */
4451 			       &in_input_buffer,
4452 			       12, /* in_max_output_length */
4453 			       &in_output_buffer,
4454 			       SMB2_IOCTL_FLAG_IS_FSCTL);
4455 	if (tevent_req_nomem(subreq, req)) {
4456 		return;
4457 	}
4458 	tevent_req_set_callback(subreq,
4459 				cli_splice_copychunk_done,
4460 				req);
4461 }
4462 
cli_splice_key_done(struct tevent_req * subreq)4463 static void cli_splice_key_done(struct tevent_req *subreq)
4464 {
4465 	struct tevent_req *req = tevent_req_callback_data(
4466 		subreq, struct tevent_req);
4467 	struct cli_smb2_splice_state *state =
4468 		tevent_req_data(req,
4469 		struct cli_smb2_splice_state);
4470 	enum ndr_err_code ndr_ret;
4471 	NTSTATUS status;
4472 
4473 	DATA_BLOB out_input_buffer = data_blob_null;
4474 	DATA_BLOB out_output_buffer = data_blob_null;
4475 
4476 	status = smb2cli_ioctl_recv(subreq, state,
4477 				    &out_input_buffer,
4478 				    &out_output_buffer);
4479 	TALLOC_FREE(subreq);
4480 	if (tevent_req_nterror(req, status)) {
4481 		return;
4482 	}
4483 
4484 	ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
4485 			state, &state->resume_rsp,
4486 			(ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
4487 	if (ndr_ret != NDR_ERR_SUCCESS) {
4488 		DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4489 		tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4490 		return;
4491 	}
4492 
4493 	memcpy(&state->cc_copy.source_key,
4494 	       &state->resume_rsp.resume_key,
4495 	       sizeof state->resume_rsp.resume_key);
4496 
4497 	cli_splice_copychunk_send(state, req);
4498 }
4499 
cli_smb2_splice_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t src_fnum,uint16_t dst_fnum,off_t size,off_t src_offset,off_t dst_offset,int (* splice_cb)(off_t n,void * priv),void * priv)4500 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
4501 				struct tevent_context *ev,
4502 				struct cli_state *cli,
4503 				uint16_t src_fnum, uint16_t dst_fnum,
4504 				off_t size, off_t src_offset, off_t dst_offset,
4505 				int (*splice_cb)(off_t n, void *priv),
4506 				void *priv)
4507 {
4508 	struct tevent_req *req;
4509 	struct tevent_req *subreq;
4510 	struct cli_smb2_splice_state *state;
4511 	NTSTATUS status;
4512 	DATA_BLOB in_input_buffer = data_blob_null;
4513 	DATA_BLOB in_output_buffer = data_blob_null;
4514 
4515 	req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
4516 	if (req == NULL) {
4517 		return NULL;
4518 	}
4519 	state->cli = cli;
4520 	state->ev = ev;
4521 	state->splice_cb = splice_cb;
4522 	state->priv = priv;
4523 	state->size = size;
4524 	state->written = 0;
4525 	state->src_offset = src_offset;
4526 	state->dst_offset = dst_offset;
4527 	state->cc_copy.chunks = talloc_array(state,
4528 			                     struct srv_copychunk,
4529 					     smb2cli_conn_cc_max_chunks(cli->conn));
4530 	if (state->cc_copy.chunks == NULL) {
4531 		return NULL;
4532 	}
4533 
4534 	status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
4535 	if (tevent_req_nterror(req, status))
4536 		return tevent_req_post(req, ev);
4537 
4538 	status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
4539 	if (tevent_req_nterror(req, status))
4540 		return tevent_req_post(req, ev);
4541 
4542 	subreq = smb2cli_ioctl_send(state, ev, cli->conn,
4543 			       cli->timeout,
4544 			       cli->smb2.session,
4545 			       cli->smb2.tcon,
4546 			       state->src_ph->fid_persistent, /* in_fid_persistent */
4547 			       state->src_ph->fid_volatile, /* in_fid_volatile */
4548 			       FSCTL_SRV_REQUEST_RESUME_KEY,
4549 			       0, /* in_max_input_length */
4550 			       &in_input_buffer,
4551 			       32, /* in_max_output_length */
4552 			       &in_output_buffer,
4553 			       SMB2_IOCTL_FLAG_IS_FSCTL);
4554 	if (tevent_req_nomem(subreq, req)) {
4555 		return NULL;
4556 	}
4557 	tevent_req_set_callback(subreq,
4558 				cli_splice_key_done,
4559 				req);
4560 
4561 	return req;
4562 }
4563 
cli_smb2_splice_recv(struct tevent_req * req,off_t * written)4564 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
4565 {
4566 	struct cli_smb2_splice_state *state = tevent_req_data(
4567 		req, struct cli_smb2_splice_state);
4568 	NTSTATUS status;
4569 
4570 	if (tevent_req_is_nterror(req, &status)) {
4571 		state->cli->raw_status = status;
4572 		tevent_req_received(req);
4573 		return status;
4574 	}
4575 	if (written != NULL) {
4576 		*written = state->written;
4577 	}
4578 	state->cli->raw_status = NT_STATUS_OK;
4579 	tevent_req_received(req);
4580 	return NT_STATUS_OK;
4581 }
4582 
4583 /***************************************************************
4584  SMB2 enum shadow copy data.
4585 ***************************************************************/
4586 
4587 struct cli_smb2_shadow_copy_data_fnum_state {
4588 	struct cli_state *cli;
4589 	uint16_t fnum;
4590 	struct smb2_hnd *ph;
4591 	DATA_BLOB out_input_buffer;
4592 	DATA_BLOB out_output_buffer;
4593 };
4594 
4595 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
4596 
cli_smb2_shadow_copy_data_fnum_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum,bool get_names)4597 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
4598 					TALLOC_CTX *mem_ctx,
4599 					struct tevent_context *ev,
4600 					struct cli_state *cli,
4601 					uint16_t fnum,
4602 					bool get_names)
4603 {
4604 	struct tevent_req *req, *subreq;
4605 	struct cli_smb2_shadow_copy_data_fnum_state *state;
4606 	NTSTATUS status;
4607 
4608 	req = tevent_req_create(mem_ctx, &state,
4609 				struct cli_smb2_shadow_copy_data_fnum_state);
4610 	if (req == NULL) {
4611 		return NULL;
4612 	}
4613 
4614 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4615 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4616 		return tevent_req_post(req, ev);
4617 	}
4618 
4619 	state->cli = cli;
4620 	state->fnum = fnum;
4621 
4622 	status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4623 	if (tevent_req_nterror(req, status)) {
4624 		return tevent_req_post(req, ev);
4625 	}
4626 
4627 	/*
4628 	 * TODO. Under SMB2 we should send a zero max_output_length
4629 	 * ioctl to get the required size, then send another ioctl
4630 	 * to get the data, but the current SMB1 implementation just
4631 	 * does one roundtrip with a 64K buffer size. Do the same
4632 	 * for now. JRA.
4633 	 */
4634 
4635 	subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4636 			state->cli->timeout,
4637 			state->cli->smb2.session,
4638 			state->cli->smb2.tcon,
4639 			state->ph->fid_persistent, /* in_fid_persistent */
4640 			state->ph->fid_volatile, /* in_fid_volatile */
4641 			FSCTL_GET_SHADOW_COPY_DATA,
4642 			0, /* in_max_input_length */
4643 			NULL, /* in_input_buffer */
4644 			get_names ?
4645 				CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4646 			NULL, /* in_output_buffer */
4647 			SMB2_IOCTL_FLAG_IS_FSCTL);
4648 
4649 	if (tevent_req_nomem(subreq, req)) {
4650 		return tevent_req_post(req, ev);
4651 	}
4652 	tevent_req_set_callback(subreq,
4653 				cli_smb2_shadow_copy_data_fnum_done,
4654 				req);
4655 
4656 	return req;
4657 }
4658 
cli_smb2_shadow_copy_data_fnum_done(struct tevent_req * subreq)4659 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4660 {
4661 	struct tevent_req *req = tevent_req_callback_data(
4662 		subreq, struct tevent_req);
4663 	struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4664 		req, struct cli_smb2_shadow_copy_data_fnum_state);
4665 	NTSTATUS status;
4666 
4667 	status = smb2cli_ioctl_recv(subreq, state,
4668 				&state->out_input_buffer,
4669 				&state->out_output_buffer);
4670 	tevent_req_simple_finish_ntstatus(subreq, status);
4671 }
4672 
cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,bool get_names,char *** pnames,int * pnum_names)4673 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4674 				TALLOC_CTX *mem_ctx,
4675 				bool get_names,
4676 				char ***pnames,
4677 				int *pnum_names)
4678 {
4679 	struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4680 		req, struct cli_smb2_shadow_copy_data_fnum_state);
4681 	char **names = NULL;
4682 	uint32_t num_names = 0;
4683 	uint32_t num_names_returned = 0;
4684 	uint32_t dlength = 0;
4685 	uint32_t i;
4686 	uint8_t *endp = NULL;
4687 	NTSTATUS status;
4688 
4689 	if (tevent_req_is_nterror(req, &status)) {
4690 		return status;
4691 	}
4692 
4693 	if (state->out_output_buffer.length < 16) {
4694 		return NT_STATUS_INVALID_NETWORK_RESPONSE;
4695 	}
4696 
4697 	num_names = IVAL(state->out_output_buffer.data, 0);
4698 	num_names_returned = IVAL(state->out_output_buffer.data, 4);
4699 	dlength = IVAL(state->out_output_buffer.data, 8);
4700 
4701 	if (num_names > 0x7FFFFFFF) {
4702 		return NT_STATUS_INVALID_NETWORK_RESPONSE;
4703 	}
4704 
4705 	if (get_names == false) {
4706 		*pnum_names = (int)num_names;
4707 		return NT_STATUS_OK;
4708 	}
4709 	if (num_names != num_names_returned) {
4710 		return NT_STATUS_INVALID_NETWORK_RESPONSE;
4711 	}
4712 	if (dlength + 12 < 12) {
4713 		return NT_STATUS_INVALID_NETWORK_RESPONSE;
4714 	}
4715 	/*
4716 	 * NB. The below is an allowable return if there are
4717 	 * more snapshots than the buffer size we told the
4718 	 * server we can receive. We currently don't support
4719 	 * this.
4720 	 */
4721 	if (dlength + 12 > state->out_output_buffer.length) {
4722 		return NT_STATUS_INVALID_NETWORK_RESPONSE;
4723 	}
4724 	if (state->out_output_buffer.length +
4725 			(2 * sizeof(SHADOW_COPY_LABEL)) <
4726 				state->out_output_buffer.length) {
4727 		return NT_STATUS_INVALID_NETWORK_RESPONSE;
4728 	}
4729 
4730 	names = talloc_array(mem_ctx, char *, num_names_returned);
4731 	if (names == NULL) {
4732 		return NT_STATUS_NO_MEMORY;
4733 	}
4734 
4735 	endp = state->out_output_buffer.data +
4736 			state->out_output_buffer.length;
4737 
4738 	for (i=0; i<num_names_returned; i++) {
4739 		bool ret;
4740 		uint8_t *src;
4741 		size_t converted_size;
4742 
4743 		src = state->out_output_buffer.data + 12 +
4744 			(i * 2 * sizeof(SHADOW_COPY_LABEL));
4745 
4746 		if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4747 			return NT_STATUS_INVALID_NETWORK_RESPONSE;
4748 		}
4749 		ret = convert_string_talloc(
4750 			names, CH_UTF16LE, CH_UNIX,
4751 			src, 2 * sizeof(SHADOW_COPY_LABEL),
4752 			&names[i], &converted_size);
4753 		if (!ret) {
4754 			TALLOC_FREE(names);
4755 			return NT_STATUS_INVALID_NETWORK_RESPONSE;
4756 		}
4757 	}
4758 	*pnum_names = num_names;
4759 	*pnames = names;
4760 	return NT_STATUS_OK;
4761 }
4762 
cli_smb2_shadow_copy_data(TALLOC_CTX * mem_ctx,struct cli_state * cli,uint16_t fnum,bool get_names,char *** pnames,int * pnum_names)4763 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4764 				struct cli_state *cli,
4765 				uint16_t fnum,
4766 				bool get_names,
4767 				char ***pnames,
4768 				int *pnum_names)
4769 {
4770 	TALLOC_CTX *frame = talloc_stackframe();
4771 	struct tevent_context *ev;
4772 	struct tevent_req *req;
4773 	NTSTATUS status = NT_STATUS_NO_MEMORY;
4774 
4775 	if (smbXcli_conn_has_async_calls(cli->conn)) {
4776 		/*
4777 		 * Can't use sync call while an async call is in flight
4778 		 */
4779 		status = NT_STATUS_INVALID_PARAMETER;
4780 		goto fail;
4781 	}
4782 	ev = samba_tevent_context_init(frame);
4783 	if (ev == NULL) {
4784 		goto fail;
4785 	}
4786 	req = cli_smb2_shadow_copy_data_fnum_send(frame,
4787 					ev,
4788 					cli,
4789 					fnum,
4790 					get_names);
4791 	if (req == NULL) {
4792 		goto fail;
4793 	}
4794 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4795 		goto fail;
4796 	}
4797 	status = cli_smb2_shadow_copy_data_fnum_recv(req,
4798 						mem_ctx,
4799 						get_names,
4800 						pnames,
4801 						pnum_names);
4802  fail:
4803 	cli->raw_status = status;
4804 
4805 	TALLOC_FREE(frame);
4806 	return status;
4807 }
4808 
4809 /***************************************************************
4810  Wrapper that allows SMB2 to truncate a file.
4811  Synchronous only.
4812 ***************************************************************/
4813 
cli_smb2_ftruncate(struct cli_state * cli,uint16_t fnum,uint64_t newsize)4814 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4815 			uint16_t fnum,
4816 			uint64_t newsize)
4817 {
4818 	NTSTATUS status;
4819 	uint8_t buf[8] = {0};
4820 	DATA_BLOB inbuf = { .data = buf, .length = sizeof(buf) };
4821 	TALLOC_CTX *frame = talloc_stackframe();
4822 
4823 	if (smbXcli_conn_has_async_calls(cli->conn)) {
4824 		/*
4825 		 * Can't use sync call while an async call is in flight
4826 		 */
4827 		status = NT_STATUS_INVALID_PARAMETER;
4828 		goto fail;
4829 	}
4830 
4831 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4832 		status = NT_STATUS_INVALID_PARAMETER;
4833 		goto fail;
4834 	}
4835 
4836 	SBVAL(buf, 0, newsize);
4837 
4838 	/* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4839 	   level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4840 
4841 	status = cli_smb2_set_info_fnum(
4842 		cli,
4843 		fnum,
4844 		1, /* in_info_type */
4845 		SMB_FILE_END_OF_FILE_INFORMATION-1000, /* in_file_info_class */
4846 		&inbuf, /* in_input_buffer */
4847 		0);
4848 
4849   fail:
4850 
4851 	cli->raw_status = status;
4852 
4853 	TALLOC_FREE(frame);
4854 	return status;
4855 }
4856 
4857 struct cli_smb2_notify_state {
4858 	struct tevent_req *subreq;
4859 	struct notify_change *changes;
4860 	size_t num_changes;
4861 };
4862 
4863 static void cli_smb2_notify_done(struct tevent_req *subreq);
4864 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4865 
cli_smb2_notify_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum,uint32_t buffer_size,uint32_t completion_filter,bool recursive)4866 struct tevent_req *cli_smb2_notify_send(
4867 	TALLOC_CTX *mem_ctx,
4868 	struct tevent_context *ev,
4869 	struct cli_state *cli,
4870 	uint16_t fnum,
4871 	uint32_t buffer_size,
4872 	uint32_t completion_filter,
4873 	bool recursive)
4874 {
4875 	struct tevent_req *req = NULL;
4876 	struct cli_smb2_notify_state *state = NULL;
4877 	struct smb2_hnd *ph = NULL;
4878 	NTSTATUS status;
4879 
4880 	req = tevent_req_create(mem_ctx, &state,
4881 				struct cli_smb2_notify_state);
4882 	if (req == NULL) {
4883 		return NULL;
4884 	}
4885 
4886 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4887 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4888 		return tevent_req_post(req, ev);
4889 	}
4890 
4891 	status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4892 	if (tevent_req_nterror(req, status)) {
4893 		return tevent_req_post(req, ev);
4894 	}
4895 
4896 	state->subreq = smb2cli_notify_send(
4897 		state,
4898 		ev,
4899 		cli->conn,
4900 		cli->timeout,
4901 		cli->smb2.session,
4902 		cli->smb2.tcon,
4903 		buffer_size,
4904 		ph->fid_persistent,
4905 		ph->fid_volatile,
4906 		completion_filter,
4907 		recursive);
4908 	if (tevent_req_nomem(state->subreq, req)) {
4909 		return tevent_req_post(req, ev);
4910 	}
4911 	tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4912 	tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4913 	return req;
4914 }
4915 
cli_smb2_notify_cancel(struct tevent_req * req)4916 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4917 {
4918 	struct cli_smb2_notify_state *state = tevent_req_data(
4919 		req, struct cli_smb2_notify_state);
4920 	bool ok;
4921 
4922 	ok = tevent_req_cancel(state->subreq);
4923 	return ok;
4924 }
4925 
cli_smb2_notify_done(struct tevent_req * subreq)4926 static void cli_smb2_notify_done(struct tevent_req *subreq)
4927 {
4928 	struct tevent_req *req = tevent_req_callback_data(
4929 		subreq, struct tevent_req);
4930 	struct cli_smb2_notify_state *state = tevent_req_data(
4931 		req, struct cli_smb2_notify_state);
4932 	uint8_t *base;
4933 	uint32_t len;
4934 	uint32_t ofs;
4935 	NTSTATUS status;
4936 
4937 	status = smb2cli_notify_recv(subreq, state, &base, &len);
4938 	TALLOC_FREE(subreq);
4939 
4940 	if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4941 		tevent_req_done(req);
4942 		return;
4943 	}
4944 	if (tevent_req_nterror(req, status)) {
4945 		return;
4946 	}
4947 
4948 	ofs = 0;
4949 
4950 	while (len - ofs >= 12) {
4951 		struct notify_change *tmp;
4952 		struct notify_change *c;
4953 		uint32_t next_ofs = IVAL(base, ofs);
4954 		uint32_t file_name_length = IVAL(base, ofs+8);
4955 		size_t namelen;
4956 		bool ok;
4957 
4958 		tmp = talloc_realloc(
4959 			state,
4960 			state->changes,
4961 			struct notify_change,
4962 			state->num_changes + 1);
4963 		if (tevent_req_nomem(tmp, req)) {
4964 			return;
4965 		}
4966 		state->changes = tmp;
4967 		c = &state->changes[state->num_changes];
4968 		state->num_changes += 1;
4969 
4970 		if (smb_buffer_oob(len, ofs, next_ofs) ||
4971 		    smb_buffer_oob(len, ofs+12, file_name_length)) {
4972 			tevent_req_nterror(
4973 				req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4974 			return;
4975 		}
4976 
4977 		c->action = IVAL(base, ofs+4);
4978 
4979 		ok = convert_string_talloc(
4980 			state->changes,
4981 			CH_UTF16LE,
4982 			CH_UNIX,
4983 			base + ofs + 12,
4984 			file_name_length,
4985 			&c->name,
4986 			&namelen);
4987 		if (!ok) {
4988 			tevent_req_nterror(
4989 				req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4990 			return;
4991 		}
4992 
4993 		if (next_ofs == 0) {
4994 			break;
4995 		}
4996 		ofs += next_ofs;
4997 	}
4998 
4999 	tevent_req_done(req);
5000 }
5001 
cli_smb2_notify_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,struct notify_change ** pchanges,uint32_t * pnum_changes)5002 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
5003 			      TALLOC_CTX *mem_ctx,
5004 			      struct notify_change **pchanges,
5005 			      uint32_t *pnum_changes)
5006 {
5007 	struct cli_smb2_notify_state *state = tevent_req_data(
5008 		req, struct cli_smb2_notify_state);
5009 	NTSTATUS status;
5010 
5011 	if (tevent_req_is_nterror(req, &status)) {
5012 		return status;
5013 	}
5014 	*pchanges = talloc_move(mem_ctx, &state->changes);
5015 	*pnum_changes = state->num_changes;
5016 	return NT_STATUS_OK;
5017 }
5018 
cli_smb2_notify(struct cli_state * cli,uint16_t fnum,uint32_t buffer_size,uint32_t completion_filter,bool recursive,TALLOC_CTX * mem_ctx,struct notify_change ** pchanges,uint32_t * pnum_changes)5019 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
5020 			 uint32_t buffer_size, uint32_t completion_filter,
5021 			 bool recursive, TALLOC_CTX *mem_ctx,
5022 			 struct notify_change **pchanges,
5023 			 uint32_t *pnum_changes)
5024 {
5025 	TALLOC_CTX *frame = talloc_stackframe();
5026 	struct tevent_context *ev;
5027 	struct tevent_req *req;
5028 	NTSTATUS status = NT_STATUS_NO_MEMORY;
5029 
5030 	if (smbXcli_conn_has_async_calls(cli->conn)) {
5031 		/*
5032 		 * Can't use sync call while an async call is in flight
5033 		 */
5034 		status = NT_STATUS_INVALID_PARAMETER;
5035 		goto fail;
5036 	}
5037 	ev = samba_tevent_context_init(frame);
5038 	if (ev == NULL) {
5039 		goto fail;
5040 	}
5041 	req = cli_smb2_notify_send(
5042 		frame,
5043 		ev,
5044 		cli,
5045 		fnum,
5046 		buffer_size,
5047 		completion_filter,
5048 		recursive);
5049 	if (req == NULL) {
5050 		goto fail;
5051 	}
5052 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5053 		goto fail;
5054 	}
5055 	status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
5056 fail:
5057 	TALLOC_FREE(frame);
5058 	return status;
5059 }
5060 
5061 struct cli_smb2_set_reparse_point_fnum_state {
5062 	struct cli_state *cli;
5063 	uint16_t fnum;
5064 	struct smb2_hnd *ph;
5065 	DATA_BLOB input_buffer;
5066 };
5067 
5068 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
5069 
cli_smb2_set_reparse_point_fnum_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum,DATA_BLOB in_buf)5070 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
5071 				TALLOC_CTX *mem_ctx,
5072 				struct tevent_context *ev,
5073 				struct cli_state *cli,
5074 				uint16_t fnum,
5075 				DATA_BLOB in_buf)
5076 {
5077 	struct tevent_req *req, *subreq;
5078 	struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
5079 	NTSTATUS status;
5080 
5081 	req = tevent_req_create(mem_ctx, &state,
5082 				struct cli_smb2_set_reparse_point_fnum_state);
5083 	if (req == NULL) {
5084 		return NULL;
5085 	}
5086 
5087 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5088 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5089 		return tevent_req_post(req, ev);
5090 	}
5091 
5092 	state->cli = cli;
5093 	state->fnum = fnum;
5094 
5095 	status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5096 	if (tevent_req_nterror(req, status)) {
5097 		return tevent_req_post(req, ev);
5098 	}
5099 
5100 	state->input_buffer = data_blob_talloc(state,
5101 						in_buf.data,
5102 						in_buf.length);
5103 	if (state->input_buffer.data == NULL) {
5104 		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
5105 		return tevent_req_post(req, ev);
5106 	}
5107 
5108 	subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5109 			state->cli->timeout,
5110 			state->cli->smb2.session,
5111 			state->cli->smb2.tcon,
5112 			state->ph->fid_persistent, /* in_fid_persistent */
5113 			state->ph->fid_volatile, /* in_fid_volatile */
5114 			FSCTL_SET_REPARSE_POINT,
5115 			0, /* in_max_input_length */
5116 			&state->input_buffer ,
5117 			0,
5118 			NULL,
5119 			SMB2_IOCTL_FLAG_IS_FSCTL);
5120 
5121 	if (tevent_req_nomem(subreq, req)) {
5122 		return tevent_req_post(req, ev);
5123 	}
5124 	tevent_req_set_callback(subreq,
5125 				cli_smb2_set_reparse_point_fnum_done,
5126 				req);
5127 
5128 	return req;
5129 }
5130 
cli_smb2_set_reparse_point_fnum_done(struct tevent_req * subreq)5131 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
5132 {
5133 	struct tevent_req *req = tevent_req_callback_data(
5134 		subreq, struct tevent_req);
5135 	struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
5136 		req, struct cli_smb2_set_reparse_point_fnum_state);
5137 	NTSTATUS status;
5138 
5139 	status = smb2cli_ioctl_recv(subreq, state,
5140 				NULL,
5141 				NULL);
5142 	TALLOC_FREE(subreq);
5143 	if (tevent_req_nterror(req, status)) {
5144 		return;
5145 	}
5146 	tevent_req_done(req);
5147 }
5148 
cli_smb2_set_reparse_point_fnum_recv(struct tevent_req * req)5149 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
5150 {
5151         return tevent_req_simple_recv_ntstatus(req);
5152 }
5153 
5154 struct cli_smb2_get_reparse_point_fnum_state {
5155 	struct cli_state *cli;
5156 	uint16_t fnum;
5157 	struct smb2_hnd *ph;
5158 	DATA_BLOB output_buffer;
5159 };
5160 
5161 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
5162 
cli_smb2_get_reparse_point_fnum_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t fnum)5163 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
5164 				TALLOC_CTX *mem_ctx,
5165 				struct tevent_context *ev,
5166 				struct cli_state *cli,
5167 				uint16_t fnum)
5168 {
5169 	struct tevent_req *req, *subreq;
5170 	struct cli_smb2_get_reparse_point_fnum_state *state = NULL;
5171 	NTSTATUS status;
5172 
5173 	req = tevent_req_create(mem_ctx, &state,
5174 				struct cli_smb2_get_reparse_point_fnum_state);
5175 	if (req == NULL) {
5176 		return NULL;
5177 	}
5178 
5179 	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5180 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5181 		return tevent_req_post(req, ev);
5182 	}
5183 
5184 	state->cli = cli;
5185 	state->fnum = fnum;
5186 
5187 	status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5188 	if (tevent_req_nterror(req, status)) {
5189 		return tevent_req_post(req, ev);
5190 	}
5191 
5192 	subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5193 			state->cli->timeout,
5194 			state->cli->smb2.session,
5195 			state->cli->smb2.tcon,
5196 			state->ph->fid_persistent, /* in_fid_persistent */
5197 			state->ph->fid_volatile, /* in_fid_volatile */
5198 			FSCTL_GET_REPARSE_POINT,
5199 			0, /* in_max_input_length */
5200 			NULL,
5201 			64*1024,
5202 			NULL,
5203 			SMB2_IOCTL_FLAG_IS_FSCTL);
5204 
5205 	if (tevent_req_nomem(subreq, req)) {
5206 		return tevent_req_post(req, ev);
5207 	}
5208 	tevent_req_set_callback(subreq,
5209 				cli_smb2_get_reparse_point_fnum_done,
5210 				req);
5211 
5212 	return req;
5213 }
5214 
cli_smb2_get_reparse_point_fnum_done(struct tevent_req * subreq)5215 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
5216 {
5217 	struct tevent_req *req = tevent_req_callback_data(
5218 		subreq, struct tevent_req);
5219 	struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5220 		req, struct cli_smb2_get_reparse_point_fnum_state);
5221 	struct cli_state *cli = state->cli;
5222 	NTSTATUS status;
5223 
5224 	status = smb2cli_ioctl_recv(subreq, state,
5225 				NULL,
5226 				&state->output_buffer);
5227 	TALLOC_FREE(subreq);
5228 	if (tevent_req_nterror(req, status)) {
5229 		cli->raw_status = status;
5230 		return;
5231 	}
5232 	tevent_req_done(req);
5233 }
5234 
cli_smb2_get_reparse_point_fnum_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,DATA_BLOB * output)5235 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
5236 				TALLOC_CTX *mem_ctx,
5237 				DATA_BLOB *output)
5238 {
5239 	struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5240 		req, struct cli_smb2_get_reparse_point_fnum_state);
5241 
5242 	if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
5243 		NTSTATUS status = state->cli->raw_status;
5244 		tevent_req_received(req);
5245 		return status;
5246 	}
5247 	*output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
5248 	if (output->data == NULL) {
5249 		tevent_req_received(req);
5250 		return NT_STATUS_NO_MEMORY;
5251 	}
5252 	tevent_req_received(req);
5253 	return NT_STATUS_OK;
5254 }
5255