2 Unix SMB/CIFS implementation.
4 Copyright (C) Ralph Boehme 2017
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "smbd/smbd.h"
22 #include "smbd/globals.h"
23 #include "../libcli/security/security.h"
24 #include "dbwrap/dbwrap.h"
25 #include "dbwrap/dbwrap_rbt.h"
26 #include "dbwrap/dbwrap_open.h"
27 #include "../lib/util/util_tdb.h"
28 #include "librpc/gen_ndr/ndr_ioctl.h"
29 #include "librpc/gen_ndr/ioctl.h"
30 #include "offload_token.h"
32 struct vfs_offload_ctx
{
34 struct db_context
*db_ctx
;
37 NTSTATUS
vfs_offload_token_ctx_init(TALLOC_CTX
*mem_ctx
,
38 struct vfs_offload_ctx
**_ctx
)
40 struct vfs_offload_ctx
*ctx
= *_ctx
;
43 if (!ctx
->initialized
) {
44 return NT_STATUS_INTERNAL_ERROR
;
49 ctx
= talloc_zero(mem_ctx
, struct vfs_offload_ctx
);
51 return NT_STATUS_NO_MEMORY
;
54 ctx
->db_ctx
= db_open_rbt(mem_ctx
);
55 if (ctx
->db_ctx
== NULL
) {
57 return NT_STATUS_INTERNAL_ERROR
;
60 ctx
->initialized
= true;
65 struct fsp_token_link
{
66 struct vfs_offload_ctx
*ctx
;
70 static int fsp_token_link_destructor(struct fsp_token_link
*link
)
72 DATA_BLOB token_blob
= link
->token_blob
;
73 TDB_DATA key
= make_tdb_data(token_blob
.data
, token_blob
.length
);
76 status
= dbwrap_delete(link
->ctx
->db_ctx
, key
);
77 if (!NT_STATUS_IS_OK(status
)) {
78 DBG_ERR("dbwrap_delete failed: %s. Token:\n", nt_errstr(status
));
79 dump_data(0, token_blob
.data
, token_blob
.length
);
86 struct vfs_offload_token_db_store_fsp_state
{
87 const struct files_struct
*fsp
;
88 const DATA_BLOB
*token_blob
;
92 static void vfs_offload_token_db_store_fsp_fn(
93 struct db_record
*rec
, TDB_DATA value
, void *private_data
)
95 struct vfs_offload_token_db_store_fsp_state
*state
= private_data
;
96 const struct files_struct
*fsp
= state
->fsp
;
97 const DATA_BLOB
*token_blob
= state
->token_blob
;
98 files_struct
*token_db_fsp
= NULL
;
101 if (value
.dsize
== 0) {
102 value
= make_tdb_data((uint8_t *)&fsp
, sizeof(files_struct
*));
103 state
->status
= dbwrap_record_store(rec
, value
, 0);
107 if (value
.dsize
!= sizeof(ptr
)) {
108 DBG_ERR("Bad db entry for token:\n");
109 dump_data(1, token_blob
->data
, token_blob
->length
);
110 state
->status
= NT_STATUS_INTERNAL_ERROR
;
113 memcpy(&ptr
, value
.dptr
, value
.dsize
);
115 token_db_fsp
= talloc_get_type_abort(ptr
, struct files_struct
);
116 if (token_db_fsp
!= fsp
) {
117 DBG_ERR("token for fsp [%s] matches already known "
118 "but different fsp [%s]:\n",
120 fsp_str_dbg(token_db_fsp
));
121 dump_data(1, token_blob
->data
, token_blob
->length
);
122 state
->status
= NT_STATUS_INTERNAL_ERROR
;
127 NTSTATUS
vfs_offload_token_db_store_fsp(struct vfs_offload_ctx
*ctx
,
128 const files_struct
*fsp
,
129 const DATA_BLOB
*token_blob
)
131 struct vfs_offload_token_db_store_fsp_state state
= {
132 .fsp
= fsp
, .token_blob
= token_blob
,
134 struct fsp_token_link
*link
= NULL
;
135 TDB_DATA key
= make_tdb_data(token_blob
->data
, token_blob
->length
);
138 link
= talloc(fsp
, struct fsp_token_link
);
140 return NT_STATUS_NO_MEMORY
;
142 *link
= (struct fsp_token_link
) {
144 .token_blob
= data_blob_dup_talloc(link
, *token_blob
),
146 if (link
->token_blob
.data
== NULL
) {
148 return NT_STATUS_NO_MEMORY
;
151 status
= dbwrap_do_locked(
154 vfs_offload_token_db_store_fsp_fn
,
156 if (!NT_STATUS_IS_OK(status
)) {
157 DBG_DEBUG("dbwrap_do_locked failed: %s\n",
162 if (!NT_STATUS_IS_OK(state
.status
)) {
163 DBG_DEBUG("vfs_offload_token_db_store_fsp_fn failed: %s\n",
169 talloc_set_destructor(link
, fsp_token_link_destructor
);
173 struct vfs_offload_token_db_fetch_fsp_state
{
174 struct files_struct
**fsp
;
178 static void vfs_offload_token_db_fetch_fsp_fn(
179 TDB_DATA key
, TDB_DATA value
, void *private_data
)
181 struct vfs_offload_token_db_fetch_fsp_state
*state
= private_data
;
184 if (value
.dsize
!= sizeof(ptr
)) {
185 DBG_ERR("Bad db entry for token:\n");
186 dump_data(1, key
.dptr
, key
.dsize
);
187 state
->status
= NT_STATUS_INTERNAL_ERROR
;
191 memcpy(&ptr
, value
.dptr
, value
.dsize
);
192 *state
->fsp
= talloc_get_type_abort(ptr
, struct files_struct
);
195 NTSTATUS
vfs_offload_token_db_fetch_fsp(struct vfs_offload_ctx
*ctx
,
196 const DATA_BLOB
*token_blob
,
199 struct vfs_offload_token_db_fetch_fsp_state state
= { .fsp
= fsp
};
200 TDB_DATA key
= make_tdb_data(token_blob
->data
, token_blob
->length
);
203 status
= dbwrap_parse_record(
206 vfs_offload_token_db_fetch_fsp_fn
,
208 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
209 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
211 if (!NT_STATUS_IS_OK(status
)) {
212 DBG_DEBUG("Unknown token:\n");
213 dump_data(10, token_blob
->data
, token_blob
->length
);
219 NTSTATUS
vfs_offload_token_create_blob(TALLOC_CTX
*mem_ctx
,
220 const files_struct
*fsp
,
222 DATA_BLOB
*token_blob
)
227 case FSCTL_DUP_EXTENTS_TO_FILE
:
230 case FSCTL_SRV_REQUEST_RESUME_KEY
:
234 DBG_ERR("Invalid fsctl [%" PRIu32
"]\n", fsctl
);
235 return NT_STATUS_NOT_SUPPORTED
;
238 *token_blob
= data_blob_talloc_zero(mem_ctx
, len
);
239 if (token_blob
->length
== 0) {
240 return NT_STATUS_NO_MEMORY
;
243 /* combine persistent and volatile handles for the resume key */
244 SBVAL(token_blob
->data
,
245 SMB_VFS_ODX_TOKEN_OFFSET_PFID
,
246 fsp
->op
->global
->open_persistent_id
);
247 SBVAL(token_blob
->data
,
248 SMB_VFS_ODX_TOKEN_OFFSET_VFID
,
249 fsp
->op
->global
->open_volatile_id
);
250 SIVAL(token_blob
->data
,
251 SMB_VFS_ODX_TOKEN_OFFSET_FSCTL
,
258 NTSTATUS
vfs_offload_token_check_handles(uint32_t fsctl
,
259 files_struct
*src_fsp
,
260 files_struct
*dst_fsp
)
264 if (src_fsp
->vuid
!= dst_fsp
->vuid
) {
265 DBG_INFO("copy chunk handles not in the same session.\n");
266 return NT_STATUS_ACCESS_DENIED
;
269 if (!NT_STATUS_IS_OK(src_fsp
->op
->status
)) {
270 DBG_INFO("copy chunk source handle invalid: %s\n",
271 nt_errstr(src_fsp
->op
->status
));
272 return NT_STATUS_ACCESS_DENIED
;
275 if (!NT_STATUS_IS_OK(dst_fsp
->op
->status
)) {
276 DBG_INFO("copy chunk destination handle invalid: %s\n",
277 nt_errstr(dst_fsp
->op
->status
));
278 return NT_STATUS_ACCESS_DENIED
;
281 if (src_fsp
->fsp_flags
.closing
) {
282 DBG_INFO("copy chunk src handle with closing in progress.\n");
283 return NT_STATUS_ACCESS_DENIED
;
286 if (dst_fsp
->fsp_flags
.closing
) {
287 DBG_INFO("copy chunk dst handle with closing in progress.\n");
288 return NT_STATUS_ACCESS_DENIED
;
291 if (src_fsp
->fsp_flags
.is_directory
) {
292 DBG_INFO("copy chunk no read on src directory handle (%s).\n",
293 smb_fname_str_dbg(src_fsp
->fsp_name
));
294 return NT_STATUS_ACCESS_DENIED
;
297 if (dst_fsp
->fsp_flags
.is_directory
) {
298 DBG_INFO("copy chunk no read on dst directory handle (%s).\n",
299 smb_fname_str_dbg(dst_fsp
->fsp_name
));
300 return NT_STATUS_ACCESS_DENIED
;
303 if (IS_IPC(src_fsp
->conn
) || IS_IPC(dst_fsp
->conn
)) {
304 DBG_INFO("copy chunk no access on IPC$ handle.\n");
305 return NT_STATUS_ACCESS_DENIED
;
308 if (IS_PRINT(src_fsp
->conn
) || IS_PRINT(dst_fsp
->conn
)) {
309 DBG_INFO("copy chunk no access on PRINT handle.\n");
310 return NT_STATUS_ACCESS_DENIED
;
314 * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
315 * The server MUST fail the request with STATUS_ACCESS_DENIED if any of
316 * the following are true:
317 * - The Open.GrantedAccess of the destination file does not include
318 * FILE_WRITE_DATA or FILE_APPEND_DATA.
320 * A non writable dst handle also doesn't make sense for other fsctls.
322 status
= check_any_access_fsp(dst_fsp
, FILE_WRITE_DATA
|FILE_APPEND_DATA
);
323 if (!NT_STATUS_IS_OK(status
)) {
324 DBG_INFO("dest handle not writable (%s).\n",
325 smb_fname_str_dbg(dst_fsp
->fsp_name
));
329 * - The Open.GrantedAccess of the destination file does not include
330 * FILE_READ_DATA, and the CtlCode is FSCTL_SRV_COPYCHUNK.
332 if ((fsctl
== FSCTL_SRV_COPYCHUNK
) && !CHECK_READ_IOCTL(dst_fsp
)) {
333 DBG_INFO("copy chunk no read on dest handle (%s).\n",
334 smb_fname_str_dbg(dst_fsp
->fsp_name
));
335 return NT_STATUS_ACCESS_DENIED
;
338 * - The Open.GrantedAccess of the source file does not include
339 * FILE_READ_DATA access.
341 if (!CHECK_READ_SMB2(src_fsp
)) {
342 DBG_INFO("src handle not readable (%s).\n",
343 smb_fname_str_dbg(src_fsp
->fsp_name
));
344 return NT_STATUS_ACCESS_DENIED
;