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