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