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