LCOV - code coverage report
Current view: top level - source3/modules - offload_token.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 94 153 61.4 %
Date: 2024-02-28 12:06:22 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Copyright (C) Ralph Boehme 2017
       5             : 
       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.
      10             : 
      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.
      15             : 
      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/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      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"
      31             : 
      32             : struct vfs_offload_ctx {
      33             :         bool initialized;
      34             :         struct db_context *db_ctx;
      35             : };
      36             : 
      37         350 : NTSTATUS vfs_offload_token_ctx_init(TALLOC_CTX *mem_ctx,
      38             :                                     struct vfs_offload_ctx **_ctx)
      39             : {
      40         350 :         struct vfs_offload_ctx *ctx = *_ctx;
      41             : 
      42         350 :         if (ctx != NULL) {
      43          93 :                 if (!ctx->initialized) {
      44           0 :                         return NT_STATUS_INTERNAL_ERROR;
      45             :                 }
      46          93 :                 return NT_STATUS_OK;
      47             :         }
      48             : 
      49         257 :         ctx = talloc_zero(mem_ctx, struct vfs_offload_ctx);
      50         257 :         if (ctx == NULL) {
      51           0 :                 return NT_STATUS_NO_MEMORY;
      52             :         }
      53             : 
      54         257 :         ctx->db_ctx = db_open_rbt(mem_ctx);
      55         257 :         if (ctx->db_ctx == NULL) {
      56           0 :                 TALLOC_FREE(ctx);
      57           0 :                 return NT_STATUS_INTERNAL_ERROR;
      58             :         }
      59             : 
      60         257 :         ctx->initialized = true;
      61         257 :         *_ctx = ctx;
      62         257 :         return NT_STATUS_OK;
      63             : }
      64             : 
      65             : struct fsp_token_link {
      66             :         struct vfs_offload_ctx *ctx;
      67             :         DATA_BLOB token_blob;
      68             : };
      69             : 
      70         350 : static int fsp_token_link_destructor(struct fsp_token_link *link)
      71             : {
      72         350 :         DATA_BLOB token_blob = link->token_blob;
      73         350 :         TDB_DATA key = make_tdb_data(token_blob.data, token_blob.length);
      74           0 :         NTSTATUS status;
      75             : 
      76         350 :         status = dbwrap_delete(link->ctx->db_ctx, key);
      77         350 :         if (!NT_STATUS_IS_OK(status)) {
      78           0 :                 DBG_ERR("dbwrap_delete failed: %s. Token:\n", nt_errstr(status));
      79           0 :                 dump_data(0, token_blob.data, token_blob.length);
      80           0 :                 return -1;
      81             :         }
      82             : 
      83         350 :         return 0;
      84             : }
      85             : 
      86             : struct vfs_offload_token_db_store_fsp_state {
      87             :         const struct files_struct *fsp;
      88             :         const DATA_BLOB *token_blob;
      89             :         NTSTATUS status;
      90             : };
      91             : 
      92         350 : static void vfs_offload_token_db_store_fsp_fn(
      93             :         struct db_record *rec, TDB_DATA value, void *private_data)
      94             : {
      95         350 :         struct vfs_offload_token_db_store_fsp_state *state = private_data;
      96         350 :         const struct files_struct *fsp = state->fsp;
      97         350 :         const DATA_BLOB *token_blob = state->token_blob;
      98         350 :         files_struct *token_db_fsp = NULL;
      99         350 :         void *ptr = NULL;
     100             : 
     101         350 :         if (value.dsize == 0) {
     102         341 :                 value = make_tdb_data((uint8_t *)&fsp, sizeof(files_struct *));
     103         341 :                 state->status = dbwrap_record_store(rec, value, 0);
     104         341 :                 return;
     105             :         }
     106             : 
     107           9 :         if (value.dsize != sizeof(ptr)) {
     108           0 :                 DBG_ERR("Bad db entry for token:\n");
     109           0 :                 dump_data(1, token_blob->data, token_blob->length);
     110           0 :                 state->status = NT_STATUS_INTERNAL_ERROR;
     111           0 :                 return;
     112             :         }
     113           9 :         memcpy(&ptr, value.dptr, value.dsize);
     114             : 
     115           9 :         token_db_fsp = talloc_get_type_abort(ptr, struct files_struct);
     116           9 :         if (token_db_fsp != fsp) {
     117           0 :                 DBG_ERR("token for fsp [%s] matches already known "
     118             :                         "but different fsp [%s]:\n",
     119             :                         fsp_str_dbg(fsp),
     120             :                         fsp_str_dbg(token_db_fsp));
     121           0 :                 dump_data(1, token_blob->data, token_blob->length);
     122           0 :                 state->status = NT_STATUS_INTERNAL_ERROR;
     123           0 :                 return;
     124             :         }
     125             : }
     126             : 
     127         350 : NTSTATUS vfs_offload_token_db_store_fsp(struct vfs_offload_ctx *ctx,
     128             :                                         const files_struct *fsp,
     129             :                                         const DATA_BLOB *token_blob)
     130             : {
     131         350 :         struct vfs_offload_token_db_store_fsp_state state = {
     132             :                 .fsp = fsp, .token_blob = token_blob,
     133             :         };
     134         350 :         struct fsp_token_link *link = NULL;
     135         350 :         TDB_DATA key = make_tdb_data(token_blob->data, token_blob->length);
     136           0 :         NTSTATUS status;
     137             : 
     138         350 :         link = talloc(fsp, struct fsp_token_link);
     139         350 :         if (link == NULL) {
     140           0 :                 return NT_STATUS_NO_MEMORY;
     141             :         }
     142         350 :         *link = (struct fsp_token_link) {
     143             :                 .ctx = ctx,
     144         350 :                 .token_blob = data_blob_dup_talloc(link, *token_blob),
     145             :         };
     146         350 :         if (link->token_blob.data == NULL) {
     147           0 :                 TALLOC_FREE(link);
     148           0 :                 return NT_STATUS_NO_MEMORY;
     149             :         }
     150             : 
     151         350 :         status = dbwrap_do_locked(
     152             :                 ctx->db_ctx,
     153             :                 key,
     154             :                 vfs_offload_token_db_store_fsp_fn,
     155             :                 &state);
     156         350 :         if (!NT_STATUS_IS_OK(status)) {
     157           0 :                 DBG_DEBUG("dbwrap_do_locked failed: %s\n",
     158             :                           nt_errstr(status));
     159           0 :                 TALLOC_FREE(link);
     160           0 :                 return status;
     161             :         }
     162         350 :         if (!NT_STATUS_IS_OK(state.status)) {
     163           0 :                 DBG_DEBUG("vfs_offload_token_db_store_fsp_fn failed: %s\n",
     164             :                           nt_errstr(status));
     165           0 :                 TALLOC_FREE(link);
     166           0 :                 return status;
     167             :         }
     168             : 
     169         350 :         talloc_set_destructor(link, fsp_token_link_destructor);
     170         350 :         return NT_STATUS_OK;
     171             : }
     172             : 
     173             : struct vfs_offload_token_db_fetch_fsp_state {
     174             :         struct files_struct **fsp;
     175             :         NTSTATUS status;
     176             : };
     177             : 
     178         328 : static void vfs_offload_token_db_fetch_fsp_fn(
     179             :         TDB_DATA key, TDB_DATA value, void *private_data)
     180             : {
     181         328 :         struct vfs_offload_token_db_fetch_fsp_state *state = private_data;
     182           0 :         void *ptr;
     183             : 
     184         328 :         if (value.dsize != sizeof(ptr)) {
     185           0 :                 DBG_ERR("Bad db entry for token:\n");
     186           0 :                 dump_data(1, key.dptr, key.dsize);
     187           0 :                 state->status = NT_STATUS_INTERNAL_ERROR;
     188           0 :                 return;
     189             :         }
     190             : 
     191         328 :         memcpy(&ptr, value.dptr, value.dsize);
     192         328 :         *state->fsp = talloc_get_type_abort(ptr, struct files_struct);
     193             : }
     194             : 
     195         346 : NTSTATUS vfs_offload_token_db_fetch_fsp(struct vfs_offload_ctx *ctx,
     196             :                                         const DATA_BLOB *token_blob,
     197             :                                         files_struct **fsp)
     198             : {
     199         346 :         struct vfs_offload_token_db_fetch_fsp_state state = { .fsp = fsp };
     200         346 :         TDB_DATA key = make_tdb_data(token_blob->data, token_blob->length);
     201           0 :         NTSTATUS status;
     202             : 
     203         346 :         status = dbwrap_parse_record(
     204             :                 ctx->db_ctx,
     205             :                 key,
     206             :                 vfs_offload_token_db_fetch_fsp_fn,
     207             :                 &state);
     208         346 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
     209          18 :                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
     210             :         }
     211         346 :         if (!NT_STATUS_IS_OK(status)) {
     212          18 :                 DBG_DEBUG("Unknown token:\n");
     213          18 :                 dump_data(10, token_blob->data, token_blob->length);
     214          18 :                 return status;
     215             :         }
     216         328 :         return state.status;
     217             : }
     218             : 
     219         310 : NTSTATUS vfs_offload_token_create_blob(TALLOC_CTX *mem_ctx,
     220             :                                        const files_struct *fsp,
     221             :                                        uint32_t fsctl,
     222             :                                        DATA_BLOB *token_blob)
     223             : {
     224           0 :         size_t len;
     225             : 
     226         310 :         switch (fsctl) {
     227           0 :         case FSCTL_DUP_EXTENTS_TO_FILE:
     228           0 :                 len = 20;
     229           0 :                 break;
     230         310 :         case FSCTL_SRV_REQUEST_RESUME_KEY:
     231         310 :                 len = 24;
     232         310 :                 break;
     233           0 :         default:
     234           0 :                 DBG_ERR("Invalid fsctl [%" PRIu32 "]\n", fsctl);
     235           0 :                 return NT_STATUS_NOT_SUPPORTED;
     236             :         }
     237             : 
     238         310 :         *token_blob = data_blob_talloc_zero(mem_ctx, len);
     239         310 :         if (token_blob->length == 0) {
     240           0 :                 return NT_STATUS_NO_MEMORY;
     241             :         }
     242             : 
     243             :         /* combine persistent and volatile handles for the resume key */
     244         310 :         SBVAL(token_blob->data,
     245             :               SMB_VFS_ODX_TOKEN_OFFSET_PFID,
     246             :               fsp->op->global->open_persistent_id);
     247         310 :         SBVAL(token_blob->data,
     248             :               SMB_VFS_ODX_TOKEN_OFFSET_VFID,
     249             :               fsp->op->global->open_volatile_id);
     250         310 :         SIVAL(token_blob->data,
     251             :               SMB_VFS_ODX_TOKEN_OFFSET_FSCTL,
     252             :               fsctl);
     253             : 
     254         310 :         return NT_STATUS_OK;
     255             : }
     256             : 
     257             : 
     258         320 : NTSTATUS vfs_offload_token_check_handles(uint32_t fsctl,
     259             :                                          files_struct *src_fsp,
     260             :                                          files_struct *dst_fsp)
     261             : {
     262           0 :         NTSTATUS status;
     263             : 
     264         320 :         if (src_fsp->vuid != dst_fsp->vuid) {
     265           0 :                 DBG_INFO("copy chunk handles not in the same session.\n");
     266           0 :                 return NT_STATUS_ACCESS_DENIED;
     267             :         }
     268             : 
     269         320 :         if (!NT_STATUS_IS_OK(src_fsp->op->status)) {
     270           0 :                 DBG_INFO("copy chunk source handle invalid: %s\n",
     271             :                          nt_errstr(src_fsp->op->status));
     272           0 :                 return NT_STATUS_ACCESS_DENIED;
     273             :         }
     274             : 
     275         320 :         if (!NT_STATUS_IS_OK(dst_fsp->op->status)) {
     276           0 :                 DBG_INFO("copy chunk destination handle invalid: %s\n",
     277             :                          nt_errstr(dst_fsp->op->status));
     278           0 :                 return NT_STATUS_ACCESS_DENIED;
     279             :         }
     280             : 
     281         320 :         if (src_fsp->fsp_flags.closing) {
     282           0 :                 DBG_INFO("copy chunk src handle with closing in progress.\n");
     283           0 :                 return NT_STATUS_ACCESS_DENIED;
     284             :         }
     285             : 
     286         320 :         if (dst_fsp->fsp_flags.closing) {
     287           0 :                 DBG_INFO("copy chunk dst handle with closing in progress.\n");
     288           0 :                 return NT_STATUS_ACCESS_DENIED;
     289             :         }
     290             : 
     291         320 :         if (src_fsp->fsp_flags.is_directory) {
     292           0 :                 DBG_INFO("copy chunk no read on src directory handle (%s).\n",
     293             :                          smb_fname_str_dbg(src_fsp->fsp_name));
     294           0 :                 return NT_STATUS_ACCESS_DENIED;
     295             :         }
     296             : 
     297         320 :         if (dst_fsp->fsp_flags.is_directory) {
     298           0 :                 DBG_INFO("copy chunk no read on dst directory handle (%s).\n",
     299             :                          smb_fname_str_dbg(dst_fsp->fsp_name));
     300           0 :                 return NT_STATUS_ACCESS_DENIED;
     301             :         }
     302             : 
     303         320 :         if (IS_IPC(src_fsp->conn) || IS_IPC(dst_fsp->conn)) {
     304           0 :                 DBG_INFO("copy chunk no access on IPC$ handle.\n");
     305           0 :                 return NT_STATUS_ACCESS_DENIED;
     306             :         }
     307             : 
     308         320 :         if (IS_PRINT(src_fsp->conn) || IS_PRINT(dst_fsp->conn)) {
     309           0 :                 DBG_INFO("copy chunk no access on PRINT handle.\n");
     310           0 :                 return NT_STATUS_ACCESS_DENIED;
     311             :         }
     312             : 
     313             :         /*
     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.
     319             :          *
     320             :          * A non writable dst handle also doesn't make sense for other fsctls.
     321             :          */
     322         320 :         status = check_any_access_fsp(dst_fsp, FILE_WRITE_DATA|FILE_APPEND_DATA);
     323         320 :         if (!NT_STATUS_IS_OK(status)) {
     324           9 :                 DBG_INFO("dest handle not writable (%s).\n",
     325             :                         smb_fname_str_dbg(dst_fsp->fsp_name));
     326           9 :                 return status;
     327             :         }
     328             :         /*
     329             :          * - The Open.GrantedAccess of the destination file does not include
     330             :          *   FILE_READ_DATA, and the CtlCode is FSCTL_SRV_COPYCHUNK.
     331             :          */
     332         311 :         if ((fsctl == FSCTL_SRV_COPYCHUNK) && !CHECK_READ_IOCTL(dst_fsp)) {
     333           9 :                 DBG_INFO("copy chunk no read on dest handle (%s).\n",
     334             :                          smb_fname_str_dbg(dst_fsp->fsp_name));
     335           9 :                 return NT_STATUS_ACCESS_DENIED;
     336             :         }
     337             :         /*
     338             :          * - The Open.GrantedAccess of the source file does not include
     339             :          *   FILE_READ_DATA access.
     340             :          */
     341         302 :         if (!CHECK_READ_SMB2(src_fsp)) {
     342           9 :                 DBG_INFO("src handle not readable (%s).\n",
     343             :                          smb_fname_str_dbg(src_fsp->fsp_name));
     344           9 :                 return NT_STATUS_ACCESS_DENIED;
     345             :         }
     346             : 
     347         293 :         return NT_STATUS_OK;
     348             : }

Generated by: LCOV version 1.14