Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Wrap disk only vfs functions to sidestep dodgy compilers.
4 : Copyright (C) Tim Potter 1998
5 : Copyright (C) Jeremy Allison 2007
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "system/time.h"
23 : #include "system/filesys.h"
24 : #include "smbd/smbd.h"
25 : #include "smbd/globals.h"
26 : #include "ntioctl.h"
27 : #include "smbprofile.h"
28 : #include "../libcli/security/security.h"
29 : #include "passdb/lookup_sid.h"
30 : #include "source3/include/msdfs.h"
31 : #include "librpc/gen_ndr/ndr_dfsblobs.h"
32 : #include "lib/util/tevent_unix.h"
33 : #include "lib/util/tevent_ntstatus.h"
34 : #include "lib/util/sys_rw.h"
35 : #include "lib/pthreadpool/pthreadpool_tevent.h"
36 : #include "librpc/gen_ndr/ndr_ioctl.h"
37 : #include "offload_token.h"
38 : #include "util_reparse.h"
39 : #include "lib/util/string_wrappers.h"
40 :
41 : #undef DBGC_CLASS
42 : #define DBGC_CLASS DBGC_VFS
43 :
44 : /* Check for NULL pointer parameters in vfswrap_* functions */
45 :
46 : /* We don't want to have NULL function pointers lying around. Someone
47 : is sure to try and execute them. These stubs are used to prevent
48 : this possibility. */
49 :
50 58622 : static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user)
51 : {
52 894 : bool bval;
53 :
54 58622 : handle->conn->have_proc_fds = sys_have_proc_fds();
55 : #ifdef DISABLE_PROC_FDS
56 21173 : handle->conn->have_proc_fds = false;
57 : #endif
58 :
59 : /*
60 : * assume the kernel will support openat2(),
61 : * it will be reset on the first ENOSYS.
62 : *
63 : * Note that libreplace will always provide openat2(),
64 : * but return -1/errno = ENOSYS...
65 : *
66 : * The option is only there to test the fallback code.
67 : */
68 58622 : bval = lp_parm_bool(SNUM(handle->conn),
69 : "vfs_default",
70 : "VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS",
71 : true);
72 58622 : if (bval) {
73 46485 : handle->conn->open_how_resolve |=
74 : VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
75 : }
76 : #ifdef DISABLE_VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
77 21173 : handle->conn->open_how_resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
78 : #endif
79 :
80 58622 : return 0; /* Return >= 0 for success */
81 : }
82 :
83 58584 : static void vfswrap_disconnect(vfs_handle_struct *handle)
84 : {
85 58584 : }
86 :
87 : /* Disk operations */
88 :
89 1587 : static uint64_t vfswrap_disk_free(vfs_handle_struct *handle,
90 : const struct smb_filename *smb_fname,
91 : uint64_t *bsize,
92 : uint64_t *dfree,
93 : uint64_t *dsize)
94 : {
95 1587 : if (sys_fsusage(smb_fname->base_name, dfree, dsize) != 0) {
96 0 : return (uint64_t)-1;
97 : }
98 :
99 1587 : *bsize = 512;
100 1587 : return *dfree / 2;
101 : }
102 :
103 3254 : static int vfswrap_get_quota(struct vfs_handle_struct *handle,
104 : const struct smb_filename *smb_fname,
105 : enum SMB_QUOTA_TYPE qtype,
106 : unid_t id,
107 : SMB_DISK_QUOTA *qt)
108 : {
109 : #ifdef HAVE_SYS_QUOTAS
110 0 : int result;
111 :
112 3254 : START_PROFILE(syscall_get_quota);
113 3254 : result = sys_get_quota(smb_fname->base_name, qtype, id, qt);
114 3254 : END_PROFILE(syscall_get_quota);
115 3254 : return result;
116 : #else
117 : errno = ENOSYS;
118 : return -1;
119 : #endif
120 : }
121 :
122 4 : static int vfswrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
123 : {
124 : #ifdef HAVE_SYS_QUOTAS
125 0 : int result;
126 :
127 4 : START_PROFILE(syscall_set_quota);
128 4 : result = sys_set_quota(handle->conn->connectpath, qtype, id, qt);
129 4 : END_PROFILE(syscall_set_quota);
130 4 : return result;
131 : #else
132 : errno = ENOSYS;
133 : return -1;
134 : #endif
135 : }
136 :
137 276 : static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle,
138 : struct files_struct *fsp,
139 : struct shadow_copy_data *shadow_copy_data,
140 : bool labels)
141 : {
142 276 : errno = ENOSYS;
143 276 : return -1; /* Not implemented. */
144 : }
145 :
146 31222 : static int vfswrap_statvfs(struct vfs_handle_struct *handle,
147 : const struct smb_filename *smb_fname,
148 : struct vfs_statvfs_struct *statbuf)
149 : {
150 31222 : return sys_statvfs(smb_fname->base_name, statbuf);
151 : }
152 :
153 31222 : static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
154 : enum timestamp_set_resolution *p_ts_res)
155 : {
156 484 : const struct loadparm_substitution *lp_sub =
157 31222 : loadparm_s3_global_substitution();
158 31222 : connection_struct *conn = handle->conn;
159 31222 : uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
160 31222 : struct smb_filename *smb_fname_cpath = NULL;
161 484 : struct vfs_statvfs_struct statbuf;
162 484 : int ret;
163 :
164 31222 : smb_fname_cpath = synthetic_smb_fname(talloc_tos(),
165 31222 : conn->connectpath,
166 : NULL,
167 : NULL,
168 : 0,
169 : 0);
170 31222 : if (smb_fname_cpath == NULL) {
171 0 : return caps;
172 : }
173 :
174 31222 : ZERO_STRUCT(statbuf);
175 31222 : ret = SMB_VFS_STATVFS(conn, smb_fname_cpath, &statbuf);
176 31222 : if (ret == 0) {
177 31222 : caps = statbuf.FsCapabilities;
178 : }
179 :
180 31222 : *p_ts_res = TIMESTAMP_SET_SECONDS;
181 :
182 : /* Work out what timestamp resolution we can
183 : * use when setting a timestamp. */
184 :
185 31222 : ret = SMB_VFS_STAT(conn, smb_fname_cpath);
186 31222 : if (ret == -1) {
187 0 : TALLOC_FREE(smb_fname_cpath);
188 0 : return caps;
189 : }
190 :
191 31222 : if (smb_fname_cpath->st.st_ex_mtime.tv_nsec ||
192 2 : smb_fname_cpath->st.st_ex_atime.tv_nsec ||
193 0 : smb_fname_cpath->st.st_ex_ctime.tv_nsec) {
194 : /* If any of the normal UNIX directory timestamps
195 : * have a non-zero tv_nsec component assume
196 : * we might be able to set sub-second timestamps.
197 : * See what filetime set primitives we have.
198 : */
199 : #if defined(HAVE_UTIMENSAT)
200 31222 : *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
201 : #elif defined(HAVE_UTIMES)
202 : /* utimes allows msec timestamps to be set. */
203 : *p_ts_res = TIMESTAMP_SET_MSEC;
204 : #elif defined(HAVE_UTIME)
205 : /* utime only allows sec timestamps to be set. */
206 : *p_ts_res = TIMESTAMP_SET_SECONDS;
207 : #endif
208 :
209 31222 : DBG_DEBUG("vfswrap_fs_capabilities: timestamp "
210 : "resolution of %s "
211 : "available on share %s, directory %s\n",
212 : *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
213 : lp_servicename(talloc_tos(), lp_sub, conn->params->service),
214 : conn->connectpath );
215 : }
216 31222 : TALLOC_FREE(smb_fname_cpath);
217 31222 : return caps;
218 : }
219 :
220 15645 : static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
221 : struct dfs_GetDFSReferral *r)
222 : {
223 15645 : struct junction_map *junction = NULL;
224 15645 : size_t consumedcnt = 0;
225 15645 : bool self_referral = false;
226 15645 : char *pathnamep = NULL;
227 15645 : char *local_dfs_path = NULL;
228 0 : NTSTATUS status;
229 0 : size_t i;
230 15645 : uint16_t max_referral_level = r->in.req.max_referral_level;
231 :
232 15645 : if (DEBUGLVL(DBGLVL_DEBUG)) {
233 0 : NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
234 : }
235 :
236 : /* get the junction entry */
237 15645 : if (r->in.req.servername == NULL) {
238 0 : return NT_STATUS_NOT_FOUND;
239 : }
240 :
241 : /*
242 : * Trim pathname sent by client so it begins with only one backslash.
243 : * Two backslashes confuse some dfs clients
244 : */
245 :
246 15645 : local_dfs_path = talloc_strdup(r, r->in.req.servername);
247 15645 : if (local_dfs_path == NULL) {
248 0 : return NT_STATUS_NO_MEMORY;
249 : }
250 15645 : pathnamep = local_dfs_path;
251 15645 : while (IS_DIRECTORY_SEP(pathnamep[0]) &&
252 15643 : IS_DIRECTORY_SEP(pathnamep[1])) {
253 0 : pathnamep++;
254 : }
255 :
256 15645 : junction = talloc_zero(r, struct junction_map);
257 15645 : if (junction == NULL) {
258 0 : return NT_STATUS_NO_MEMORY;
259 : }
260 :
261 : /* The following call can change cwd. */
262 15645 : status = get_referred_path(r,
263 15645 : handle->conn->session_info,
264 : pathnamep,
265 15645 : handle->conn->sconn->remote_address,
266 15645 : handle->conn->sconn->local_address,
267 : junction, &consumedcnt, &self_referral);
268 15645 : if (!NT_STATUS_IS_OK(status)) {
269 9441 : struct smb_filename connectpath_fname = {
270 9441 : .base_name = handle->conn->connectpath
271 : };
272 9441 : vfs_ChDir(handle->conn, &connectpath_fname);
273 9441 : return status;
274 : }
275 : {
276 6204 : struct smb_filename connectpath_fname = {
277 6204 : .base_name = handle->conn->connectpath
278 : };
279 6204 : vfs_ChDir(handle->conn, &connectpath_fname);
280 : }
281 :
282 6204 : if (!self_referral) {
283 4624 : pathnamep[consumedcnt] = '\0';
284 :
285 4624 : if (DEBUGLVL(DBGLVL_INFO)) {
286 0 : dbgtext("Path %s to alternate path(s):",
287 : pathnamep);
288 0 : for (i=0; i < junction->referral_count; i++) {
289 0 : dbgtext(" %s",
290 0 : junction->referral_list[i].alternate_path);
291 : }
292 0 : dbgtext(".\n");
293 : }
294 : }
295 :
296 6204 : if (r->in.req.max_referral_level <= 2) {
297 0 : max_referral_level = 2;
298 : }
299 6204 : if (r->in.req.max_referral_level >= 3) {
300 6204 : max_referral_level = 3;
301 : }
302 :
303 6204 : r->out.resp = talloc_zero(r, struct dfs_referral_resp);
304 6204 : if (r->out.resp == NULL) {
305 0 : return NT_STATUS_NO_MEMORY;
306 : }
307 :
308 6204 : r->out.resp->path_consumed = strlen_m(pathnamep) * 2;
309 6204 : r->out.resp->nb_referrals = junction->referral_count;
310 :
311 6204 : r->out.resp->header_flags = DFS_HEADER_FLAG_STORAGE_SVR;
312 6204 : if (self_referral) {
313 1580 : r->out.resp->header_flags |= DFS_HEADER_FLAG_REFERAL_SVR;
314 : }
315 :
316 6204 : r->out.resp->referral_entries = talloc_zero_array(r,
317 : struct dfs_referral_type,
318 : r->out.resp->nb_referrals);
319 6204 : if (r->out.resp->referral_entries == NULL) {
320 0 : return NT_STATUS_NO_MEMORY;
321 : }
322 :
323 6204 : switch (max_referral_level) {
324 0 : case 2:
325 0 : for(i=0; i < junction->referral_count; i++) {
326 0 : struct referral *ref = &junction->referral_list[i];
327 0 : TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
328 0 : struct dfs_referral_type *t =
329 0 : &r->out.resp->referral_entries[i];
330 0 : struct dfs_referral_v2 *v2 = &t->referral.v2;
331 :
332 0 : t->version = 2;
333 0 : v2->size = VERSION2_REFERRAL_SIZE;
334 0 : if (self_referral) {
335 0 : v2->server_type = DFS_SERVER_ROOT;
336 : } else {
337 0 : v2->server_type = DFS_SERVER_NON_ROOT;
338 : }
339 0 : v2->entry_flags = 0;
340 0 : v2->proximity = ref->proximity;
341 0 : v2->ttl = ref->ttl;
342 0 : v2->DFS_path = talloc_strdup(mem_ctx, pathnamep);
343 0 : if (v2->DFS_path == NULL) {
344 0 : return NT_STATUS_NO_MEMORY;
345 : }
346 0 : v2->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
347 0 : if (v2->DFS_alt_path == NULL) {
348 0 : return NT_STATUS_NO_MEMORY;
349 : }
350 0 : v2->netw_address = talloc_strdup(mem_ctx,
351 0 : ref->alternate_path);
352 0 : if (v2->netw_address == NULL) {
353 0 : return NT_STATUS_NO_MEMORY;
354 : }
355 : }
356 :
357 0 : break;
358 6204 : case 3:
359 16536 : for(i=0; i < junction->referral_count; i++) {
360 10332 : struct referral *ref = &junction->referral_list[i];
361 10332 : TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
362 10332 : struct dfs_referral_type *t =
363 10332 : &r->out.resp->referral_entries[i];
364 10332 : struct dfs_referral_v3 *v3 = &t->referral.v3;
365 10332 : struct dfs_normal_referral *r1 = &v3->referrals.r1;
366 :
367 10332 : t->version = 3;
368 10332 : v3->size = VERSION3_REFERRAL_SIZE;
369 10332 : if (self_referral) {
370 1580 : v3->server_type = DFS_SERVER_ROOT;
371 : } else {
372 8752 : v3->server_type = DFS_SERVER_NON_ROOT;
373 : }
374 10332 : v3->entry_flags = 0;
375 10332 : v3->ttl = ref->ttl;
376 10332 : r1->DFS_path = talloc_strdup(mem_ctx, pathnamep);
377 10332 : if (r1->DFS_path == NULL) {
378 0 : return NT_STATUS_NO_MEMORY;
379 : }
380 10332 : r1->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
381 10332 : if (r1->DFS_alt_path == NULL) {
382 0 : return NT_STATUS_NO_MEMORY;
383 : }
384 20664 : r1->netw_address = talloc_strdup(mem_ctx,
385 10332 : ref->alternate_path);
386 10332 : if (r1->netw_address == NULL) {
387 0 : return NT_STATUS_NO_MEMORY;
388 : }
389 : }
390 6204 : break;
391 0 : default:
392 0 : DBG_ERR("Invalid dfs referral version: %d\n",
393 : max_referral_level);
394 0 : return NT_STATUS_INVALID_LEVEL;
395 : }
396 :
397 6204 : if (DEBUGLVL(DBGLVL_DEBUG)) {
398 0 : NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
399 : }
400 :
401 6204 : return NT_STATUS_OK;
402 : }
403 :
404 0 : static NTSTATUS vfswrap_create_dfs_pathat(struct vfs_handle_struct *handle,
405 : struct files_struct *dirfsp,
406 : const struct smb_filename *smb_fname,
407 : const struct referral *reflist,
408 : size_t referral_count)
409 : {
410 0 : TALLOC_CTX *frame = talloc_stackframe();
411 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
412 0 : int ret;
413 0 : char *msdfs_link = NULL;
414 :
415 : /* Form the msdfs_link contents */
416 0 : msdfs_link = msdfs_link_string(frame,
417 : reflist,
418 : referral_count);
419 0 : if (msdfs_link == NULL) {
420 0 : goto out;
421 : }
422 :
423 0 : ret = symlinkat(msdfs_link,
424 : fsp_get_pathref_fd(dirfsp),
425 0 : smb_fname->base_name);
426 0 : if (ret == 0) {
427 0 : status = NT_STATUS_OK;
428 : } else {
429 0 : status = map_nt_error_from_unix(errno);
430 : }
431 :
432 0 : out:
433 :
434 0 : TALLOC_FREE(frame);
435 0 : return status;
436 : }
437 :
438 : /*
439 : * Read and return the contents of a DFS redirect given a
440 : * pathname. A caller can pass in NULL for ppreflist and
441 : * preferral_count but still determine if this was a
442 : * DFS redirect point by getting NT_STATUS_OK back
443 : * without incurring the overhead of reading and parsing
444 : * the referral contents.
445 : */
446 :
447 5008 : static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
448 : TALLOC_CTX *mem_ctx,
449 : struct files_struct *dirfsp,
450 : struct smb_filename *smb_fname,
451 : struct referral **ppreflist,
452 : size_t *preferral_count)
453 : {
454 5008 : NTSTATUS status = NT_STATUS_NO_MEMORY;
455 0 : size_t bufsize;
456 5008 : char *link_target = NULL;
457 0 : int referral_len;
458 0 : bool ok;
459 : #if defined(HAVE_BROKEN_READLINK)
460 : char link_target_buf[PATH_MAX];
461 : #else
462 0 : char link_target_buf[7];
463 : #endif
464 0 : int ret;
465 :
466 5008 : if (is_named_stream(smb_fname)) {
467 0 : status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
468 0 : goto err;
469 : }
470 :
471 5008 : if (ppreflist == NULL && preferral_count == NULL) {
472 : /*
473 : * We're only checking if this is a DFS
474 : * redirect. We don't need to return data.
475 : */
476 382 : bufsize = sizeof(link_target_buf);
477 382 : link_target = link_target_buf;
478 : } else {
479 4626 : bufsize = PATH_MAX;
480 4626 : link_target = talloc_array(mem_ctx, char, bufsize);
481 4626 : if (!link_target) {
482 0 : goto err;
483 : }
484 : }
485 :
486 5008 : referral_len = readlinkat(fsp_get_pathref_fd(dirfsp),
487 5008 : smb_fname->base_name,
488 : link_target,
489 : bufsize - 1);
490 5008 : if (referral_len == -1) {
491 0 : if (errno == EINVAL) {
492 : /*
493 : * If the path isn't a link, readlinkat
494 : * returns EINVAL. Allow the caller to
495 : * detect this.
496 : */
497 0 : DBG_INFO("%s is not a link.\n", smb_fname->base_name);
498 0 : status = NT_STATUS_OBJECT_TYPE_MISMATCH;
499 : } else {
500 0 : status = map_nt_error_from_unix(errno);
501 0 : if (errno == ENOENT) {
502 0 : DBG_NOTICE("Error reading "
503 : "msdfs link %s: %s\n",
504 : smb_fname->base_name,
505 : strerror(errno));
506 : } else {
507 0 : DBG_ERR("Error reading "
508 : "msdfs link %s: %s\n",
509 : smb_fname->base_name,
510 : strerror(errno));
511 : }
512 : }
513 0 : goto err;
514 : }
515 5008 : link_target[referral_len] = '\0';
516 :
517 5008 : DBG_INFO("%s -> %s\n",
518 : smb_fname->base_name,
519 : link_target);
520 :
521 5008 : if (!strnequal(link_target, "msdfs:", 6)) {
522 4 : status = NT_STATUS_OBJECT_TYPE_MISMATCH;
523 4 : goto err;
524 : }
525 :
526 5004 : ret = sys_fstatat(fsp_get_pathref_fd(dirfsp),
527 5004 : smb_fname->base_name,
528 : &smb_fname->st,
529 : AT_SYMLINK_NOFOLLOW,
530 5004 : lp_fake_directory_create_times(SNUM(handle->conn)));
531 5004 : if (ret < 0) {
532 0 : status = map_nt_error_from_unix(errno);
533 0 : goto err;
534 : }
535 :
536 5004 : if (ppreflist == NULL && preferral_count == NULL) {
537 : /* Early return for checking if this is a DFS link. */
538 378 : return NT_STATUS_OK;
539 : }
540 :
541 4626 : ok = parse_msdfs_symlink(mem_ctx,
542 4626 : lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
543 : link_target,
544 : ppreflist,
545 : preferral_count);
546 :
547 4626 : if (ok) {
548 4626 : status = NT_STATUS_OK;
549 : } else {
550 0 : status = NT_STATUS_NO_MEMORY;
551 : }
552 :
553 4630 : err:
554 :
555 4630 : if (link_target != link_target_buf) {
556 4626 : TALLOC_FREE(link_target);
557 : }
558 4630 : return status;
559 : }
560 :
561 0 : static NTSTATUS vfswrap_snap_check_path(struct vfs_handle_struct *handle,
562 : TALLOC_CTX *mem_ctx,
563 : const char *service_path,
564 : char **base_volume)
565 : {
566 0 : return NT_STATUS_NOT_SUPPORTED;
567 : }
568 :
569 0 : static NTSTATUS vfswrap_snap_create(struct vfs_handle_struct *handle,
570 : TALLOC_CTX *mem_ctx,
571 : const char *base_volume,
572 : time_t *tstamp,
573 : bool rw,
574 : char **base_path,
575 : char **snap_path)
576 : {
577 0 : return NT_STATUS_NOT_SUPPORTED;
578 : }
579 :
580 0 : static NTSTATUS vfswrap_snap_delete(struct vfs_handle_struct *handle,
581 : TALLOC_CTX *mem_ctx,
582 : char *base_path,
583 : char *snap_path)
584 : {
585 0 : return NT_STATUS_NOT_SUPPORTED;
586 : }
587 :
588 : /* Directory operations */
589 :
590 308702 : static DIR *vfswrap_fdopendir(vfs_handle_struct *handle,
591 : files_struct *fsp,
592 : const char *mask,
593 : uint32_t attr)
594 : {
595 1133 : DIR *result;
596 :
597 308702 : START_PROFILE(syscall_fdopendir);
598 308702 : result = sys_fdopendir(fsp_get_io_fd(fsp));
599 308702 : END_PROFILE(syscall_fdopendir);
600 308702 : return result;
601 : }
602 :
603 161021656 : static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
604 : struct files_struct *dirfsp,
605 : DIR *dirp)
606 : {
607 7199 : struct dirent *result;
608 :
609 161021656 : START_PROFILE(syscall_readdir);
610 :
611 161021656 : result = readdir(dirp);
612 161021656 : END_PROFILE(syscall_readdir);
613 :
614 161021656 : return result;
615 : }
616 :
617 895820 : static NTSTATUS vfswrap_freaddir_attr(struct vfs_handle_struct *handle,
618 : struct files_struct *fsp,
619 : TALLOC_CTX *mem_ctx,
620 : struct readdir_attr_data **attr_data)
621 : {
622 895820 : return NT_STATUS_NOT_SUPPORTED;
623 : }
624 :
625 2350 : static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
626 : {
627 2350 : START_PROFILE(syscall_rewinddir);
628 2350 : rewinddir(dirp);
629 2350 : END_PROFILE(syscall_rewinddir);
630 2350 : }
631 :
632 13105 : static int vfswrap_mkdirat(vfs_handle_struct *handle,
633 : struct files_struct *dirfsp,
634 : const struct smb_filename *smb_fname,
635 : mode_t mode)
636 : {
637 72 : int result;
638 :
639 13105 : START_PROFILE(syscall_mkdirat);
640 :
641 13105 : result = mkdirat(fsp_get_pathref_fd(dirfsp), smb_fname->base_name, mode);
642 :
643 13105 : END_PROFILE(syscall_mkdirat);
644 13105 : return result;
645 : }
646 :
647 308702 : static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
648 : {
649 1133 : int result;
650 :
651 308702 : START_PROFILE(syscall_closedir);
652 308702 : result = closedir(dirp);
653 308702 : END_PROFILE(syscall_closedir);
654 308702 : return result;
655 : }
656 :
657 : /* File operations */
658 :
659 6132060 : static int vfswrap_openat(vfs_handle_struct *handle,
660 : const struct files_struct *dirfsp,
661 : const struct smb_filename *smb_fname,
662 : files_struct *fsp,
663 : const struct vfs_open_how *how)
664 : {
665 6132060 : int flags = how->flags;
666 6132060 : mode_t mode = how->mode;
667 6132060 : bool have_opath = false;
668 6132060 : bool became_root = false;
669 30197 : int result;
670 :
671 6132060 : START_PROFILE(syscall_openat);
672 :
673 6132060 : if (how->resolve & ~(VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS |
674 : VFS_OPEN_HOW_WITH_BACKUP_INTENT)) {
675 0 : errno = ENOSYS;
676 0 : result = -1;
677 0 : goto out;
678 : }
679 :
680 6132060 : SMB_ASSERT(!is_named_stream(smb_fname));
681 :
682 : #ifdef O_PATH
683 4216749 : have_opath = true;
684 4216749 : if (fsp->fsp_flags.is_pathref) {
685 3358428 : flags |= O_PATH;
686 : }
687 4216749 : if (flags & O_PATH) {
688 : /*
689 : * From "man 2 openat":
690 : *
691 : * When O_PATH is specified in flags, flag bits other than
692 : * O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored.
693 : *
694 : * From "man 2 openat2":
695 : *
696 : * Whereas openat(2) ignores unknown bits in its flags
697 : * argument, openat2() returns an error if unknown or
698 : * conflicting flags are specified in how.flags.
699 : *
700 : * So we better clear ignored/invalid flags
701 : * and only keep the expected ones.
702 : */
703 3866691 : flags &= (O_PATH|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
704 : }
705 : #endif
706 :
707 6132060 : if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
708 245226 : struct open_how linux_how = {
709 : .flags = flags,
710 : .mode = mode,
711 : .resolve = RESOLVE_NO_SYMLINKS,
712 : };
713 :
714 245226 : result = openat2(fsp_get_pathref_fd(dirfsp),
715 : smb_fname->base_name,
716 : &linux_how,
717 : sizeof(linux_how));
718 245226 : if (result == -1) {
719 18267 : if (errno == ENOSYS) {
720 : /*
721 : * The kernel doesn't support
722 : * openat2(), so indicate to
723 : * the callers that
724 : * VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
725 : * would just be a waste of time.
726 : */
727 0 : fsp->conn->open_how_resolve &=
728 : ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
729 : }
730 18267 : goto out;
731 : }
732 :
733 226959 : goto done;
734 : }
735 :
736 5886834 : if (fsp->fsp_flags.is_pathref && !have_opath) {
737 1493674 : become_root();
738 1493674 : became_root = true;
739 : }
740 :
741 5886834 : result = openat(fsp_get_pathref_fd(dirfsp),
742 5886834 : smb_fname->base_name,
743 : flags,
744 : mode);
745 :
746 5865546 : if (became_root) {
747 1493674 : int err = errno;
748 1493674 : unbecome_root();
749 1493674 : errno = err;
750 : }
751 :
752 4402066 : done:
753 6113793 : if (result >= 0) {
754 4400649 : fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
755 : } else {
756 : /*
757 : * "/proc/self/fd/-1" never exists. Indicate to upper
758 : * layers that for this fsp a possible name-based
759 : * fallback is the only way to go.
760 : */
761 1713144 : fsp->fsp_flags.have_proc_fds = false;
762 : }
763 :
764 6132060 : out:
765 6132060 : END_PROFILE(syscall_openat);
766 6132060 : return result;
767 : }
768 551109 : static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
769 : struct smb_request *req,
770 : struct files_struct *dirfsp,
771 : struct smb_filename *smb_fname,
772 : uint32_t access_mask,
773 : uint32_t share_access,
774 : uint32_t create_disposition,
775 : uint32_t create_options,
776 : uint32_t file_attributes,
777 : uint32_t oplock_request,
778 : const struct smb2_lease *lease,
779 : uint64_t allocation_size,
780 : uint32_t private_flags,
781 : struct security_descriptor *sd,
782 : struct ea_list *ea_list,
783 : files_struct **result,
784 : int *pinfo,
785 : const struct smb2_create_blobs *in_context_blobs,
786 : struct smb2_create_blobs *out_context_blobs)
787 : {
788 551109 : return create_file_default(handle->conn, req, dirfsp, smb_fname,
789 : access_mask, share_access,
790 : create_disposition, create_options,
791 : file_attributes, oplock_request, lease,
792 : allocation_size, private_flags,
793 : sd, ea_list, result,
794 : pinfo, in_context_blobs, out_context_blobs);
795 : }
796 :
797 4091969 : static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
798 : {
799 24929 : int result;
800 :
801 4091969 : START_PROFILE(syscall_close);
802 4091969 : result = fd_close_posix(fsp);
803 4091969 : END_PROFILE(syscall_close);
804 4091969 : return result;
805 : }
806 :
807 4406 : static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
808 : size_t n, off_t offset)
809 : {
810 14 : ssize_t result;
811 :
812 : #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
813 4406 : START_PROFILE_BYTES(syscall_pread, n);
814 4406 : result = sys_pread_full(fsp_get_io_fd(fsp), data, n, offset);
815 4406 : END_PROFILE_BYTES(syscall_pread);
816 :
817 4406 : if (result == -1 && errno == ESPIPE) {
818 : /* Maintain the fiction that pipes can be seeked (sought?) on. */
819 0 : result = sys_read(fsp_get_io_fd(fsp), data, n);
820 0 : fh_set_pos(fsp->fh, 0);
821 : }
822 :
823 : #else /* HAVE_PREAD */
824 : errno = ENOSYS;
825 : result = -1;
826 : #endif /* HAVE_PREAD */
827 :
828 4406 : return result;
829 : }
830 :
831 1064 : static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
832 : size_t n, off_t offset)
833 : {
834 14 : ssize_t result;
835 :
836 : #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
837 1064 : START_PROFILE_BYTES(syscall_pwrite, n);
838 1064 : result = sys_pwrite_full(fsp_get_io_fd(fsp), data, n, offset);
839 1064 : END_PROFILE_BYTES(syscall_pwrite);
840 :
841 1064 : if (result == -1 && errno == ESPIPE) {
842 : /* Maintain the fiction that pipes can be sought on. */
843 0 : result = sys_write(fsp_get_io_fd(fsp), data, n);
844 : }
845 :
846 : #else /* HAVE_PWRITE */
847 : errno = ENOSYS;
848 : result = -1;
849 : #endif /* HAVE_PWRITE */
850 :
851 1064 : return result;
852 : }
853 :
854 : struct vfswrap_pread_state {
855 : ssize_t ret;
856 : int fd;
857 : void *buf;
858 : size_t count;
859 : off_t offset;
860 :
861 : struct vfs_aio_state vfs_aio_state;
862 : SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
863 : };
864 :
865 : static void vfs_pread_do(void *private_data);
866 : static void vfs_pread_done(struct tevent_req *subreq);
867 : static int vfs_pread_state_destructor(struct vfswrap_pread_state *state);
868 :
869 12917 : static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
870 : TALLOC_CTX *mem_ctx,
871 : struct tevent_context *ev,
872 : struct files_struct *fsp,
873 : void *data,
874 : size_t n, off_t offset)
875 : {
876 42 : struct tevent_req *req, *subreq;
877 42 : struct vfswrap_pread_state *state;
878 :
879 12917 : req = tevent_req_create(mem_ctx, &state, struct vfswrap_pread_state);
880 12917 : if (req == NULL) {
881 0 : return NULL;
882 : }
883 :
884 12917 : state->ret = -1;
885 12917 : state->fd = fsp_get_io_fd(fsp);
886 12917 : state->buf = data;
887 12917 : state->count = n;
888 12917 : state->offset = offset;
889 :
890 12917 : SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
891 : state->profile_bytes, n);
892 12917 : SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
893 :
894 12959 : subreq = pthreadpool_tevent_job_send(
895 12917 : state, ev, handle->conn->sconn->pool,
896 : vfs_pread_do, state);
897 12917 : if (tevent_req_nomem(subreq, req)) {
898 0 : return tevent_req_post(req, ev);
899 : }
900 12917 : tevent_req_set_callback(subreq, vfs_pread_done, req);
901 :
902 12917 : talloc_set_destructor(state, vfs_pread_state_destructor);
903 :
904 12917 : return req;
905 : }
906 :
907 12917 : static void vfs_pread_do(void *private_data)
908 : {
909 12917 : struct vfswrap_pread_state *state = talloc_get_type_abort(
910 : private_data, struct vfswrap_pread_state);
911 42 : struct timespec start_time;
912 42 : struct timespec end_time;
913 :
914 12917 : SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
915 :
916 12917 : PROFILE_TIMESTAMP(&start_time);
917 :
918 12917 : state->ret = sys_pread_full(state->fd,
919 : state->buf,
920 : state->count,
921 : state->offset);
922 :
923 12917 : if (state->ret == -1) {
924 0 : state->vfs_aio_state.error = errno;
925 : }
926 :
927 12917 : PROFILE_TIMESTAMP(&end_time);
928 :
929 12917 : state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
930 :
931 12917 : SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
932 12917 : }
933 :
934 0 : static int vfs_pread_state_destructor(struct vfswrap_pread_state *state)
935 : {
936 0 : return -1;
937 : }
938 :
939 12917 : static void vfs_pread_done(struct tevent_req *subreq)
940 : {
941 12917 : struct tevent_req *req = tevent_req_callback_data(
942 : subreq, struct tevent_req);
943 12917 : struct vfswrap_pread_state *state = tevent_req_data(
944 : req, struct vfswrap_pread_state);
945 42 : int ret;
946 :
947 12917 : ret = pthreadpool_tevent_job_recv(subreq);
948 12917 : TALLOC_FREE(subreq);
949 12917 : SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
950 12917 : talloc_set_destructor(state, NULL);
951 12917 : if (ret != 0) {
952 0 : if (ret != EAGAIN) {
953 0 : tevent_req_error(req, ret);
954 0 : return;
955 : }
956 : /*
957 : * If we get EAGAIN from pthreadpool_tevent_job_recv() this
958 : * means the lower level pthreadpool failed to create a new
959 : * thread. Fallback to sync processing in that case to allow
960 : * some progress for the client.
961 : */
962 0 : vfs_pread_do(state);
963 : }
964 :
965 12917 : tevent_req_done(req);
966 : }
967 :
968 12917 : static ssize_t vfswrap_pread_recv(struct tevent_req *req,
969 : struct vfs_aio_state *vfs_aio_state)
970 : {
971 12917 : struct vfswrap_pread_state *state = tevent_req_data(
972 : req, struct vfswrap_pread_state);
973 :
974 12917 : if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
975 0 : return -1;
976 : }
977 :
978 12917 : *vfs_aio_state = state->vfs_aio_state;
979 12917 : return state->ret;
980 : }
981 :
982 : struct vfswrap_pwrite_state {
983 : ssize_t ret;
984 : int fd;
985 : const void *buf;
986 : size_t count;
987 : off_t offset;
988 :
989 : struct vfs_aio_state vfs_aio_state;
990 : SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
991 : };
992 :
993 : static void vfs_pwrite_do(void *private_data);
994 : static void vfs_pwrite_done(struct tevent_req *subreq);
995 : static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state);
996 :
997 143664 : static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
998 : TALLOC_CTX *mem_ctx,
999 : struct tevent_context *ev,
1000 : struct files_struct *fsp,
1001 : const void *data,
1002 : size_t n, off_t offset)
1003 : {
1004 52 : struct tevent_req *req, *subreq;
1005 52 : struct vfswrap_pwrite_state *state;
1006 :
1007 143664 : req = tevent_req_create(mem_ctx, &state, struct vfswrap_pwrite_state);
1008 143664 : if (req == NULL) {
1009 0 : return NULL;
1010 : }
1011 :
1012 143664 : state->ret = -1;
1013 143664 : state->fd = fsp_get_io_fd(fsp);
1014 143664 : state->buf = data;
1015 143664 : state->count = n;
1016 143664 : state->offset = offset;
1017 :
1018 143664 : SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
1019 : state->profile_bytes, n);
1020 143664 : SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1021 :
1022 143716 : subreq = pthreadpool_tevent_job_send(
1023 143664 : state, ev, handle->conn->sconn->pool,
1024 : vfs_pwrite_do, state);
1025 143664 : if (tevent_req_nomem(subreq, req)) {
1026 0 : return tevent_req_post(req, ev);
1027 : }
1028 143664 : tevent_req_set_callback(subreq, vfs_pwrite_done, req);
1029 :
1030 143664 : talloc_set_destructor(state, vfs_pwrite_state_destructor);
1031 :
1032 143664 : return req;
1033 : }
1034 :
1035 143664 : static void vfs_pwrite_do(void *private_data)
1036 : {
1037 143664 : struct vfswrap_pwrite_state *state = talloc_get_type_abort(
1038 : private_data, struct vfswrap_pwrite_state);
1039 52 : struct timespec start_time;
1040 52 : struct timespec end_time;
1041 :
1042 143664 : SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1043 :
1044 143664 : PROFILE_TIMESTAMP(&start_time);
1045 :
1046 143664 : state->ret = sys_pwrite_full(state->fd,
1047 : state->buf,
1048 : state->count,
1049 : state->offset);
1050 :
1051 143664 : if (state->ret == -1) {
1052 0 : state->vfs_aio_state.error = errno;
1053 : }
1054 :
1055 143664 : PROFILE_TIMESTAMP(&end_time);
1056 :
1057 143664 : state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1058 :
1059 143664 : SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1060 143664 : }
1061 :
1062 0 : static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state)
1063 : {
1064 0 : return -1;
1065 : }
1066 :
1067 143664 : static void vfs_pwrite_done(struct tevent_req *subreq)
1068 : {
1069 143664 : struct tevent_req *req = tevent_req_callback_data(
1070 : subreq, struct tevent_req);
1071 143664 : struct vfswrap_pwrite_state *state = tevent_req_data(
1072 : req, struct vfswrap_pwrite_state);
1073 52 : int ret;
1074 :
1075 143664 : ret = pthreadpool_tevent_job_recv(subreq);
1076 143664 : TALLOC_FREE(subreq);
1077 143664 : SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1078 143664 : talloc_set_destructor(state, NULL);
1079 143664 : if (ret != 0) {
1080 0 : if (ret != EAGAIN) {
1081 0 : tevent_req_error(req, ret);
1082 0 : return;
1083 : }
1084 : /*
1085 : * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1086 : * means the lower level pthreadpool failed to create a new
1087 : * thread. Fallback to sync processing in that case to allow
1088 : * some progress for the client.
1089 : */
1090 0 : vfs_pwrite_do(state);
1091 : }
1092 :
1093 143664 : tevent_req_done(req);
1094 : }
1095 :
1096 143664 : static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
1097 : struct vfs_aio_state *vfs_aio_state)
1098 : {
1099 143664 : struct vfswrap_pwrite_state *state = tevent_req_data(
1100 : req, struct vfswrap_pwrite_state);
1101 :
1102 143664 : if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1103 0 : return -1;
1104 : }
1105 :
1106 143664 : *vfs_aio_state = state->vfs_aio_state;
1107 143664 : return state->ret;
1108 : }
1109 :
1110 : struct vfswrap_fsync_state {
1111 : ssize_t ret;
1112 : int fd;
1113 :
1114 : struct vfs_aio_state vfs_aio_state;
1115 : SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1116 : };
1117 :
1118 : static void vfs_fsync_do(void *private_data);
1119 : static void vfs_fsync_done(struct tevent_req *subreq);
1120 : static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state);
1121 :
1122 146 : static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
1123 : TALLOC_CTX *mem_ctx,
1124 : struct tevent_context *ev,
1125 : struct files_struct *fsp)
1126 : {
1127 2 : struct tevent_req *req, *subreq;
1128 2 : struct vfswrap_fsync_state *state;
1129 :
1130 146 : req = tevent_req_create(mem_ctx, &state, struct vfswrap_fsync_state);
1131 146 : if (req == NULL) {
1132 0 : return NULL;
1133 : }
1134 :
1135 146 : state->ret = -1;
1136 146 : state->fd = fsp_get_io_fd(fsp);
1137 :
1138 146 : SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1139 : state->profile_bytes, 0);
1140 146 : SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1141 :
1142 148 : subreq = pthreadpool_tevent_job_send(
1143 146 : state, ev, handle->conn->sconn->pool, vfs_fsync_do, state);
1144 146 : if (tevent_req_nomem(subreq, req)) {
1145 0 : return tevent_req_post(req, ev);
1146 : }
1147 146 : tevent_req_set_callback(subreq, vfs_fsync_done, req);
1148 :
1149 146 : talloc_set_destructor(state, vfs_fsync_state_destructor);
1150 :
1151 146 : return req;
1152 : }
1153 :
1154 146 : static void vfs_fsync_do(void *private_data)
1155 : {
1156 146 : struct vfswrap_fsync_state *state = talloc_get_type_abort(
1157 : private_data, struct vfswrap_fsync_state);
1158 2 : struct timespec start_time;
1159 2 : struct timespec end_time;
1160 :
1161 146 : SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1162 :
1163 146 : PROFILE_TIMESTAMP(&start_time);
1164 :
1165 2 : do {
1166 146 : state->ret = fsync(state->fd);
1167 146 : } while ((state->ret == -1) && (errno == EINTR));
1168 :
1169 146 : if (state->ret == -1) {
1170 0 : state->vfs_aio_state.error = errno;
1171 : }
1172 :
1173 146 : PROFILE_TIMESTAMP(&end_time);
1174 :
1175 146 : state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1176 :
1177 146 : SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1178 146 : }
1179 :
1180 0 : static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state)
1181 : {
1182 0 : return -1;
1183 : }
1184 :
1185 146 : static void vfs_fsync_done(struct tevent_req *subreq)
1186 : {
1187 146 : struct tevent_req *req = tevent_req_callback_data(
1188 : subreq, struct tevent_req);
1189 146 : struct vfswrap_fsync_state *state = tevent_req_data(
1190 : req, struct vfswrap_fsync_state);
1191 2 : int ret;
1192 :
1193 146 : ret = pthreadpool_tevent_job_recv(subreq);
1194 146 : TALLOC_FREE(subreq);
1195 146 : SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1196 146 : talloc_set_destructor(state, NULL);
1197 146 : if (ret != 0) {
1198 0 : if (ret != EAGAIN) {
1199 0 : tevent_req_error(req, ret);
1200 0 : return;
1201 : }
1202 : /*
1203 : * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1204 : * means the lower level pthreadpool failed to create a new
1205 : * thread. Fallback to sync processing in that case to allow
1206 : * some progress for the client.
1207 : */
1208 0 : vfs_fsync_do(state);
1209 : }
1210 :
1211 146 : tevent_req_done(req);
1212 : }
1213 :
1214 146 : static int vfswrap_fsync_recv(struct tevent_req *req,
1215 : struct vfs_aio_state *vfs_aio_state)
1216 : {
1217 146 : struct vfswrap_fsync_state *state = tevent_req_data(
1218 : req, struct vfswrap_fsync_state);
1219 :
1220 146 : if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1221 0 : return -1;
1222 : }
1223 :
1224 146 : *vfs_aio_state = state->vfs_aio_state;
1225 146 : return state->ret;
1226 : }
1227 :
1228 445 : static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
1229 : {
1230 445 : off_t result = 0;
1231 :
1232 445 : START_PROFILE(syscall_lseek);
1233 :
1234 445 : result = lseek(fsp_get_io_fd(fsp), offset, whence);
1235 : /*
1236 : * We want to maintain the fiction that we can seek
1237 : * on a fifo for file system purposes. This allows
1238 : * people to set up UNIX fifo's that feed data to Windows
1239 : * applications. JRA.
1240 : */
1241 :
1242 445 : if((result == -1) && (errno == ESPIPE)) {
1243 0 : result = 0;
1244 0 : errno = 0;
1245 : }
1246 :
1247 445 : END_PROFILE(syscall_lseek);
1248 445 : return result;
1249 : }
1250 :
1251 0 : static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
1252 : off_t offset, size_t n)
1253 : {
1254 0 : ssize_t result;
1255 :
1256 0 : START_PROFILE_BYTES(syscall_sendfile, n);
1257 0 : result = sys_sendfile(tofd, fsp_get_io_fd(fromfsp), hdr, offset, n);
1258 0 : END_PROFILE_BYTES(syscall_sendfile);
1259 0 : return result;
1260 : }
1261 :
1262 0 : static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
1263 : int fromfd,
1264 : files_struct *tofsp,
1265 : off_t offset,
1266 : size_t n)
1267 : {
1268 0 : ssize_t result;
1269 :
1270 0 : START_PROFILE_BYTES(syscall_recvfile, n);
1271 0 : result = sys_recvfile(fromfd, fsp_get_io_fd(tofsp), offset, n);
1272 0 : END_PROFILE_BYTES(syscall_recvfile);
1273 0 : return result;
1274 : }
1275 :
1276 972 : static int vfswrap_renameat(vfs_handle_struct *handle,
1277 : files_struct *srcfsp,
1278 : const struct smb_filename *smb_fname_src,
1279 : files_struct *dstfsp,
1280 : const struct smb_filename *smb_fname_dst)
1281 : {
1282 972 : int result = -1;
1283 :
1284 972 : START_PROFILE(syscall_renameat);
1285 :
1286 972 : SMB_ASSERT(!is_named_stream(smb_fname_src));
1287 972 : SMB_ASSERT(!is_named_stream(smb_fname_dst));
1288 :
1289 972 : result = renameat(fsp_get_pathref_fd(srcfsp),
1290 972 : smb_fname_src->base_name,
1291 : fsp_get_pathref_fd(dstfsp),
1292 972 : smb_fname_dst->base_name);
1293 :
1294 972 : END_PROFILE(syscall_renameat);
1295 972 : return result;
1296 : }
1297 :
1298 5675700 : static int vfswrap_stat(vfs_handle_struct *handle,
1299 : struct smb_filename *smb_fname)
1300 : {
1301 5675700 : int result = -1;
1302 :
1303 5675700 : START_PROFILE(syscall_stat);
1304 :
1305 5675700 : SMB_ASSERT(!is_named_stream(smb_fname));
1306 :
1307 5675700 : result = sys_stat(smb_fname->base_name, &smb_fname->st,
1308 5675700 : lp_fake_directory_create_times(SNUM(handle->conn)));
1309 :
1310 5675700 : END_PROFILE(syscall_stat);
1311 5675700 : return result;
1312 : }
1313 :
1314 34270240 : static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1315 : {
1316 125624 : int result;
1317 :
1318 34270240 : START_PROFILE(syscall_fstat);
1319 34270240 : result = sys_fstat(fsp_get_pathref_fd(fsp),
1320 34270240 : sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
1321 34270240 : END_PROFILE(syscall_fstat);
1322 34270240 : return result;
1323 : }
1324 :
1325 82689 : static int vfswrap_lstat(vfs_handle_struct *handle,
1326 : struct smb_filename *smb_fname)
1327 : {
1328 82689 : int result = -1;
1329 :
1330 82689 : START_PROFILE(syscall_lstat);
1331 :
1332 82689 : SMB_ASSERT(!is_named_stream(smb_fname));
1333 :
1334 82689 : result = sys_lstat(smb_fname->base_name, &smb_fname->st,
1335 82689 : lp_fake_directory_create_times(SNUM(handle->conn)));
1336 :
1337 82689 : END_PROFILE(syscall_lstat);
1338 82689 : return result;
1339 : }
1340 :
1341 45040 : static int vfswrap_fstatat(
1342 : struct vfs_handle_struct *handle,
1343 : const struct files_struct *dirfsp,
1344 : const struct smb_filename *smb_fname,
1345 : SMB_STRUCT_STAT *sbuf,
1346 : int flags)
1347 : {
1348 45040 : int result = -1;
1349 :
1350 45040 : START_PROFILE(syscall_fstatat);
1351 :
1352 45040 : SMB_ASSERT(!is_named_stream(smb_fname));
1353 :
1354 45040 : result = sys_fstatat(
1355 : fsp_get_pathref_fd(dirfsp),
1356 45040 : smb_fname->base_name,
1357 : sbuf,
1358 : flags,
1359 45040 : lp_fake_directory_create_times(SNUM(handle->conn)));
1360 :
1361 45040 : END_PROFILE(syscall_fstatat);
1362 45040 : return result;
1363 : }
1364 :
1365 160724157 : static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1366 : const char *name,
1367 : enum vfs_translate_direction direction,
1368 : TALLOC_CTX *mem_ctx,
1369 : char **mapped_name)
1370 : {
1371 160724157 : return NT_STATUS_NONE_MAPPED;
1372 : }
1373 :
1374 : /**
1375 : * Return allocated parent directory and basename of path
1376 : *
1377 : * Note: if requesting atname, it is returned as talloc child of the
1378 : * parent. Freeing the parent is thus sufficient to free both.
1379 : */
1380 4180884 : static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
1381 : TALLOC_CTX *mem_ctx,
1382 : const struct smb_filename *smb_fname_in,
1383 : struct smb_filename **parent_dir_out,
1384 : struct smb_filename **atname_out)
1385 : {
1386 4180884 : struct smb_filename *parent = NULL;
1387 4180884 : struct smb_filename *name = NULL;
1388 4180884 : char *p = NULL;
1389 :
1390 4180884 : parent = cp_smb_filename_nostream(mem_ctx, smb_fname_in);
1391 4180884 : if (parent == NULL) {
1392 0 : return NT_STATUS_NO_MEMORY;
1393 : }
1394 4180884 : SET_STAT_INVALID(parent->st);
1395 :
1396 4180884 : p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
1397 4180884 : if (p == NULL) {
1398 2932141 : TALLOC_FREE(parent->base_name);
1399 2932141 : parent->base_name = talloc_strdup(parent, ".");
1400 2932141 : if (parent->base_name == NULL) {
1401 0 : TALLOC_FREE(parent);
1402 0 : return NT_STATUS_NO_MEMORY;
1403 : }
1404 2932141 : p = smb_fname_in->base_name;
1405 : } else {
1406 1248743 : *p = '\0';
1407 1248743 : p++;
1408 : }
1409 :
1410 4180884 : if (atname_out == NULL) {
1411 1130 : *parent_dir_out = parent;
1412 1130 : return NT_STATUS_OK;
1413 : }
1414 :
1415 4192290 : name = synthetic_smb_fname(
1416 : parent,
1417 : p,
1418 4179754 : smb_fname_in->stream_name,
1419 : &smb_fname_in->st,
1420 4179754 : smb_fname_in->twrp,
1421 4179754 : smb_fname_in->flags);
1422 4179754 : if (name == NULL) {
1423 0 : return NT_STATUS_NO_MEMORY;
1424 : }
1425 :
1426 4179754 : *parent_dir_out = parent;
1427 4179754 : *atname_out = name;
1428 4179754 : return NT_STATUS_OK;
1429 : }
1430 :
1431 : /*
1432 : * Implement the default fsctl operation.
1433 : */
1434 : static bool vfswrap_logged_ioctl_message = false;
1435 :
1436 3516 : static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1437 : struct files_struct *fsp,
1438 : TALLOC_CTX *ctx,
1439 : uint32_t function,
1440 : uint16_t req_flags, /* Needed for UNICODE ... */
1441 : const uint8_t *_in_data,
1442 : uint32_t in_len,
1443 : uint8_t **_out_data,
1444 : uint32_t max_out_len,
1445 : uint32_t *out_len)
1446 : {
1447 3516 : const char *in_data = (const char *)_in_data;
1448 3516 : char **out_data = (char **)_out_data;
1449 4 : NTSTATUS status;
1450 :
1451 : /*
1452 : * Currently all fsctls operate on the base
1453 : * file if given an alternate data stream.
1454 : * Revisit this if we implement fsctls later
1455 : * that need access to the ADS handle.
1456 : */
1457 3516 : fsp = metadata_fsp(fsp);
1458 :
1459 3516 : switch (function) {
1460 242 : case FSCTL_SET_SPARSE:
1461 : {
1462 242 : bool set_sparse = true;
1463 :
1464 242 : if (in_len >= 1 && in_data[0] == 0) {
1465 40 : set_sparse = false;
1466 : }
1467 :
1468 242 : status = file_set_sparse(handle->conn, fsp, set_sparse);
1469 :
1470 242 : DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1471 : ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1472 : smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1473 : nt_errstr(status)));
1474 :
1475 242 : return status;
1476 : }
1477 :
1478 72 : case FSCTL_CREATE_OR_GET_OBJECT_ID:
1479 : {
1480 0 : unsigned char objid[16];
1481 72 : uint8_t *return_data = NULL;
1482 :
1483 : /* This should return the object-id on this file.
1484 : * I think I'll make this be the inode+dev. JRA.
1485 : */
1486 :
1487 72 : DBG_DEBUG("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1488 : fsp_fnum_dbg(fsp));
1489 :
1490 72 : *out_len = MIN(max_out_len, 64);
1491 :
1492 : /* Hmmm, will this cause problems if less data asked for? */
1493 72 : return_data = talloc_array(ctx, uint8_t, 64);
1494 72 : if (return_data == NULL) {
1495 0 : return NT_STATUS_NO_MEMORY;
1496 : }
1497 :
1498 : /* For backwards compatibility only store the dev/inode. */
1499 72 : push_file_id_16(return_data, &fsp->file_id);
1500 72 : memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1501 72 : push_file_id_16(return_data + 32, &fsp->file_id);
1502 72 : memset(return_data+48, 0, 16);
1503 72 : *_out_data = return_data;
1504 72 : return NT_STATUS_OK;
1505 : }
1506 :
1507 6 : case FSCTL_GET_REPARSE_POINT:
1508 : {
1509 0 : uint32_t tag;
1510 6 : status = fsctl_get_reparse_point(
1511 : fsp, ctx, &tag, _out_data, max_out_len, out_len);
1512 6 : return status;
1513 : }
1514 :
1515 62 : case FSCTL_SET_REPARSE_POINT:
1516 : {
1517 62 : status = fsctl_set_reparse_point(fsp, ctx, _in_data, in_len);
1518 62 : return status;
1519 : }
1520 :
1521 10 : case FSCTL_DELETE_REPARSE_POINT:
1522 : {
1523 10 : status = fsctl_del_reparse_point(fsp, ctx, _in_data, in_len);
1524 10 : return status;
1525 : }
1526 :
1527 3112 : case FSCTL_GET_SHADOW_COPY_DATA:
1528 : {
1529 : /*
1530 : * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1531 : * and return their volume names. If max_data_count is 16, then it is just
1532 : * asking for the number of volumes and length of the combined names.
1533 : *
1534 : * pdata is the data allocated by our caller, but that uses
1535 : * total_data_count (which is 0 in our case) rather than max_data_count.
1536 : * Allocate the correct amount and return the pointer to let
1537 : * it be deallocated when we return.
1538 : */
1539 3112 : struct shadow_copy_data *shadow_data = NULL;
1540 3112 : bool labels = False;
1541 3112 : uint32_t labels_data_count = 0;
1542 0 : uint32_t i;
1543 3112 : char *cur_pdata = NULL;
1544 :
1545 3112 : if (max_out_len < 16) {
1546 4 : DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1547 : max_out_len);
1548 4 : return NT_STATUS_INVALID_PARAMETER;
1549 : }
1550 :
1551 3108 : if (max_out_len > 16) {
1552 1413 : labels = True;
1553 : }
1554 :
1555 3108 : shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1556 3108 : if (shadow_data == NULL) {
1557 0 : DBG_ERR("TALLOC_ZERO() failed!\n");
1558 0 : return NT_STATUS_NO_MEMORY;
1559 : }
1560 :
1561 : /*
1562 : * Call the VFS routine to actually do the work.
1563 : */
1564 3108 : if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1565 276 : int log_lev = DBGLVL_ERR;
1566 276 : if (errno == 0) {
1567 : /* broken module didn't set errno on error */
1568 0 : status = NT_STATUS_UNSUCCESSFUL;
1569 : } else {
1570 276 : status = map_nt_error_from_unix(errno);
1571 276 : if (NT_STATUS_EQUAL(status,
1572 : NT_STATUS_NOT_SUPPORTED)) {
1573 276 : log_lev = DBGLVL_INFO;
1574 : }
1575 : }
1576 276 : DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1577 : "connectpath %s, failed - %s.\n",
1578 : fsp->conn->connectpath,
1579 : nt_errstr(status)));
1580 276 : TALLOC_FREE(shadow_data);
1581 276 : return status;
1582 : }
1583 :
1584 2832 : labels_data_count = (shadow_data->num_volumes * 2 *
1585 : sizeof(SHADOW_COPY_LABEL)) + 2;
1586 :
1587 2832 : if (!labels) {
1588 1419 : *out_len = 16;
1589 : } else {
1590 1413 : *out_len = 12 + labels_data_count;
1591 : }
1592 :
1593 2832 : if (max_out_len < *out_len) {
1594 0 : DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1595 : max_out_len, *out_len);
1596 0 : TALLOC_FREE(shadow_data);
1597 0 : return NT_STATUS_BUFFER_TOO_SMALL;
1598 : }
1599 :
1600 2832 : cur_pdata = talloc_zero_array(ctx, char, *out_len);
1601 2832 : if (cur_pdata == NULL) {
1602 0 : TALLOC_FREE(shadow_data);
1603 0 : return NT_STATUS_NO_MEMORY;
1604 : }
1605 :
1606 2832 : *out_data = cur_pdata;
1607 :
1608 : /* num_volumes 4 bytes */
1609 2832 : SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1610 :
1611 2832 : if (labels) {
1612 : /* num_labels 4 bytes */
1613 1413 : SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1614 : }
1615 :
1616 : /* needed_data_count 4 bytes */
1617 2832 : SIVAL(cur_pdata, 8, labels_data_count);
1618 :
1619 2832 : cur_pdata += 12;
1620 :
1621 2832 : DBG_DEBUG("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1622 : shadow_data->num_volumes, fsp_str_dbg(fsp));
1623 2832 : if (labels && shadow_data->labels) {
1624 5622 : for (i=0; i<shadow_data->num_volumes; i++) {
1625 4209 : size_t len = 0;
1626 4209 : status = srvstr_push(cur_pdata, req_flags,
1627 : cur_pdata, shadow_data->labels[i],
1628 : 2 * sizeof(SHADOW_COPY_LABEL),
1629 : STR_UNICODE|STR_TERMINATE, &len);
1630 4209 : if (!NT_STATUS_IS_OK(status)) {
1631 0 : TALLOC_FREE(*out_data);
1632 0 : TALLOC_FREE(shadow_data);
1633 0 : return status;
1634 : }
1635 4209 : cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1636 4209 : DEBUGADD(DBGLVL_DEBUG,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1637 : }
1638 : }
1639 :
1640 2832 : TALLOC_FREE(shadow_data);
1641 :
1642 2832 : return NT_STATUS_OK;
1643 : }
1644 :
1645 4 : case FSCTL_FIND_FILES_BY_SID:
1646 : {
1647 : /* pretend this succeeded -
1648 : *
1649 : * we have to send back a list with all files owned by this SID
1650 : *
1651 : * but I have to check that --metze
1652 : */
1653 0 : ssize_t ret;
1654 0 : struct dom_sid sid;
1655 0 : struct dom_sid_buf buf;
1656 0 : uid_t uid;
1657 0 : size_t sid_len;
1658 :
1659 4 : DBG_DEBUG("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1660 : fsp_fnum_dbg(fsp));
1661 :
1662 4 : if (in_len < 8) {
1663 : /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1664 4 : return NT_STATUS_INVALID_PARAMETER;
1665 : }
1666 :
1667 0 : sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1668 :
1669 : /* unknown 4 bytes: this is not the length of the sid :-( */
1670 : /*unknown = IVAL(pdata,0);*/
1671 :
1672 0 : ret = sid_parse(_in_data + 4, sid_len, &sid);
1673 0 : if (ret == -1) {
1674 0 : return NT_STATUS_INVALID_PARAMETER;
1675 : }
1676 0 : DEBUGADD(DBGLVL_DEBUG, ("for SID: %s\n",
1677 : dom_sid_str_buf(&sid, &buf)));
1678 :
1679 0 : if (!sid_to_uid(&sid, &uid)) {
1680 0 : DBG_ERR("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1681 : dom_sid_str_buf(&sid, &buf),
1682 : (unsigned long)sid_len);
1683 0 : uid = (-1);
1684 : }
1685 :
1686 : /* we can take a look at the find source :-)
1687 : *
1688 : * find ./ -uid $uid -name '*' is what we need here
1689 : *
1690 : *
1691 : * and send 4bytes len and then NULL terminated unicode strings
1692 : * for each file
1693 : *
1694 : * but I don't know how to deal with the paged results
1695 : * (maybe we can hang the result anywhere in the fsp struct)
1696 : *
1697 : * but I don't know how to deal with the paged results
1698 : * (maybe we can hang the result anywhere in the fsp struct)
1699 : *
1700 : * we don't send all files at once
1701 : * and at the next we should *not* start from the beginning,
1702 : * so we have to cache the result
1703 : *
1704 : * --metze
1705 : */
1706 :
1707 : /* this works for now... */
1708 0 : return NT_STATUS_OK;
1709 : }
1710 :
1711 4 : case FSCTL_QUERY_ALLOCATED_RANGES:
1712 : {
1713 : /* FIXME: This is just a dummy reply, telling that all of the
1714 : * file is allocated. MKS cp needs that.
1715 : * Adding the real allocated ranges via FIEMAP on Linux
1716 : * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1717 : * this FSCTL correct for sparse files.
1718 : */
1719 0 : uint64_t offset, length;
1720 4 : char *out_data_tmp = NULL;
1721 :
1722 4 : if (in_len != 16) {
1723 0 : DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1724 : in_len);
1725 0 : return NT_STATUS_INVALID_PARAMETER;
1726 : }
1727 :
1728 4 : if (max_out_len < 16) {
1729 0 : DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1730 : max_out_len);
1731 0 : return NT_STATUS_INVALID_PARAMETER;
1732 : }
1733 :
1734 4 : offset = BVAL(in_data,0);
1735 4 : length = BVAL(in_data,8);
1736 :
1737 4 : if (offset + length < offset) {
1738 : /* No 64-bit integer wrap. */
1739 0 : return NT_STATUS_INVALID_PARAMETER;
1740 : }
1741 :
1742 : /* Shouldn't this be SMB_VFS_STAT ... ? */
1743 4 : status = vfs_stat_fsp(fsp);
1744 4 : if (!NT_STATUS_IS_OK(status)) {
1745 0 : return status;
1746 : }
1747 :
1748 4 : *out_len = 16;
1749 4 : out_data_tmp = talloc_array(ctx, char, *out_len);
1750 4 : if (out_data_tmp == NULL) {
1751 0 : DBG_DEBUG("unable to allocate memory for response\n");
1752 0 : return NT_STATUS_NO_MEMORY;
1753 : }
1754 :
1755 4 : if (offset > fsp->fsp_name->st.st_ex_size ||
1756 4 : fsp->fsp_name->st.st_ex_size == 0 ||
1757 : length == 0) {
1758 4 : memset(out_data_tmp, 0, *out_len);
1759 : } else {
1760 0 : uint64_t end = offset + length;
1761 0 : end = MIN(end, fsp->fsp_name->st.st_ex_size);
1762 0 : SBVAL(out_data_tmp, 0, 0);
1763 0 : SBVAL(out_data_tmp, 8, end);
1764 : }
1765 :
1766 4 : *out_data = out_data_tmp;
1767 :
1768 4 : return NT_STATUS_OK;
1769 : }
1770 :
1771 4 : case FSCTL_IS_VOLUME_DIRTY:
1772 : {
1773 4 : DBG_DEBUG("FSCTL_IS_VOLUME_DIRTY: called on %s "
1774 : "(but remotely not supported)\n", fsp_fnum_dbg(fsp));
1775 : /*
1776 : * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1777 : * says we have to respond with NT_STATUS_INVALID_PARAMETER
1778 : */
1779 4 : return NT_STATUS_INVALID_PARAMETER;
1780 : }
1781 :
1782 0 : default:
1783 : /*
1784 : * Only print once ... unfortunately there could be lots of
1785 : * different FSCTLs that are called.
1786 : */
1787 0 : if (!vfswrap_logged_ioctl_message) {
1788 0 : vfswrap_logged_ioctl_message = true;
1789 0 : DBG_NOTICE("%s (0x%x): Currently not implemented.\n",
1790 : __func__, function);
1791 : }
1792 : }
1793 :
1794 0 : return NT_STATUS_NOT_SUPPORTED;
1795 : }
1796 :
1797 : static bool vfswrap_is_offline(struct connection_struct *conn,
1798 : const struct smb_filename *fname);
1799 :
1800 : struct vfswrap_get_dos_attributes_state {
1801 : struct vfs_aio_state aio_state;
1802 : connection_struct *conn;
1803 : TALLOC_CTX *mem_ctx;
1804 : struct tevent_context *ev;
1805 : files_struct *dir_fsp;
1806 : struct smb_filename *smb_fname;
1807 : uint32_t dosmode;
1808 : bool as_root;
1809 : };
1810 :
1811 : static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq);
1812 :
1813 20143 : static struct tevent_req *vfswrap_get_dos_attributes_send(
1814 : TALLOC_CTX *mem_ctx,
1815 : struct tevent_context *ev,
1816 : struct vfs_handle_struct *handle,
1817 : files_struct *dir_fsp,
1818 : struct smb_filename *smb_fname)
1819 : {
1820 20143 : struct tevent_req *req = NULL;
1821 20143 : struct tevent_req *subreq = NULL;
1822 20143 : struct vfswrap_get_dos_attributes_state *state = NULL;
1823 :
1824 20143 : SMB_ASSERT(!is_named_stream(smb_fname));
1825 :
1826 20143 : req = tevent_req_create(mem_ctx, &state,
1827 : struct vfswrap_get_dos_attributes_state);
1828 20143 : if (req == NULL) {
1829 0 : return NULL;
1830 : }
1831 :
1832 20143 : *state = (struct vfswrap_get_dos_attributes_state) {
1833 20143 : .conn = dir_fsp->conn,
1834 : .mem_ctx = mem_ctx,
1835 : .ev = ev,
1836 : .dir_fsp = dir_fsp,
1837 : .smb_fname = smb_fname,
1838 : };
1839 :
1840 20143 : if (!lp_store_dos_attributes(SNUM(dir_fsp->conn))) {
1841 0 : DBG_ERR("%s: \"smbd async dosmode\" enabled, but "
1842 : "\"store dos attributes\" is disabled\n",
1843 : dir_fsp->conn->connectpath);
1844 0 : tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
1845 0 : return tevent_req_post(req, ev);
1846 : }
1847 :
1848 20143 : subreq = SMB_VFS_GETXATTRAT_SEND(state,
1849 : ev,
1850 : dir_fsp,
1851 : smb_fname,
1852 : SAMBA_XATTR_DOS_ATTRIB,
1853 : sizeof(fstring));
1854 20143 : if (tevent_req_nomem(subreq, req)) {
1855 0 : return tevent_req_post(req, ev);
1856 : }
1857 20143 : tevent_req_set_callback(subreq,
1858 : vfswrap_get_dos_attributes_getxattr_done,
1859 : req);
1860 :
1861 20143 : return req;
1862 : }
1863 :
1864 20145 : static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq)
1865 : {
1866 0 : struct tevent_req *req =
1867 20145 : tevent_req_callback_data(subreq,
1868 : struct tevent_req);
1869 0 : struct vfswrap_get_dos_attributes_state *state =
1870 20145 : tevent_req_data(req,
1871 : struct vfswrap_get_dos_attributes_state);
1872 0 : ssize_t xattr_size;
1873 20145 : DATA_BLOB blob = {0};
1874 20145 : char *path = NULL;
1875 20145 : char *tofree = NULL;
1876 0 : char pathbuf[PATH_MAX+1];
1877 0 : ssize_t pathlen;
1878 0 : struct smb_filename smb_fname;
1879 0 : bool offline;
1880 0 : NTSTATUS status;
1881 :
1882 20145 : xattr_size = SMB_VFS_GETXATTRAT_RECV(subreq,
1883 : &state->aio_state,
1884 : state,
1885 : &blob.data);
1886 20145 : TALLOC_FREE(subreq);
1887 20145 : if (xattr_size == -1) {
1888 128 : status = map_nt_error_from_unix(state->aio_state.error);
1889 :
1890 128 : if (state->as_root) {
1891 2 : tevent_req_nterror(req, status);
1892 2 : return;
1893 : }
1894 126 : if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1895 124 : tevent_req_nterror(req, status);
1896 124 : return;
1897 : }
1898 :
1899 2 : state->as_root = true;
1900 :
1901 2 : become_root();
1902 2 : subreq = SMB_VFS_GETXATTRAT_SEND(state,
1903 : state->ev,
1904 : state->dir_fsp,
1905 : state->smb_fname,
1906 : SAMBA_XATTR_DOS_ATTRIB,
1907 : sizeof(fstring));
1908 2 : unbecome_root();
1909 2 : if (tevent_req_nomem(subreq, req)) {
1910 0 : return;
1911 : }
1912 2 : tevent_req_set_callback(subreq,
1913 : vfswrap_get_dos_attributes_getxattr_done,
1914 : req);
1915 2 : return;
1916 : }
1917 :
1918 20017 : blob.length = xattr_size;
1919 :
1920 20017 : status = parse_dos_attribute_blob(state->smb_fname,
1921 : blob,
1922 : &state->dosmode);
1923 20017 : if (!NT_STATUS_IS_OK(status)) {
1924 0 : tevent_req_nterror(req, status);
1925 0 : return;
1926 : }
1927 :
1928 20017 : pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
1929 20017 : state->smb_fname->base_name,
1930 : pathbuf,
1931 : sizeof(pathbuf),
1932 : &path,
1933 : &tofree);
1934 20017 : if (pathlen == -1) {
1935 0 : tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1936 0 : return;
1937 : }
1938 :
1939 20017 : smb_fname = (struct smb_filename) {
1940 : .base_name = path,
1941 20017 : .st = state->smb_fname->st,
1942 20017 : .flags = state->smb_fname->flags,
1943 20017 : .twrp = state->smb_fname->twrp,
1944 : };
1945 :
1946 20017 : offline = vfswrap_is_offline(state->conn, &smb_fname);
1947 20017 : if (offline) {
1948 0 : state->dosmode |= FILE_ATTRIBUTE_OFFLINE;
1949 : }
1950 20017 : TALLOC_FREE(tofree);
1951 :
1952 20017 : tevent_req_done(req);
1953 20017 : return;
1954 : }
1955 :
1956 20143 : static NTSTATUS vfswrap_get_dos_attributes_recv(struct tevent_req *req,
1957 : struct vfs_aio_state *aio_state,
1958 : uint32_t *dosmode)
1959 : {
1960 0 : struct vfswrap_get_dos_attributes_state *state =
1961 20143 : tevent_req_data(req,
1962 : struct vfswrap_get_dos_attributes_state);
1963 0 : NTSTATUS status;
1964 :
1965 20143 : if (tevent_req_is_nterror(req, &status)) {
1966 126 : tevent_req_received(req);
1967 126 : return status;
1968 : }
1969 :
1970 20017 : *aio_state = state->aio_state;
1971 20017 : *dosmode = state->dosmode;
1972 20017 : tevent_req_received(req);
1973 20017 : return NT_STATUS_OK;
1974 : }
1975 :
1976 1456035 : static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
1977 : struct files_struct *fsp,
1978 : uint32_t *dosmode)
1979 : {
1980 2249 : bool offline;
1981 :
1982 1456035 : SMB_ASSERT(!fsp_is_alternate_stream(fsp));
1983 :
1984 1456035 : offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
1985 1456035 : if (offline) {
1986 0 : *dosmode |= FILE_ATTRIBUTE_OFFLINE;
1987 : }
1988 :
1989 1456035 : return fget_ea_dos_attribute(fsp, dosmode);
1990 : }
1991 :
1992 175673 : static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
1993 : struct files_struct *fsp,
1994 : uint32_t dosmode)
1995 : {
1996 175673 : SMB_ASSERT(!fsp_is_alternate_stream(fsp));
1997 :
1998 175673 : return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
1999 : }
2000 :
2001 : static struct vfs_offload_ctx *vfswrap_offload_ctx;
2002 :
2003 : struct vfswrap_offload_read_state {
2004 : DATA_BLOB token;
2005 : };
2006 :
2007 280 : static struct tevent_req *vfswrap_offload_read_send(
2008 : TALLOC_CTX *mem_ctx,
2009 : struct tevent_context *ev,
2010 : struct vfs_handle_struct *handle,
2011 : struct files_struct *fsp,
2012 : uint32_t fsctl,
2013 : uint32_t ttl,
2014 : off_t offset,
2015 : size_t to_copy)
2016 : {
2017 280 : struct tevent_req *req = NULL;
2018 280 : struct vfswrap_offload_read_state *state = NULL;
2019 0 : NTSTATUS status;
2020 :
2021 280 : req = tevent_req_create(mem_ctx, &state,
2022 : struct vfswrap_offload_read_state);
2023 280 : if (req == NULL) {
2024 0 : return NULL;
2025 : }
2026 :
2027 280 : status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
2028 : &vfswrap_offload_ctx);
2029 280 : if (tevent_req_nterror(req, status)) {
2030 0 : return tevent_req_post(req, ev);
2031 : }
2032 :
2033 280 : if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY) {
2034 0 : tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
2035 0 : return tevent_req_post(req, ev);
2036 : }
2037 :
2038 280 : status = vfs_offload_token_create_blob(state, fsp, fsctl,
2039 280 : &state->token);
2040 280 : if (tevent_req_nterror(req, status)) {
2041 0 : return tevent_req_post(req, ev);
2042 : }
2043 :
2044 280 : status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
2045 280 : &state->token);
2046 280 : if (tevent_req_nterror(req, status)) {
2047 0 : return tevent_req_post(req, ev);
2048 : }
2049 :
2050 280 : tevent_req_done(req);
2051 280 : return tevent_req_post(req, ev);
2052 : }
2053 :
2054 280 : static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
2055 : struct vfs_handle_struct *handle,
2056 : TALLOC_CTX *mem_ctx,
2057 : uint32_t *flags,
2058 : uint64_t *xferlen,
2059 : DATA_BLOB *token)
2060 : {
2061 280 : struct vfswrap_offload_read_state *state = tevent_req_data(
2062 : req, struct vfswrap_offload_read_state);
2063 0 : NTSTATUS status;
2064 :
2065 280 : if (tevent_req_is_nterror(req, &status)) {
2066 0 : tevent_req_received(req);
2067 0 : return status;
2068 : }
2069 :
2070 280 : *flags = 0;
2071 280 : *xferlen = 0;
2072 280 : token->length = state->token.length;
2073 280 : token->data = talloc_move(mem_ctx, &state->token.data);
2074 :
2075 280 : tevent_req_received(req);
2076 280 : return NT_STATUS_OK;
2077 : }
2078 :
2079 : struct vfswrap_offload_write_state {
2080 : uint8_t *buf;
2081 : bool read_lck_locked;
2082 : bool write_lck_locked;
2083 : DATA_BLOB *token;
2084 : struct tevent_context *src_ev;
2085 : struct files_struct *src_fsp;
2086 : off_t src_off;
2087 : struct tevent_context *dst_ev;
2088 : struct files_struct *dst_fsp;
2089 : off_t dst_off;
2090 : off_t to_copy;
2091 : off_t remaining;
2092 : off_t copied;
2093 : size_t next_io_size;
2094 : };
2095 :
2096 624 : static void vfswrap_offload_write_cleanup(struct tevent_req *req,
2097 : enum tevent_req_state req_state)
2098 : {
2099 624 : struct vfswrap_offload_write_state *state = tevent_req_data(
2100 : req, struct vfswrap_offload_write_state);
2101 0 : bool ok;
2102 :
2103 624 : if (state->dst_fsp == NULL) {
2104 504 : return;
2105 : }
2106 :
2107 120 : ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2108 120 : SMB_ASSERT(ok);
2109 120 : state->dst_fsp = NULL;
2110 : }
2111 :
2112 : static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req);
2113 : static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
2114 :
2115 312 : static struct tevent_req *vfswrap_offload_write_send(
2116 : struct vfs_handle_struct *handle,
2117 : TALLOC_CTX *mem_ctx,
2118 : struct tevent_context *ev,
2119 : uint32_t fsctl,
2120 : DATA_BLOB *token,
2121 : off_t transfer_offset,
2122 : struct files_struct *dest_fsp,
2123 : off_t dest_off,
2124 : off_t to_copy)
2125 : {
2126 0 : struct tevent_req *req;
2127 312 : struct vfswrap_offload_write_state *state = NULL;
2128 : /* off_t is signed! */
2129 312 : off_t max_offset = INT64_MAX - to_copy;
2130 312 : size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
2131 312 : files_struct *src_fsp = NULL;
2132 0 : NTSTATUS status;
2133 0 : bool ok;
2134 :
2135 312 : req = tevent_req_create(mem_ctx, &state,
2136 : struct vfswrap_offload_write_state);
2137 312 : if (req == NULL) {
2138 0 : return NULL;
2139 : }
2140 :
2141 312 : *state = (struct vfswrap_offload_write_state) {
2142 : .token = token,
2143 : .src_off = transfer_offset,
2144 : .dst_ev = ev,
2145 : .dst_fsp = dest_fsp,
2146 : .dst_off = dest_off,
2147 : .to_copy = to_copy,
2148 : .remaining = to_copy,
2149 : };
2150 :
2151 312 : tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
2152 :
2153 312 : switch (fsctl) {
2154 312 : case FSCTL_SRV_COPYCHUNK:
2155 : case FSCTL_SRV_COPYCHUNK_WRITE:
2156 312 : break;
2157 :
2158 0 : case FSCTL_OFFLOAD_WRITE:
2159 0 : tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2160 0 : return tevent_req_post(req, ev);
2161 :
2162 0 : case FSCTL_DUP_EXTENTS_TO_FILE:
2163 0 : DBG_DEBUG("COW clones not supported by vfs_default\n");
2164 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2165 0 : return tevent_req_post(req, ev);
2166 :
2167 0 : default:
2168 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2169 0 : return tevent_req_post(req, ev);
2170 : }
2171 :
2172 : /*
2173 : * From here on we assume a copy-chunk fsctl
2174 : */
2175 :
2176 312 : if (to_copy == 0) {
2177 8 : tevent_req_done(req);
2178 8 : return tevent_req_post(req, ev);
2179 : }
2180 :
2181 304 : if (state->src_off > max_offset) {
2182 : /*
2183 : * Protect integer checks below.
2184 : */
2185 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2186 0 : return tevent_req_post(req, ev);
2187 : }
2188 304 : if (state->src_off < 0) {
2189 : /*
2190 : * Protect integer checks below.
2191 : */
2192 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2193 0 : return tevent_req_post(req, ev);
2194 : }
2195 304 : if (state->dst_off > max_offset) {
2196 : /*
2197 : * Protect integer checks below.
2198 : */
2199 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2200 0 : return tevent_req_post(req, ev);
2201 : }
2202 304 : if (state->dst_off < 0) {
2203 : /*
2204 : * Protect integer checks below.
2205 : */
2206 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2207 0 : return tevent_req_post(req, ev);
2208 : }
2209 :
2210 304 : status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2211 : token, &src_fsp);
2212 304 : if (tevent_req_nterror(req, status)) {
2213 16 : return tevent_req_post(req, ev);
2214 : }
2215 :
2216 288 : DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy);
2217 :
2218 288 : status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2219 288 : if (!NT_STATUS_IS_OK(status)) {
2220 24 : tevent_req_nterror(req, status);
2221 24 : return tevent_req_post(req, ev);
2222 : }
2223 :
2224 264 : ok = change_to_user_and_service_by_fsp(src_fsp);
2225 264 : if (!ok) {
2226 0 : tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2227 0 : return tevent_req_post(req, ev);
2228 : }
2229 :
2230 264 : state->src_ev = src_fsp->conn->sconn->ev_ctx;
2231 264 : state->src_fsp = src_fsp;
2232 :
2233 264 : status = vfs_stat_fsp(src_fsp);
2234 264 : if (tevent_req_nterror(req, status)) {
2235 0 : return tevent_req_post(req, ev);
2236 : }
2237 :
2238 264 : if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2239 : /*
2240 : * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2241 : * If the SourceOffset or SourceOffset + Length extends beyond
2242 : * the end of file, the server SHOULD<240> treat this as a
2243 : * STATUS_END_OF_FILE error.
2244 : * ...
2245 : * <240> Section 3.3.5.15.6: Windows servers will return
2246 : * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2247 : */
2248 16 : tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2249 16 : return tevent_req_post(req, ev);
2250 : }
2251 :
2252 248 : status = vfswrap_offload_copy_file_range(req);
2253 248 : if (NT_STATUS_IS_OK(status)) {
2254 192 : tevent_req_done(req);
2255 192 : return tevent_req_post(req, ev);
2256 : }
2257 56 : if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2258 16 : tevent_req_nterror(req, status);
2259 16 : return tevent_req_post(req, ev);
2260 : }
2261 :
2262 40 : state->buf = talloc_array(state, uint8_t, num);
2263 40 : if (tevent_req_nomem(state->buf, req)) {
2264 0 : return tevent_req_post(req, ev);
2265 : }
2266 :
2267 40 : status = vfswrap_offload_write_loop(req);
2268 40 : if (!NT_STATUS_IS_OK(status)) {
2269 0 : tevent_req_nterror(req, status);
2270 0 : return tevent_req_post(req, ev);
2271 : }
2272 :
2273 40 : return req;
2274 : }
2275 :
2276 248 : static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
2277 : {
2278 248 : struct vfswrap_offload_write_state *state = tevent_req_data(
2279 : req, struct vfswrap_offload_write_state);
2280 0 : struct lock_struct lck;
2281 0 : ssize_t nwritten;
2282 0 : NTSTATUS status;
2283 0 : bool same_file;
2284 0 : bool ok;
2285 0 : static bool try_copy_file_range = true;
2286 :
2287 248 : if (!try_copy_file_range) {
2288 0 : return NT_STATUS_MORE_PROCESSING_REQUIRED;
2289 : }
2290 :
2291 248 : same_file = file_id_equal(&state->src_fsp->file_id,
2292 248 : &state->dst_fsp->file_id);
2293 264 : if (same_file &&
2294 16 : sys_io_ranges_overlap(state->remaining,
2295 : state->src_off,
2296 16 : state->remaining,
2297 : state->dst_off))
2298 : {
2299 8 : return NT_STATUS_MORE_PROCESSING_REQUIRED;
2300 : }
2301 :
2302 448 : if (fsp_is_alternate_stream(state->src_fsp) ||
2303 208 : fsp_is_alternate_stream(state->dst_fsp))
2304 : {
2305 32 : return NT_STATUS_MORE_PROCESSING_REQUIRED;
2306 : }
2307 :
2308 416 : init_strict_lock_struct(state->src_fsp,
2309 208 : state->src_fsp->op->global->open_persistent_id,
2310 208 : state->src_off,
2311 208 : state->remaining,
2312 : READ_LOCK,
2313 208 : lp_posix_cifsu_locktype(state->src_fsp),
2314 : &lck);
2315 :
2316 208 : ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2317 : state->src_fsp,
2318 : &lck);
2319 208 : if (!ok) {
2320 8 : return NT_STATUS_FILE_LOCK_CONFLICT;
2321 : }
2322 :
2323 200 : ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2324 200 : if (!ok) {
2325 0 : return NT_STATUS_INTERNAL_ERROR;
2326 : }
2327 :
2328 400 : init_strict_lock_struct(state->dst_fsp,
2329 200 : state->dst_fsp->op->global->open_persistent_id,
2330 200 : state->dst_off,
2331 200 : state->remaining,
2332 : WRITE_LOCK,
2333 200 : lp_posix_cifsu_locktype(state->dst_fsp),
2334 : &lck);
2335 :
2336 200 : ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2337 : state->dst_fsp,
2338 : &lck);
2339 200 : if (!ok) {
2340 8 : return NT_STATUS_FILE_LOCK_CONFLICT;
2341 : }
2342 :
2343 384 : while (state->remaining > 0) {
2344 192 : nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
2345 192 : &state->src_off,
2346 192 : fsp_get_io_fd(state->dst_fsp),
2347 192 : &state->dst_off,
2348 192 : state->remaining,
2349 : 0);
2350 192 : if (nwritten == -1) {
2351 0 : DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
2352 : "n [%jd] failed: %s\n",
2353 : fsp_str_dbg(state->src_fsp),
2354 : (intmax_t)state->src_off,
2355 : fsp_str_dbg(state->dst_fsp),
2356 : (intmax_t)state->dst_off,
2357 : (intmax_t)state->remaining,
2358 : strerror(errno));
2359 0 : switch (errno) {
2360 0 : case EOPNOTSUPP:
2361 : case ENOSYS:
2362 0 : try_copy_file_range = false;
2363 0 : status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2364 0 : break;
2365 0 : case EXDEV:
2366 0 : status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2367 0 : break;
2368 0 : default:
2369 0 : status = map_nt_error_from_unix(errno);
2370 0 : if (NT_STATUS_EQUAL(
2371 : status,
2372 : NT_STATUS_MORE_PROCESSING_REQUIRED))
2373 : {
2374 : /* Avoid triggering the fallback */
2375 0 : status = NT_STATUS_INTERNAL_ERROR;
2376 : }
2377 0 : break;
2378 : }
2379 0 : return status;
2380 : }
2381 :
2382 192 : if (state->remaining < nwritten) {
2383 0 : DBG_DEBUG("copy_file_range src [%s] dst [%s] "
2384 : "n [%jd] remaining [%jd]\n",
2385 : fsp_str_dbg(state->src_fsp),
2386 : fsp_str_dbg(state->dst_fsp),
2387 : (intmax_t)nwritten,
2388 : (intmax_t)state->remaining);
2389 0 : return NT_STATUS_INTERNAL_ERROR;
2390 : }
2391 :
2392 192 : if (nwritten == 0) {
2393 0 : break;
2394 : }
2395 192 : state->copied += nwritten;
2396 192 : state->remaining -= nwritten;
2397 : }
2398 :
2399 : /*
2400 : * Tell the req cleanup function there's no need to call
2401 : * change_to_user_and_service_by_fsp() on the dst handle.
2402 : */
2403 192 : state->dst_fsp = NULL;
2404 192 : return NT_STATUS_OK;
2405 : }
2406 :
2407 : static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2408 :
2409 40 : static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2410 : {
2411 40 : struct vfswrap_offload_write_state *state = tevent_req_data(
2412 : req, struct vfswrap_offload_write_state);
2413 40 : struct tevent_req *subreq = NULL;
2414 0 : struct lock_struct read_lck;
2415 0 : bool ok;
2416 :
2417 : /*
2418 : * This is called under the context of state->src_fsp.
2419 : */
2420 :
2421 40 : state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2422 :
2423 80 : init_strict_lock_struct(state->src_fsp,
2424 40 : state->src_fsp->op->global->open_persistent_id,
2425 40 : state->src_off,
2426 : state->next_io_size,
2427 : READ_LOCK,
2428 40 : lp_posix_cifsu_locktype(state->src_fsp),
2429 : &read_lck);
2430 :
2431 40 : ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2432 : state->src_fsp,
2433 : &read_lck);
2434 40 : if (!ok) {
2435 0 : return NT_STATUS_FILE_LOCK_CONFLICT;
2436 : }
2437 :
2438 40 : subreq = SMB_VFS_PREAD_SEND(state,
2439 : state->src_ev,
2440 : state->src_fsp,
2441 : state->buf,
2442 : state->next_io_size,
2443 : state->src_off);
2444 40 : if (subreq == NULL) {
2445 0 : return NT_STATUS_NO_MEMORY;
2446 : }
2447 40 : tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2448 :
2449 40 : return NT_STATUS_OK;
2450 : }
2451 :
2452 : static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2453 :
2454 40 : static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2455 : {
2456 40 : struct tevent_req *req = tevent_req_callback_data(
2457 : subreq, struct tevent_req);
2458 40 : struct vfswrap_offload_write_state *state = tevent_req_data(
2459 : req, struct vfswrap_offload_write_state);
2460 0 : struct vfs_aio_state aio_state;
2461 0 : struct lock_struct write_lck;
2462 0 : ssize_t nread;
2463 0 : bool ok;
2464 :
2465 40 : nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2466 40 : TALLOC_FREE(subreq);
2467 40 : if (nread == -1) {
2468 0 : DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2469 0 : tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2470 0 : return;
2471 : }
2472 40 : if (nread != state->next_io_size) {
2473 0 : DBG_ERR("Short read, only %zd of %zu\n",
2474 : nread, state->next_io_size);
2475 0 : tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2476 0 : return;
2477 : }
2478 :
2479 40 : state->src_off += nread;
2480 :
2481 40 : ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2482 40 : if (!ok) {
2483 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2484 0 : return;
2485 : }
2486 :
2487 80 : init_strict_lock_struct(state->dst_fsp,
2488 40 : state->dst_fsp->op->global->open_persistent_id,
2489 40 : state->dst_off,
2490 : state->next_io_size,
2491 : WRITE_LOCK,
2492 40 : lp_posix_cifsu_locktype(state->dst_fsp),
2493 : &write_lck);
2494 :
2495 40 : ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2496 : state->dst_fsp,
2497 : &write_lck);
2498 40 : if (!ok) {
2499 0 : tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2500 0 : return;
2501 : }
2502 :
2503 40 : subreq = SMB_VFS_PWRITE_SEND(state,
2504 : state->dst_ev,
2505 : state->dst_fsp,
2506 : state->buf,
2507 : state->next_io_size,
2508 : state->dst_off);
2509 40 : if (subreq == NULL) {
2510 0 : tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2511 0 : return;
2512 : }
2513 40 : tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2514 : }
2515 :
2516 40 : static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2517 : {
2518 40 : struct tevent_req *req = tevent_req_callback_data(
2519 : subreq, struct tevent_req);
2520 40 : struct vfswrap_offload_write_state *state = tevent_req_data(
2521 : req, struct vfswrap_offload_write_state);
2522 0 : struct vfs_aio_state aio_state;
2523 0 : ssize_t nwritten;
2524 0 : NTSTATUS status;
2525 0 : bool ok;
2526 :
2527 40 : nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2528 40 : TALLOC_FREE(subreq);
2529 40 : if (nwritten == -1) {
2530 0 : DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2531 0 : tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2532 0 : return;
2533 : }
2534 40 : if (nwritten != state->next_io_size) {
2535 0 : DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2536 0 : tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2537 0 : return;
2538 : }
2539 :
2540 40 : state->dst_off += nwritten;
2541 :
2542 40 : if (state->remaining < nwritten) {
2543 : /* Paranoia check */
2544 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2545 0 : return;
2546 : }
2547 40 : state->copied += nwritten;
2548 40 : state->remaining -= nwritten;
2549 40 : if (state->remaining == 0) {
2550 40 : tevent_req_done(req);
2551 40 : return;
2552 : }
2553 :
2554 0 : ok = change_to_user_and_service_by_fsp(state->src_fsp);
2555 0 : if (!ok) {
2556 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2557 0 : return;
2558 : }
2559 :
2560 0 : status = vfswrap_offload_write_loop(req);
2561 0 : if (!NT_STATUS_IS_OK(status)) {
2562 0 : tevent_req_nterror(req, status);
2563 0 : return;
2564 : }
2565 :
2566 0 : return;
2567 : }
2568 :
2569 312 : static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2570 : struct tevent_req *req,
2571 : off_t *copied)
2572 : {
2573 312 : struct vfswrap_offload_write_state *state = tevent_req_data(
2574 : req, struct vfswrap_offload_write_state);
2575 0 : NTSTATUS status;
2576 :
2577 312 : if (tevent_req_is_nterror(req, &status)) {
2578 72 : DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2579 72 : *copied = 0;
2580 72 : tevent_req_received(req);
2581 72 : return status;
2582 : }
2583 :
2584 240 : *copied = state->copied;
2585 240 : DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2586 240 : tevent_req_received(req);
2587 :
2588 240 : return NT_STATUS_OK;
2589 : }
2590 :
2591 0 : static NTSTATUS vfswrap_fget_compression(struct vfs_handle_struct *handle,
2592 : TALLOC_CTX *mem_ctx,
2593 : struct files_struct *fsp,
2594 : uint16_t *_compression_fmt)
2595 : {
2596 0 : return NT_STATUS_INVALID_DEVICE_REQUEST;
2597 : }
2598 :
2599 0 : static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2600 : TALLOC_CTX *mem_ctx,
2601 : struct files_struct *fsp,
2602 : uint16_t compression_fmt)
2603 : {
2604 0 : return NT_STATUS_INVALID_DEVICE_REQUEST;
2605 : }
2606 :
2607 : /********************************************************************
2608 : Given a stat buffer return the allocated size on disk, taking into
2609 : account sparse files.
2610 : ********************************************************************/
2611 1708846 : static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2612 : struct files_struct *fsp,
2613 : const SMB_STRUCT_STAT *sbuf)
2614 : {
2615 4290 : uint64_t result;
2616 :
2617 1708846 : START_PROFILE(syscall_get_alloc_size);
2618 :
2619 1708846 : if(S_ISDIR(sbuf->st_ex_mode)) {
2620 148265 : result = 0;
2621 148265 : goto out;
2622 : }
2623 :
2624 : #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2625 : /* The type of st_blocksize is blkcnt_t which *MUST* be
2626 : signed (according to POSIX) and can be less than 64-bits.
2627 : Ensure when we're converting to 64 bits wide we don't
2628 : sign extend. */
2629 : #if defined(SIZEOF_BLKCNT_T_8)
2630 1560581 : result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2631 : #elif defined(SIZEOF_BLKCNT_T_4)
2632 : {
2633 : uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2634 : result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2635 : }
2636 : #else
2637 : #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2638 : #endif
2639 1560581 : if (result == 0) {
2640 : /*
2641 : * Some file systems do not allocate a block for very
2642 : * small files. But for non-empty file should report a
2643 : * positive size.
2644 : */
2645 :
2646 1482014 : uint64_t filesize = get_file_size_stat(sbuf);
2647 1482014 : if (filesize > 0) {
2648 4729 : result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2649 : }
2650 : }
2651 : #else
2652 : result = get_file_size_stat(sbuf);
2653 : #endif
2654 :
2655 1560581 : if (fsp && fsp->initial_allocation_size)
2656 2532 : result = MAX(result,fsp->initial_allocation_size);
2657 :
2658 1560581 : result = smb_roundup(handle->conn, result);
2659 :
2660 1708846 : out:
2661 1708846 : END_PROFILE(syscall_get_alloc_size);
2662 1708846 : return result;
2663 : }
2664 :
2665 171434 : static int vfswrap_unlinkat(vfs_handle_struct *handle,
2666 : struct files_struct *dirfsp,
2667 : const struct smb_filename *smb_fname,
2668 : int flags)
2669 : {
2670 171434 : int result = -1;
2671 :
2672 171434 : START_PROFILE(syscall_unlinkat);
2673 :
2674 171434 : SMB_ASSERT(!is_named_stream(smb_fname));
2675 :
2676 171434 : result = unlinkat(fsp_get_pathref_fd(dirfsp),
2677 171434 : smb_fname->base_name,
2678 : flags);
2679 :
2680 171434 : END_PROFILE(syscall_unlinkat);
2681 171434 : return result;
2682 : }
2683 :
2684 20554 : static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2685 : {
2686 0 : int result;
2687 :
2688 20554 : START_PROFILE(syscall_fchmod);
2689 :
2690 20554 : if (!fsp->fsp_flags.is_pathref) {
2691 20542 : result = fchmod(fsp_get_io_fd(fsp), mode);
2692 20542 : END_PROFILE(syscall_fchmod);
2693 20542 : return result;
2694 : }
2695 :
2696 12 : if (fsp->fsp_flags.have_proc_fds) {
2697 10 : int fd = fsp_get_pathref_fd(fsp);
2698 0 : struct sys_proc_fd_path_buf buf;
2699 :
2700 10 : result = chmod(sys_proc_fd_path(fd, &buf), mode);
2701 :
2702 10 : END_PROFILE(syscall_fchmod);
2703 10 : return result;
2704 : }
2705 :
2706 : /*
2707 : * This is no longer a handle based call.
2708 : */
2709 2 : result = chmod(fsp->fsp_name->base_name, mode);
2710 :
2711 2 : END_PROFILE(syscall_fchmod);
2712 2 : return result;
2713 : }
2714 :
2715 3392 : static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2716 : {
2717 : #ifdef HAVE_FCHOWN
2718 0 : int result;
2719 :
2720 3392 : START_PROFILE(syscall_fchown);
2721 3392 : if (!fsp->fsp_flags.is_pathref) {
2722 2992 : result = fchown(fsp_get_io_fd(fsp), uid, gid);
2723 2992 : END_PROFILE(syscall_fchown);
2724 2992 : return result;
2725 : }
2726 :
2727 400 : if (fsp->fsp_flags.have_proc_fds) {
2728 200 : int fd = fsp_get_pathref_fd(fsp);
2729 0 : struct sys_proc_fd_path_buf buf;
2730 :
2731 200 : result = chown(sys_proc_fd_path(fd, &buf), uid, gid);
2732 :
2733 200 : END_PROFILE(syscall_fchown);
2734 200 : return result;
2735 : }
2736 :
2737 : /*
2738 : * This is no longer a handle based call.
2739 : */
2740 200 : result = chown(fsp->fsp_name->base_name, uid, gid);
2741 200 : END_PROFILE(syscall_fchown);
2742 200 : return result;
2743 : #else
2744 : errno = ENOSYS;
2745 : return -1;
2746 : #endif
2747 : }
2748 :
2749 0 : static int vfswrap_lchown(vfs_handle_struct *handle,
2750 : const struct smb_filename *smb_fname,
2751 : uid_t uid,
2752 : gid_t gid)
2753 : {
2754 0 : int result;
2755 :
2756 0 : START_PROFILE(syscall_lchown);
2757 0 : result = lchown(smb_fname->base_name, uid, gid);
2758 0 : END_PROFILE(syscall_lchown);
2759 0 : return result;
2760 : }
2761 :
2762 1830744 : static int vfswrap_chdir(vfs_handle_struct *handle,
2763 : const struct smb_filename *smb_fname)
2764 : {
2765 4390 : int result;
2766 :
2767 1830744 : START_PROFILE(syscall_chdir);
2768 1830744 : result = chdir(smb_fname->base_name);
2769 1830744 : END_PROFILE(syscall_chdir);
2770 1830744 : return result;
2771 : }
2772 :
2773 105586 : static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
2774 : TALLOC_CTX *ctx)
2775 : {
2776 1566 : char *result;
2777 105586 : struct smb_filename *smb_fname = NULL;
2778 :
2779 105586 : START_PROFILE(syscall_getwd);
2780 105586 : result = sys_getwd();
2781 105586 : END_PROFILE(syscall_getwd);
2782 :
2783 105586 : if (result == NULL) {
2784 0 : return NULL;
2785 : }
2786 105586 : smb_fname = synthetic_smb_fname(ctx,
2787 : result,
2788 : NULL,
2789 : NULL,
2790 : 0,
2791 : 0);
2792 : /*
2793 : * sys_getwd() *always* returns malloced memory.
2794 : * We must free here to avoid leaks:
2795 : * BUG:https://bugzilla.samba.org/show_bug.cgi?id=13372
2796 : */
2797 105586 : SAFE_FREE(result);
2798 105586 : return smb_fname;
2799 : }
2800 :
2801 : /*********************************************************************
2802 : nsec timestamp resolution call. Convert down to whatever the underlying
2803 : system will support.
2804 : **********************************************************************/
2805 :
2806 11062 : static int vfswrap_fntimes(vfs_handle_struct *handle,
2807 : files_struct *fsp,
2808 : struct smb_file_time *ft)
2809 : {
2810 11062 : int result = -1;
2811 115 : struct timespec ts[2];
2812 11062 : struct timespec *times = NULL;
2813 :
2814 11062 : START_PROFILE(syscall_fntimes);
2815 :
2816 11062 : if (fsp_is_alternate_stream(fsp)) {
2817 0 : errno = ENOENT;
2818 0 : goto out;
2819 : }
2820 :
2821 11062 : if (ft != NULL) {
2822 11062 : if (is_omit_timespec(&ft->atime)) {
2823 10163 : ft->atime = fsp->fsp_name->st.st_ex_atime;
2824 : }
2825 :
2826 11062 : if (is_omit_timespec(&ft->mtime)) {
2827 3118 : ft->mtime = fsp->fsp_name->st.st_ex_mtime;
2828 : }
2829 :
2830 11062 : if (!is_omit_timespec(&ft->create_time)) {
2831 844 : set_create_timespec_ea(fsp,
2832 : ft->create_time);
2833 : }
2834 :
2835 11062 : if ((timespec_compare(&ft->atime,
2836 21263 : &fsp->fsp_name->st.st_ex_atime) == 0) &&
2837 10201 : (timespec_compare(&ft->mtime,
2838 10201 : &fsp->fsp_name->st.st_ex_mtime) == 0)) {
2839 3744 : result = 0;
2840 3744 : goto out;
2841 : }
2842 :
2843 7318 : ts[0] = ft->atime;
2844 7318 : ts[1] = ft->mtime;
2845 7318 : times = ts;
2846 : } else {
2847 0 : times = NULL;
2848 : }
2849 :
2850 7318 : if (!fsp->fsp_flags.is_pathref) {
2851 5085 : result = futimens(fsp_get_io_fd(fsp), times);
2852 5085 : goto out;
2853 : }
2854 :
2855 2233 : if (fsp->fsp_flags.have_proc_fds) {
2856 1148 : int fd = fsp_get_pathref_fd(fsp);
2857 1 : struct sys_proc_fd_path_buf buf;
2858 :
2859 1148 : result = utimensat(AT_FDCWD,
2860 1148 : sys_proc_fd_path(fd, &buf),
2861 : times,
2862 : 0);
2863 :
2864 1148 : goto out;
2865 : }
2866 :
2867 : /*
2868 : * The fd is a pathref (opened with O_PATH) and there isn't fd to
2869 : * path translation mechanism. Fallback to path based call.
2870 : */
2871 1085 : result = utimensat(AT_FDCWD, fsp->fsp_name->base_name, times, 0);
2872 :
2873 11062 : out:
2874 11062 : END_PROFILE(syscall_fntimes);
2875 :
2876 11062 : return result;
2877 : }
2878 :
2879 :
2880 : /*********************************************************************
2881 : A version of ftruncate that will write the space on disk if strict
2882 : allocate is set.
2883 : **********************************************************************/
2884 :
2885 0 : static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2886 : {
2887 0 : off_t space_to_write;
2888 0 : uint64_t space_avail;
2889 0 : uint64_t bsize,dfree,dsize;
2890 0 : int ret;
2891 0 : NTSTATUS status;
2892 0 : SMB_STRUCT_STAT *pst;
2893 0 : bool ok;
2894 :
2895 0 : ok = vfs_valid_pwrite_range(len, 0);
2896 0 : if (!ok) {
2897 0 : errno = EINVAL;
2898 0 : return -1;
2899 : }
2900 :
2901 0 : status = vfs_stat_fsp(fsp);
2902 0 : if (!NT_STATUS_IS_OK(status)) {
2903 0 : return -1;
2904 : }
2905 0 : pst = &fsp->fsp_name->st;
2906 :
2907 : #ifdef S_ISFIFO
2908 0 : if (S_ISFIFO(pst->st_ex_mode))
2909 0 : return 0;
2910 : #endif
2911 :
2912 0 : if (pst->st_ex_size == len)
2913 0 : return 0;
2914 :
2915 : /* Shrink - just ftruncate. */
2916 0 : if (pst->st_ex_size > len)
2917 0 : return ftruncate(fsp_get_io_fd(fsp), len);
2918 :
2919 0 : space_to_write = len - pst->st_ex_size;
2920 :
2921 : /* for allocation try fallocate first. This can fail on some
2922 : platforms e.g. when the filesystem doesn't support it and no
2923 : emulation is being done by the libc (like on AIX with JFS1). In that
2924 : case we do our own emulation. fallocate implementations can
2925 : return ENOTSUP or EINVAL in cases like that. */
2926 0 : ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
2927 0 : if (ret == -1 && errno == ENOSPC) {
2928 0 : return -1;
2929 : }
2930 0 : if (ret == 0) {
2931 0 : return 0;
2932 : }
2933 0 : DBG_DEBUG("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
2934 : "error %d. Falling back to slow manual allocation\n", errno);
2935 :
2936 : /* available disk space is enough or not? */
2937 0 : space_avail =
2938 0 : get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
2939 : /* space_avail is 1k blocks */
2940 0 : if (space_avail == (uint64_t)-1 ||
2941 0 : ((uint64_t)space_to_write/1024 > space_avail) ) {
2942 0 : errno = ENOSPC;
2943 0 : return -1;
2944 : }
2945 :
2946 : /* Write out the real space on disk. */
2947 0 : ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
2948 0 : if (ret != 0) {
2949 0 : return -1;
2950 : }
2951 :
2952 0 : return 0;
2953 : }
2954 :
2955 1139 : static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2956 : {
2957 1139 : int result = -1;
2958 55 : SMB_STRUCT_STAT *pst;
2959 55 : NTSTATUS status;
2960 1139 : char c = 0;
2961 :
2962 1139 : START_PROFILE(syscall_ftruncate);
2963 :
2964 1139 : if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->fsp_flags.is_sparse) {
2965 0 : result = strict_allocate_ftruncate(handle, fsp, len);
2966 0 : END_PROFILE(syscall_ftruncate);
2967 0 : return result;
2968 : }
2969 :
2970 : /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
2971 : ftruncate if the system supports it. Then I discovered that
2972 : you can have some filesystems that support ftruncate
2973 : expansion and some that don't! On Linux fat can't do
2974 : ftruncate extend but ext2 can. */
2975 :
2976 1139 : result = ftruncate(fsp_get_io_fd(fsp), len);
2977 :
2978 : /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
2979 : extend a file with ftruncate. Provide alternate implementation
2980 : for this */
2981 :
2982 : /* Do an fstat to see if the file is longer than the requested
2983 : size in which case the ftruncate above should have
2984 : succeeded or shorter, in which case seek to len - 1 and
2985 : write 1 byte of zero */
2986 1139 : status = vfs_stat_fsp(fsp);
2987 1139 : if (!NT_STATUS_IS_OK(status)) {
2988 0 : goto done;
2989 : }
2990 :
2991 : /* We need to update the files_struct after successful ftruncate */
2992 1139 : if (result == 0) {
2993 1139 : goto done;
2994 : }
2995 :
2996 0 : pst = &fsp->fsp_name->st;
2997 :
2998 : #ifdef S_ISFIFO
2999 0 : if (S_ISFIFO(pst->st_ex_mode)) {
3000 0 : result = 0;
3001 0 : goto done;
3002 : }
3003 : #endif
3004 :
3005 0 : if (pst->st_ex_size == len) {
3006 0 : result = 0;
3007 0 : goto done;
3008 : }
3009 :
3010 0 : if (pst->st_ex_size > len) {
3011 : /* the ftruncate should have worked */
3012 0 : goto done;
3013 : }
3014 :
3015 0 : if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
3016 0 : goto done;
3017 : }
3018 :
3019 0 : result = 0;
3020 :
3021 1139 : done:
3022 :
3023 1139 : END_PROFILE(syscall_ftruncate);
3024 1084 : return result;
3025 : }
3026 :
3027 186 : static int vfswrap_fallocate(vfs_handle_struct *handle,
3028 : files_struct *fsp,
3029 : uint32_t mode,
3030 : off_t offset,
3031 : off_t len)
3032 : {
3033 0 : int result;
3034 :
3035 186 : START_PROFILE(syscall_fallocate);
3036 186 : if (mode == 0) {
3037 0 : result = sys_posix_fallocate(fsp_get_io_fd(fsp), offset, len);
3038 : /*
3039 : * posix_fallocate returns 0 on success, errno on error
3040 : * and doesn't set errno. Make it behave like fallocate()
3041 : * which returns -1, and sets errno on failure.
3042 : */
3043 0 : if (result != 0) {
3044 0 : errno = result;
3045 0 : result = -1;
3046 : }
3047 : } else {
3048 : /* sys_fallocate handles filtering of unsupported mode flags */
3049 186 : result = sys_fallocate(fsp_get_io_fd(fsp), mode, offset, len);
3050 : }
3051 186 : END_PROFILE(syscall_fallocate);
3052 186 : return result;
3053 : }
3054 :
3055 5680 : static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
3056 : {
3057 34 : bool result;
3058 :
3059 5680 : START_PROFILE(syscall_fcntl_lock);
3060 :
3061 5680 : if (fsp->fsp_flags.use_ofd_locks) {
3062 5680 : op = map_process_lock_to_ofd_lock(op);
3063 : }
3064 :
3065 5680 : result = fcntl_lock(fsp_get_io_fd(fsp), op, offset, count, type);
3066 5680 : END_PROFILE(syscall_fcntl_lock);
3067 5680 : return result;
3068 : }
3069 :
3070 0 : static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
3071 : files_struct *fsp,
3072 : uint32_t share_access,
3073 : uint32_t access_mask)
3074 : {
3075 0 : errno = ENOTSUP;
3076 0 : return -1;
3077 : }
3078 :
3079 382038 : static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
3080 : va_list cmd_arg)
3081 : {
3082 898 : void *argp;
3083 898 : va_list dup_cmd_arg;
3084 898 : int result;
3085 898 : int val;
3086 :
3087 382038 : START_PROFILE(syscall_fcntl);
3088 :
3089 382038 : va_copy(dup_cmd_arg, cmd_arg);
3090 :
3091 382038 : switch(cmd) {
3092 0 : case F_SETLK:
3093 : case F_SETLKW:
3094 : case F_GETLK:
3095 : #if defined(HAVE_OFD_LOCKS)
3096 : case F_OFD_SETLK:
3097 : case F_OFD_SETLKW:
3098 : case F_OFD_GETLK:
3099 : #endif
3100 : #if defined(HAVE_F_OWNER_EX)
3101 : case F_GETOWN_EX:
3102 : case F_SETOWN_EX:
3103 : #endif
3104 : #if defined(HAVE_RW_HINTS)
3105 : case F_GET_RW_HINT:
3106 : case F_SET_RW_HINT:
3107 : case F_GET_FILE_RW_HINT:
3108 : case F_SET_FILE_RW_HINT:
3109 : #endif
3110 0 : argp = va_arg(dup_cmd_arg, void *);
3111 0 : result = sys_fcntl_ptr(fsp_get_io_fd(fsp), cmd, argp);
3112 0 : break;
3113 382038 : default:
3114 382038 : val = va_arg(dup_cmd_arg, int);
3115 382038 : result = sys_fcntl_int(fsp_get_io_fd(fsp), cmd, val);
3116 : }
3117 :
3118 382038 : va_end(dup_cmd_arg);
3119 :
3120 382038 : END_PROFILE(syscall_fcntl);
3121 382038 : return result;
3122 : }
3123 :
3124 205789 : static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
3125 : {
3126 113 : bool result;
3127 205789 : int op = F_GETLK;
3128 :
3129 205789 : START_PROFILE(syscall_fcntl_getlock);
3130 :
3131 205789 : if (fsp->fsp_flags.use_ofd_locks) {
3132 205789 : op = map_process_lock_to_ofd_lock(op);
3133 : }
3134 :
3135 205789 : result = fcntl_getlock(fsp_get_io_fd(fsp), op, poffset, pcount, ptype, ppid);
3136 205789 : END_PROFILE(syscall_fcntl_getlock);
3137 205789 : return result;
3138 : }
3139 :
3140 12 : static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
3141 : int leasetype)
3142 : {
3143 12 : int result = -1;
3144 :
3145 12 : START_PROFILE(syscall_linux_setlease);
3146 :
3147 12 : SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3148 :
3149 : #ifdef HAVE_KERNEL_OPLOCKS_LINUX
3150 12 : result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
3151 : #else
3152 : errno = ENOSYS;
3153 : #endif
3154 12 : END_PROFILE(syscall_linux_setlease);
3155 12 : return result;
3156 : }
3157 :
3158 128 : static int vfswrap_symlinkat(vfs_handle_struct *handle,
3159 : const struct smb_filename *link_target,
3160 : struct files_struct *dirfsp,
3161 : const struct smb_filename *new_smb_fname)
3162 : {
3163 0 : int result;
3164 :
3165 128 : START_PROFILE(syscall_symlinkat);
3166 :
3167 128 : SMB_ASSERT(!is_named_stream(new_smb_fname));
3168 :
3169 128 : result = symlinkat(link_target->base_name,
3170 : fsp_get_pathref_fd(dirfsp),
3171 128 : new_smb_fname->base_name);
3172 128 : END_PROFILE(syscall_symlinkat);
3173 128 : return result;
3174 : }
3175 :
3176 74173 : static int vfswrap_readlinkat(vfs_handle_struct *handle,
3177 : const struct files_struct *dirfsp,
3178 : const struct smb_filename *smb_fname,
3179 : char *buf,
3180 : size_t bufsiz)
3181 : {
3182 0 : int result;
3183 :
3184 74173 : START_PROFILE(syscall_readlinkat);
3185 :
3186 74173 : SMB_ASSERT(!is_named_stream(smb_fname));
3187 :
3188 74173 : result = readlinkat(fsp_get_pathref_fd(dirfsp),
3189 74173 : smb_fname->base_name,
3190 : buf,
3191 : bufsiz);
3192 :
3193 74173 : END_PROFILE(syscall_readlinkat);
3194 74173 : return result;
3195 : }
3196 :
3197 43 : static int vfswrap_linkat(vfs_handle_struct *handle,
3198 : files_struct *srcfsp,
3199 : const struct smb_filename *old_smb_fname,
3200 : files_struct *dstfsp,
3201 : const struct smb_filename *new_smb_fname,
3202 : int flags)
3203 : {
3204 1 : int result;
3205 :
3206 43 : START_PROFILE(syscall_linkat);
3207 :
3208 43 : SMB_ASSERT(!is_named_stream(old_smb_fname));
3209 43 : SMB_ASSERT(!is_named_stream(new_smb_fname));
3210 :
3211 43 : result = linkat(fsp_get_pathref_fd(srcfsp),
3212 43 : old_smb_fname->base_name,
3213 : fsp_get_pathref_fd(dstfsp),
3214 43 : new_smb_fname->base_name,
3215 : flags);
3216 :
3217 43 : END_PROFILE(syscall_linkat);
3218 43 : return result;
3219 : }
3220 :
3221 2 : static int vfswrap_mknodat(vfs_handle_struct *handle,
3222 : files_struct *dirfsp,
3223 : const struct smb_filename *smb_fname,
3224 : mode_t mode,
3225 : SMB_DEV_T dev)
3226 : {
3227 0 : int result;
3228 :
3229 2 : START_PROFILE(syscall_mknodat);
3230 :
3231 2 : SMB_ASSERT(!is_named_stream(smb_fname));
3232 :
3233 2 : result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
3234 2 : smb_fname->base_name,
3235 : mode,
3236 : dev);
3237 :
3238 2 : END_PROFILE(syscall_mknodat);
3239 2 : return result;
3240 : }
3241 :
3242 3540198 : static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
3243 : TALLOC_CTX *ctx,
3244 : const struct smb_filename *smb_fname)
3245 : {
3246 12318 : char *result;
3247 3540198 : struct smb_filename *result_fname = NULL;
3248 :
3249 3540198 : START_PROFILE(syscall_realpath);
3250 3540198 : result = sys_realpath(smb_fname->base_name);
3251 3540198 : END_PROFILE(syscall_realpath);
3252 3540198 : if (result) {
3253 3540140 : result_fname = synthetic_smb_fname(ctx,
3254 : result,
3255 : NULL,
3256 : NULL,
3257 : 0,
3258 : 0);
3259 3540140 : SAFE_FREE(result);
3260 : }
3261 3540198 : return result_fname;
3262 : }
3263 :
3264 0 : static int vfswrap_fchflags(vfs_handle_struct *handle,
3265 : struct files_struct *fsp,
3266 : unsigned int flags)
3267 : {
3268 : #ifdef HAVE_FCHFLAGS
3269 : int fd = fsp_get_pathref_fd(fsp);
3270 :
3271 : SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3272 :
3273 : if (!fsp->fsp_flags.is_pathref) {
3274 : return fchflags(fd, flags);
3275 : }
3276 :
3277 : if (fsp->fsp_flags.have_proc_fds) {
3278 : struct sys_proc_fd_path_buf buf;
3279 :
3280 : return chflags(sys_proc_fd_path(fd, &buf), flags);
3281 : }
3282 :
3283 : /*
3284 : * This is no longer a handle based call.
3285 : */
3286 : return chflags(fsp->fsp_name->base_name, flags);
3287 : #else
3288 0 : errno = ENOSYS;
3289 0 : return -1;
3290 : #endif
3291 : }
3292 :
3293 35213745 : static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
3294 : const SMB_STRUCT_STAT *sbuf)
3295 : {
3296 127469 : struct file_id key;
3297 :
3298 : /* the ZERO_STRUCT ensures padding doesn't break using the key as a
3299 : * blob */
3300 35213745 : ZERO_STRUCT(key);
3301 :
3302 35213745 : key.devid = sbuf->st_ex_dev;
3303 35213745 : key.inode = sbuf->st_ex_ino;
3304 : /* key.extid is unused by default. */
3305 :
3306 35213745 : return key;
3307 : }
3308 :
3309 923320 : static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
3310 : const SMB_STRUCT_STAT *psbuf)
3311 : {
3312 970 : uint64_t file_id;
3313 :
3314 923320 : if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
3315 921708 : return (uint64_t)psbuf->st_ex_ino;
3316 : }
3317 :
3318 : /* FileIDLow */
3319 1612 : file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
3320 :
3321 : /* FileIDHigh */
3322 1612 : file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
3323 :
3324 1612 : return file_id;
3325 : }
3326 :
3327 317065 : static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
3328 : struct files_struct *fsp,
3329 : TALLOC_CTX *mem_ctx,
3330 : unsigned int *pnum_streams,
3331 : struct stream_struct **pstreams)
3332 : {
3333 317065 : struct stream_struct *tmp_streams = NULL;
3334 317065 : unsigned int num_streams = *pnum_streams;
3335 317065 : struct stream_struct *streams = *pstreams;
3336 840 : NTSTATUS status;
3337 :
3338 317065 : SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3339 :
3340 317065 : if (fsp->fsp_flags.is_directory) {
3341 : /*
3342 : * No default streams on directories
3343 : */
3344 25508 : goto done;
3345 : }
3346 291557 : status = vfs_stat_fsp(fsp);
3347 291557 : if (!NT_STATUS_IS_OK(status)) {
3348 0 : return status;
3349 : }
3350 :
3351 291557 : if (num_streams + 1 < 1) {
3352 : /* Integer wrap. */
3353 0 : return NT_STATUS_INVALID_PARAMETER;
3354 : }
3355 :
3356 291557 : tmp_streams = talloc_realloc(mem_ctx,
3357 : streams,
3358 : struct stream_struct,
3359 : num_streams + 1);
3360 291557 : if (tmp_streams == NULL) {
3361 0 : return NT_STATUS_NO_MEMORY;
3362 : }
3363 291557 : tmp_streams[num_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3364 291557 : if (tmp_streams[num_streams].name == NULL) {
3365 0 : return NT_STATUS_NO_MEMORY;
3366 : }
3367 291557 : tmp_streams[num_streams].size = fsp->fsp_name->st.st_ex_size;
3368 291557 : tmp_streams[num_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(
3369 : handle->conn,
3370 : fsp,
3371 : &fsp->fsp_name->st);
3372 291557 : num_streams += 1;
3373 :
3374 291557 : *pnum_streams = num_streams;
3375 291557 : *pstreams = tmp_streams;
3376 317065 : done:
3377 317065 : return NT_STATUS_OK;
3378 : }
3379 :
3380 273565 : static NTSTATUS vfswrap_get_real_filename_at(
3381 : struct vfs_handle_struct *handle,
3382 : struct files_struct *dirfsp,
3383 : const char *name,
3384 : TALLOC_CTX *mem_ctx,
3385 : char **found_name)
3386 : {
3387 : /*
3388 : * Don't fall back to get_real_filename so callers can differentiate
3389 : * between a full directory scan and an actual case-insensitive stat.
3390 : */
3391 273565 : return NT_STATUS_NOT_SUPPORTED;
3392 : }
3393 :
3394 3907705 : static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
3395 : const struct files_struct *dirfsp,
3396 : const struct smb_filename *smb_fname)
3397 : {
3398 3907705 : return handle->conn->connectpath;
3399 : }
3400 :
3401 5807 : static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3402 : struct byte_range_lock *br_lck,
3403 : struct lock_struct *plock)
3404 : {
3405 5807 : SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3406 :
3407 : /* Note: blr is not used in the default implementation. */
3408 5807 : return brl_lock_windows_default(br_lck, plock);
3409 : }
3410 :
3411 2889 : static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3412 : struct byte_range_lock *br_lck,
3413 : const struct lock_struct *plock)
3414 : {
3415 2889 : SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3416 :
3417 2889 : return brl_unlock_windows_default(br_lck, plock);
3418 : }
3419 :
3420 204087 : static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3421 : files_struct *fsp,
3422 : struct lock_struct *plock)
3423 : {
3424 204087 : SMB_ASSERT(plock->lock_type == READ_LOCK ||
3425 : plock->lock_type == WRITE_LOCK);
3426 :
3427 204087 : return strict_lock_check_default(fsp, plock);
3428 : }
3429 :
3430 : /* NT ACL operations. */
3431 :
3432 421715 : static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3433 : files_struct *fsp,
3434 : uint32_t security_info,
3435 : TALLOC_CTX *mem_ctx,
3436 : struct security_descriptor **ppdesc)
3437 : {
3438 1655 : NTSTATUS result;
3439 :
3440 421715 : START_PROFILE(fget_nt_acl);
3441 :
3442 421715 : SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3443 :
3444 421715 : result = posix_fget_nt_acl(fsp, security_info,
3445 : mem_ctx, ppdesc);
3446 421715 : END_PROFILE(fget_nt_acl);
3447 421715 : return result;
3448 : }
3449 :
3450 157951 : static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3451 : {
3452 452 : NTSTATUS result;
3453 :
3454 157951 : START_PROFILE(fset_nt_acl);
3455 :
3456 157951 : SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3457 :
3458 157951 : result = set_nt_acl(fsp, security_info_sent, psd);
3459 157951 : END_PROFILE(fset_nt_acl);
3460 157951 : return result;
3461 : }
3462 :
3463 0 : static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
3464 : struct smb_filename *file,
3465 : struct security_acl *sacl,
3466 : uint32_t access_requested,
3467 : uint32_t access_denied)
3468 : {
3469 0 : return NT_STATUS_OK; /* Nothing to do here ... */
3470 : }
3471 :
3472 148861 : static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3473 : files_struct *fsp,
3474 : SMB_ACL_TYPE_T type,
3475 : TALLOC_CTX *mem_ctx)
3476 : {
3477 148861 : SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3478 :
3479 148861 : return sys_acl_get_fd(handle, fsp, type, mem_ctx);
3480 : }
3481 :
3482 1610 : static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
3483 : files_struct *fsp,
3484 : SMB_ACL_TYPE_T type,
3485 : SMB_ACL_T theacl)
3486 : {
3487 1610 : SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3488 :
3489 1610 : return sys_acl_set_fd(handle, fsp, type, theacl);
3490 : }
3491 :
3492 0 : static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
3493 : files_struct *fsp)
3494 : {
3495 0 : SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3496 :
3497 0 : return sys_acl_delete_def_fd(handle, fsp);
3498 : }
3499 :
3500 : /****************************************************************
3501 : Extended attribute operations.
3502 : *****************************************************************/
3503 :
3504 82300 : static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
3505 : struct files_struct *fsp,
3506 : const char *name,
3507 : void *value,
3508 : size_t size)
3509 : {
3510 82300 : int fd = fsp_get_pathref_fd(fsp);
3511 :
3512 82300 : SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3513 :
3514 82300 : if (!fsp->fsp_flags.is_pathref) {
3515 4161 : return fgetxattr(fd, name, value, size);
3516 : }
3517 :
3518 78139 : if (fsp->fsp_flags.have_proc_fds) {
3519 0 : struct sys_proc_fd_path_buf buf;
3520 :
3521 38355 : return getxattr(sys_proc_fd_path(fd, &buf), name, value, size);
3522 : }
3523 :
3524 : /*
3525 : * This is no longer a handle based call.
3526 : */
3527 39784 : return getxattr(fsp->fsp_name->base_name, name, value, size);
3528 : }
3529 :
3530 : struct vfswrap_getxattrat_state {
3531 : struct tevent_context *ev;
3532 : struct vfs_handle_struct *handle;
3533 : files_struct *dir_fsp;
3534 : const struct smb_filename *smb_fname;
3535 :
3536 : /*
3537 : * The following variables are talloced off "state" which is protected
3538 : * by a destructor and thus are guaranteed to be safe to be used in the
3539 : * job function in the worker thread.
3540 : */
3541 : char *name;
3542 : const char *xattr_name;
3543 : uint8_t *xattr_value;
3544 : struct security_unix_token *token;
3545 :
3546 : ssize_t xattr_size;
3547 : struct vfs_aio_state vfs_aio_state;
3548 : SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
3549 : };
3550 :
3551 0 : static int vfswrap_getxattrat_state_destructor(
3552 : struct vfswrap_getxattrat_state *state)
3553 : {
3554 0 : return -1;
3555 : }
3556 :
3557 : static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3558 : static void vfswrap_getxattrat_do_async(void *private_data);
3559 : static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3560 :
3561 10077 : static struct tevent_req *vfswrap_getxattrat_send(
3562 : TALLOC_CTX *mem_ctx,
3563 : struct tevent_context *ev,
3564 : struct vfs_handle_struct *handle,
3565 : files_struct *dir_fsp,
3566 : const struct smb_filename *smb_fname,
3567 : const char *xattr_name,
3568 : size_t alloc_hint)
3569 : {
3570 10077 : struct tevent_req *req = NULL;
3571 10077 : struct tevent_req *subreq = NULL;
3572 10077 : struct vfswrap_getxattrat_state *state = NULL;
3573 10077 : size_t max_threads = 0;
3574 10077 : bool have_per_thread_cwd = false;
3575 10077 : bool have_per_thread_creds = false;
3576 10077 : bool do_async = false;
3577 :
3578 10077 : SMB_ASSERT(!is_named_stream(smb_fname));
3579 :
3580 10077 : req = tevent_req_create(mem_ctx, &state,
3581 : struct vfswrap_getxattrat_state);
3582 10077 : if (req == NULL) {
3583 0 : return NULL;
3584 : }
3585 10077 : *state = (struct vfswrap_getxattrat_state) {
3586 : .ev = ev,
3587 : .handle = handle,
3588 : .dir_fsp = dir_fsp,
3589 : .smb_fname = smb_fname,
3590 : };
3591 :
3592 10077 : max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
3593 10077 : if (max_threads >= 1) {
3594 : /*
3595 : * We need a non sync threadpool!
3596 : */
3597 10077 : have_per_thread_cwd = per_thread_cwd_supported();
3598 : }
3599 : #ifdef HAVE_LINUX_THREAD_CREDENTIALS
3600 10077 : have_per_thread_creds = true;
3601 : #endif
3602 10077 : if (have_per_thread_cwd && have_per_thread_creds) {
3603 10077 : do_async = true;
3604 : }
3605 :
3606 10077 : SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
3607 : state->profile_bytes, 0);
3608 :
3609 10077 : if (fsp_get_pathref_fd(dir_fsp) == -1) {
3610 0 : DBG_ERR("Need a valid directory fd\n");
3611 0 : tevent_req_error(req, EINVAL);
3612 0 : return tevent_req_post(req, ev);
3613 : }
3614 :
3615 10077 : if (alloc_hint > 0) {
3616 10077 : state->xattr_value = talloc_zero_array(state,
3617 : uint8_t,
3618 : alloc_hint);
3619 10077 : if (tevent_req_nomem(state->xattr_value, req)) {
3620 0 : return tevent_req_post(req, ev);
3621 : }
3622 : }
3623 :
3624 10077 : if (!do_async) {
3625 0 : vfswrap_getxattrat_do_sync(req);
3626 0 : return tevent_req_post(req, ev);
3627 : }
3628 :
3629 : /*
3630 : * Now allocate all parameters from a memory context that won't go away
3631 : * no matter what. These parameters will get used in threads and we
3632 : * can't reliably cancel threads, so all buffers passed to the threads
3633 : * must not be freed before all referencing threads terminate.
3634 : */
3635 :
3636 10077 : state->name = talloc_strdup(state, smb_fname->base_name);
3637 10077 : if (tevent_req_nomem(state->name, req)) {
3638 0 : return tevent_req_post(req, ev);
3639 : }
3640 :
3641 10077 : state->xattr_name = talloc_strdup(state, xattr_name);
3642 10077 : if (tevent_req_nomem(state->xattr_name, req)) {
3643 0 : return tevent_req_post(req, ev);
3644 : }
3645 :
3646 : /*
3647 : * This is a hot codepath so at first glance one might think we should
3648 : * somehow optimize away the token allocation and do a
3649 : * talloc_reference() or similar black magic instead. But due to the
3650 : * talloc_stackframe pool per SMB2 request this should be a simple copy
3651 : * without a malloc in most cases.
3652 : */
3653 10077 : if (geteuid() == sec_initial_uid()) {
3654 10075 : state->token = root_unix_token(state);
3655 : } else {
3656 2 : state->token = copy_unix_token(
3657 : state,
3658 2 : dir_fsp->conn->session_info->unix_token);
3659 : }
3660 10077 : if (tevent_req_nomem(state->token, req)) {
3661 0 : return tevent_req_post(req, ev);
3662 : }
3663 :
3664 10077 : SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3665 :
3666 10077 : subreq = pthreadpool_tevent_job_send(
3667 : state,
3668 : ev,
3669 10077 : dir_fsp->conn->sconn->pool,
3670 : vfswrap_getxattrat_do_async,
3671 : state);
3672 10077 : if (tevent_req_nomem(subreq, req)) {
3673 0 : return tevent_req_post(req, ev);
3674 : }
3675 10077 : tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3676 :
3677 10077 : talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3678 :
3679 10077 : return req;
3680 : }
3681 :
3682 0 : static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3683 : {
3684 0 : struct vfswrap_getxattrat_state *state = tevent_req_data(
3685 : req, struct vfswrap_getxattrat_state);
3686 :
3687 0 : state->xattr_size = vfswrap_fgetxattr(state->handle,
3688 0 : state->smb_fname->fsp,
3689 : state->xattr_name,
3690 0 : state->xattr_value,
3691 0 : talloc_array_length(state->xattr_value));
3692 0 : if (state->xattr_size == -1) {
3693 0 : tevent_req_error(req, errno);
3694 0 : return;
3695 : }
3696 :
3697 0 : tevent_req_done(req);
3698 0 : return;
3699 : }
3700 :
3701 10077 : static void vfswrap_getxattrat_do_async(void *private_data)
3702 : {
3703 10077 : struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3704 : private_data, struct vfswrap_getxattrat_state);
3705 0 : struct timespec start_time;
3706 0 : struct timespec end_time;
3707 0 : int ret;
3708 :
3709 10077 : PROFILE_TIMESTAMP(&start_time);
3710 10077 : SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
3711 :
3712 : /*
3713 : * Here we simulate a getxattrat()
3714 : * call using fchdir();getxattr()
3715 : */
3716 :
3717 10077 : per_thread_cwd_activate();
3718 :
3719 : /* Become the correct credential on this thread. */
3720 10077 : ret = set_thread_credentials(state->token->uid,
3721 10077 : state->token->gid,
3722 10077 : (size_t)state->token->ngroups,
3723 10077 : state->token->groups);
3724 10077 : if (ret != 0) {
3725 0 : state->xattr_size = -1;
3726 0 : state->vfs_aio_state.error = errno;
3727 0 : goto end_profile;
3728 : }
3729 :
3730 20154 : state->xattr_size = vfswrap_fgetxattr(state->handle,
3731 10077 : state->smb_fname->fsp,
3732 : state->xattr_name,
3733 10077 : state->xattr_value,
3734 10077 : talloc_array_length(state->xattr_value));
3735 10077 : if (state->xattr_size == -1) {
3736 68 : state->vfs_aio_state.error = errno;
3737 : }
3738 :
3739 10009 : end_profile:
3740 10077 : PROFILE_TIMESTAMP(&end_time);
3741 10077 : state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3742 10077 : SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
3743 10077 : }
3744 :
3745 10077 : static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3746 : {
3747 10077 : struct tevent_req *req = tevent_req_callback_data(
3748 : subreq, struct tevent_req);
3749 10077 : struct vfswrap_getxattrat_state *state = tevent_req_data(
3750 : req, struct vfswrap_getxattrat_state);
3751 0 : int ret;
3752 0 : bool ok;
3753 :
3754 : /*
3755 : * Make sure we run as the user again
3756 : */
3757 10077 : ok = change_to_user_and_service_by_fsp(state->dir_fsp);
3758 10077 : SMB_ASSERT(ok);
3759 :
3760 10077 : ret = pthreadpool_tevent_job_recv(subreq);
3761 10077 : TALLOC_FREE(subreq);
3762 10077 : SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
3763 10077 : talloc_set_destructor(state, NULL);
3764 10077 : if (ret != 0) {
3765 0 : if (ret != EAGAIN) {
3766 0 : tevent_req_error(req, ret);
3767 0 : return;
3768 : }
3769 : /*
3770 : * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3771 : * means the lower level pthreadpool failed to create a new
3772 : * thread. Fallback to sync processing in that case to allow
3773 : * some progress for the client.
3774 : */
3775 0 : vfswrap_getxattrat_do_sync(req);
3776 0 : return;
3777 : }
3778 :
3779 10077 : if (state->xattr_size == -1) {
3780 68 : tevent_req_error(req, state->vfs_aio_state.error);
3781 68 : return;
3782 : }
3783 :
3784 10009 : if (state->xattr_value == NULL) {
3785 : /*
3786 : * The caller only wanted the size.
3787 : */
3788 0 : tevent_req_done(req);
3789 0 : return;
3790 : }
3791 :
3792 : /*
3793 : * shrink the buffer to the returned size.
3794 : * (can't fail). It means NULL if size is 0.
3795 : */
3796 10009 : state->xattr_value = talloc_realloc(state,
3797 : state->xattr_value,
3798 : uint8_t,
3799 : state->xattr_size);
3800 :
3801 10009 : tevent_req_done(req);
3802 : }
3803 :
3804 10077 : static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3805 : struct vfs_aio_state *aio_state,
3806 : TALLOC_CTX *mem_ctx,
3807 : uint8_t **xattr_value)
3808 : {
3809 10077 : struct vfswrap_getxattrat_state *state = tevent_req_data(
3810 : req, struct vfswrap_getxattrat_state);
3811 0 : ssize_t xattr_size;
3812 :
3813 10077 : if (tevent_req_is_unix_error(req, &aio_state->error)) {
3814 68 : tevent_req_received(req);
3815 68 : return -1;
3816 : }
3817 :
3818 10009 : *aio_state = state->vfs_aio_state;
3819 10009 : xattr_size = state->xattr_size;
3820 10009 : if (xattr_value != NULL) {
3821 10009 : *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3822 : }
3823 :
3824 10009 : tevent_req_received(req);
3825 10009 : return xattr_size;
3826 : }
3827 :
3828 16268 : static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3829 : {
3830 16268 : int fd = fsp_get_pathref_fd(fsp);
3831 :
3832 16268 : SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3833 :
3834 16268 : if (!fsp->fsp_flags.is_pathref) {
3835 694 : return flistxattr(fd, list, size);
3836 : }
3837 :
3838 15574 : if (fsp->fsp_flags.have_proc_fds) {
3839 0 : struct sys_proc_fd_path_buf buf;
3840 :
3841 7798 : return listxattr(sys_proc_fd_path(fd, &buf), list, size);
3842 : }
3843 :
3844 : /*
3845 : * This is no longer a handle based call.
3846 : */
3847 7776 : return listxattr(fsp->fsp_name->base_name, list, size);
3848 : }
3849 :
3850 12 : static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3851 : {
3852 12 : int fd = fsp_get_pathref_fd(fsp);
3853 :
3854 12 : SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3855 :
3856 12 : if (!fsp->fsp_flags.is_pathref) {
3857 0 : return fremovexattr(fd, name);
3858 : }
3859 :
3860 12 : if (fsp->fsp_flags.have_proc_fds) {
3861 0 : struct sys_proc_fd_path_buf buf;
3862 :
3863 6 : return removexattr(sys_proc_fd_path(fd, &buf), name);
3864 : }
3865 :
3866 : /*
3867 : * This is no longer a handle based call.
3868 : */
3869 6 : return removexattr(fsp->fsp_name->base_name, name);
3870 : }
3871 :
3872 11111 : static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3873 : {
3874 11111 : int fd = fsp_get_pathref_fd(fsp);
3875 :
3876 11111 : SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3877 :
3878 11111 : if (!fsp->fsp_flags.is_pathref) {
3879 10634 : return fsetxattr(fd, name, value, size, flags);
3880 : }
3881 :
3882 477 : if (fsp->fsp_flags.have_proc_fds) {
3883 0 : struct sys_proc_fd_path_buf buf;
3884 :
3885 239 : return setxattr(sys_proc_fd_path(fd, &buf),
3886 : name,
3887 : value,
3888 : size,
3889 : flags);
3890 : }
3891 :
3892 : /*
3893 : * This is no longer a handle based call.
3894 : */
3895 238 : return setxattr(fsp->fsp_name->base_name, name, value, size, flags);
3896 : }
3897 :
3898 77 : static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3899 : {
3900 77 : return false;
3901 : }
3902 :
3903 1476052 : static bool vfswrap_is_offline(struct connection_struct *conn,
3904 : const struct smb_filename *fname)
3905 : {
3906 2249 : NTSTATUS status;
3907 2249 : char *path;
3908 1476052 : bool offline = false;
3909 :
3910 1476052 : if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
3911 57076 : return false;
3912 : }
3913 :
3914 1418944 : if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
3915 : #if defined(ENOTSUP)
3916 1418944 : errno = ENOTSUP;
3917 : #endif
3918 1418944 : return false;
3919 : }
3920 :
3921 0 : status = get_full_smb_filename(talloc_tos(), fname, &path);
3922 0 : if (!NT_STATUS_IS_OK(status)) {
3923 0 : errno = map_errno_from_nt_status(status);
3924 0 : return false;
3925 : }
3926 :
3927 0 : offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
3928 :
3929 0 : TALLOC_FREE(path);
3930 :
3931 0 : return offline;
3932 : }
3933 :
3934 550 : static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
3935 : struct files_struct *fsp,
3936 : TALLOC_CTX *mem_ctx,
3937 : DATA_BLOB *cookie)
3938 : {
3939 550 : return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
3940 : }
3941 :
3942 168 : static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
3943 : struct files_struct *fsp,
3944 : const DATA_BLOB old_cookie,
3945 : TALLOC_CTX *mem_ctx,
3946 : DATA_BLOB *new_cookie)
3947 : {
3948 168 : return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
3949 : new_cookie);
3950 : }
3951 :
3952 158 : static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
3953 : struct smb_request *smb1req,
3954 : struct smbXsrv_open *op,
3955 : const DATA_BLOB old_cookie,
3956 : TALLOC_CTX *mem_ctx,
3957 : struct files_struct **fsp,
3958 : DATA_BLOB *new_cookie)
3959 : {
3960 158 : return vfs_default_durable_reconnect(handle->conn, smb1req, op,
3961 : old_cookie, mem_ctx,
3962 : fsp, new_cookie);
3963 : }
3964 :
3965 : static struct vfs_fn_pointers vfs_default_fns = {
3966 : /* Disk operations */
3967 :
3968 : .connect_fn = vfswrap_connect,
3969 : .disconnect_fn = vfswrap_disconnect,
3970 : .disk_free_fn = vfswrap_disk_free,
3971 : .get_quota_fn = vfswrap_get_quota,
3972 : .set_quota_fn = vfswrap_set_quota,
3973 : .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
3974 : .statvfs_fn = vfswrap_statvfs,
3975 : .fs_capabilities_fn = vfswrap_fs_capabilities,
3976 : .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
3977 : .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
3978 : .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
3979 : .snap_check_path_fn = vfswrap_snap_check_path,
3980 : .snap_create_fn = vfswrap_snap_create,
3981 : .snap_delete_fn = vfswrap_snap_delete,
3982 :
3983 : /* Directory operations */
3984 :
3985 : .fdopendir_fn = vfswrap_fdopendir,
3986 : .readdir_fn = vfswrap_readdir,
3987 : .freaddir_attr_fn = vfswrap_freaddir_attr,
3988 : .rewind_dir_fn = vfswrap_rewinddir,
3989 : .mkdirat_fn = vfswrap_mkdirat,
3990 : .closedir_fn = vfswrap_closedir,
3991 :
3992 : /* File operations */
3993 :
3994 : .openat_fn = vfswrap_openat,
3995 : .create_file_fn = vfswrap_create_file,
3996 : .close_fn = vfswrap_close,
3997 : .pread_fn = vfswrap_pread,
3998 : .pread_send_fn = vfswrap_pread_send,
3999 : .pread_recv_fn = vfswrap_pread_recv,
4000 : .pwrite_fn = vfswrap_pwrite,
4001 : .pwrite_send_fn = vfswrap_pwrite_send,
4002 : .pwrite_recv_fn = vfswrap_pwrite_recv,
4003 : .lseek_fn = vfswrap_lseek,
4004 : .sendfile_fn = vfswrap_sendfile,
4005 : .recvfile_fn = vfswrap_recvfile,
4006 : .renameat_fn = vfswrap_renameat,
4007 : .fsync_send_fn = vfswrap_fsync_send,
4008 : .fsync_recv_fn = vfswrap_fsync_recv,
4009 : .stat_fn = vfswrap_stat,
4010 : .fstat_fn = vfswrap_fstat,
4011 : .lstat_fn = vfswrap_lstat,
4012 : .fstatat_fn = vfswrap_fstatat,
4013 : .get_alloc_size_fn = vfswrap_get_alloc_size,
4014 : .unlinkat_fn = vfswrap_unlinkat,
4015 : .fchmod_fn = vfswrap_fchmod,
4016 : .fchown_fn = vfswrap_fchown,
4017 : .lchown_fn = vfswrap_lchown,
4018 : .chdir_fn = vfswrap_chdir,
4019 : .getwd_fn = vfswrap_getwd,
4020 : .fntimes_fn = vfswrap_fntimes,
4021 : .ftruncate_fn = vfswrap_ftruncate,
4022 : .fallocate_fn = vfswrap_fallocate,
4023 : .lock_fn = vfswrap_lock,
4024 : .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
4025 : .fcntl_fn = vfswrap_fcntl,
4026 : .linux_setlease_fn = vfswrap_linux_setlease,
4027 : .getlock_fn = vfswrap_getlock,
4028 : .symlinkat_fn = vfswrap_symlinkat,
4029 : .readlinkat_fn = vfswrap_readlinkat,
4030 : .linkat_fn = vfswrap_linkat,
4031 : .mknodat_fn = vfswrap_mknodat,
4032 : .realpath_fn = vfswrap_realpath,
4033 : .fchflags_fn = vfswrap_fchflags,
4034 : .file_id_create_fn = vfswrap_file_id_create,
4035 : .fs_file_id_fn = vfswrap_fs_file_id,
4036 : .fstreaminfo_fn = vfswrap_fstreaminfo,
4037 : .get_real_filename_at_fn = vfswrap_get_real_filename_at,
4038 : .connectpath_fn = vfswrap_connectpath,
4039 : .brl_lock_windows_fn = vfswrap_brl_lock_windows,
4040 : .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
4041 : .strict_lock_check_fn = vfswrap_strict_lock_check,
4042 : .translate_name_fn = vfswrap_translate_name,
4043 : .parent_pathname_fn = vfswrap_parent_pathname,
4044 : .fsctl_fn = vfswrap_fsctl,
4045 : .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
4046 : .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
4047 : .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
4048 : .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
4049 : .offload_read_send_fn = vfswrap_offload_read_send,
4050 : .offload_read_recv_fn = vfswrap_offload_read_recv,
4051 : .offload_write_send_fn = vfswrap_offload_write_send,
4052 : .offload_write_recv_fn = vfswrap_offload_write_recv,
4053 : .fget_compression_fn = vfswrap_fget_compression,
4054 : .set_compression_fn = vfswrap_set_compression,
4055 :
4056 : /* NT ACL operations. */
4057 :
4058 : .fget_nt_acl_fn = vfswrap_fget_nt_acl,
4059 : .fset_nt_acl_fn = vfswrap_fset_nt_acl,
4060 : .audit_file_fn = vfswrap_audit_file,
4061 :
4062 : /* POSIX ACL operations. */
4063 :
4064 : .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
4065 : .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
4066 : .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
4067 : .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
4068 :
4069 : /* EA operations. */
4070 : .getxattrat_send_fn = vfswrap_getxattrat_send,
4071 : .getxattrat_recv_fn = vfswrap_getxattrat_recv,
4072 : .fgetxattr_fn = vfswrap_fgetxattr,
4073 : .flistxattr_fn = vfswrap_flistxattr,
4074 : .fremovexattr_fn = vfswrap_fremovexattr,
4075 : .fsetxattr_fn = vfswrap_fsetxattr,
4076 :
4077 : /* aio operations */
4078 : .aio_force_fn = vfswrap_aio_force,
4079 :
4080 : /* durable handle operations */
4081 : .durable_cookie_fn = vfswrap_durable_cookie,
4082 : .durable_disconnect_fn = vfswrap_durable_disconnect,
4083 : .durable_reconnect_fn = vfswrap_durable_reconnect,
4084 : };
4085 :
4086 : static_decl_vfs;
4087 29610 : NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
4088 : {
4089 : /*
4090 : * Here we need to implement every call!
4091 : *
4092 : * As this is the end of the vfs module chain.
4093 : */
4094 29610 : smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
4095 29610 : return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
4096 : DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);
4097 : }
4098 :
4099 :
|