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