LCOV - code coverage report
Current view: top level - source3/modules - offload_token.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 94 153 61.4 %
Date: 2024-04-21 15:09:00 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         320 : NTSTATUS vfs_offload_token_ctx_init(TALLOC_CTX *mem_ctx,
      38             :                                     struct vfs_offload_ctx **_ctx)
      39             : {
      40         320 :         struct vfs_offload_ctx *ctx = *_ctx;
      41             : 
      42         320 :         if (ctx != NULL) {
      43          88 :                 if (!ctx->initialized) {
      44           0 :                         return NT_STATUS_INTERNAL_ERROR;
      45             :                 }
      46          88 :                 return NT_STATUS_OK;
      47             :         }
      48             : 
      49         232 :         ctx = talloc_zero(mem_ctx, struct vfs_offload_ctx);
      50         232 :         if (ctx == NULL) {
      51           0 :                 return NT_STATUS_NO_MEMORY;
      52             :         }
      53             : 
      54         232 :         ctx->db_ctx = db_open_rbt(mem_ctx);
      55         232 :         if (ctx->db_ctx == NULL) {
      56           0 :                 TALLOC_FREE(ctx);
      57           0 :                 return NT_STATUS_INTERNAL_ERROR;
      58             :         }
      59             : 
      60         232 :         ctx->initialized = true;
      61         232 :         *_ctx = ctx;
      62         232 :         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         320 : static int fsp_token_link_destructor(struct fsp_token_link *link)
      71             : {
      72         320 :         DATA_BLOB token_blob = link->token_blob;
      73         320 :         TDB_DATA key = make_tdb_data(token_blob.data, token_blob.length);
      74           0 :         NTSTATUS status;
      75             : 
      76         320 :         status = dbwrap_delete(link->ctx->db_ctx, key);
      77         320 :         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         320 :         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         320 : static void vfs_offload_token_db_store_fsp_fn(
      93             :         struct db_record *rec, TDB_DATA value, void *private_data)
      94             : {
      95         320 :         struct vfs_offload_token_db_store_fsp_state *state = private_data;
      96         320 :         const struct files_struct *fsp = state->fsp;
      97         320 :         const DATA_BLOB *token_blob = state->token_blob;
      98         320 :         files_struct *token_db_fsp = NULL;
      99         320 :         void *ptr = NULL;
     100             : 
     101         320 :         if (value.dsize == 0) {
     102         312 :                 value = make_tdb_data((uint8_t *)&fsp, sizeof(files_struct *));
     103         312 :                 state->status = dbwrap_record_store(rec, value, 0);
     104         312 :                 return;
     105             :         }
     106             : 
     107           8 :         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           8 :         memcpy(&ptr, value.dptr, value.dsize);
     114             : 
     115           8 :         token_db_fsp = talloc_get_type_abort(ptr, struct files_struct);
     116           8 :         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         320 : 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         320 :         struct vfs_offload_token_db_store_fsp_state state = {
     132             :                 .fsp = fsp, .token_blob = token_blob,
     133             :         };
     134         320 :         struct fsp_token_link *link = NULL;
     135         320 :         TDB_DATA key = make_tdb_data(token_blob->data, token_blob->length);
     136           0 :         NTSTATUS status;
     137             : 
     138         320 :         link = talloc(fsp, struct fsp_token_link);
     139         320 :         if (link == NULL) {
     140           0 :                 return NT_STATUS_NO_MEMORY;
     141             :         }
     142         320 :         *link = (struct fsp_token_link) {
     143             :                 .ctx = ctx,
     144         320 :                 .token_blob = data_blob_dup_talloc(link, *token_blob),
     145             :         };
     146         320 :         if (link->token_blob.data == NULL) {
     147           0 :                 TALLOC_FREE(link);
     148           0 :                 return NT_STATUS_NO_MEMORY;
     149             :         }
     150             : 
     151         320 :         status = dbwrap_do_locked(
     152             :                 ctx->db_ctx,
     153             :                 key,
     154             :                 vfs_offload_token_db_store_fsp_fn,
     155             :                 &state);
     156         320 :         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         320 :         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         320 :         talloc_set_destructor(link, fsp_token_link_destructor);
     170         320 :         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         296 : static void vfs_offload_token_db_fetch_fsp_fn(
     179             :         TDB_DATA key, TDB_DATA value, void *private_data)
     180             : {
     181         296 :         struct vfs_offload_token_db_fetch_fsp_state *state = private_data;
     182           0 :         void *ptr;
     183             : 
     184         296 :         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         296 :         memcpy(&ptr, value.dptr, value.dsize);
     192         296 :         *state->fsp = talloc_get_type_abort(ptr, struct files_struct);
     193             : }
     194             : 
     195         312 : NTSTATUS vfs_offload_token_db_fetch_fsp(struct vfs_offload_ctx *ctx,
     196             :                                         const DATA_BLOB *token_blob,
     197             :                                         files_struct **fsp)
     198             : {
     199         312 :         struct vfs_offload_token_db_fetch_fsp_state state = { .fsp = fsp };
     200         312 :         TDB_DATA key = make_tdb_data(token_blob->data, token_blob->length);
     201           0 :         NTSTATUS status;
     202             : 
     203         312 :         status = dbwrap_parse_record(
     204             :                 ctx->db_ctx,
     205             :                 key,
     206             :                 vfs_offload_token_db_fetch_fsp_fn,
     207             :                 &state);
     208         312 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
     209          16 :                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
     210             :         }
     211         312 :         if (!NT_STATUS_IS_OK(status)) {
     212          16 :                 DBG_DEBUG("Unknown token:\n");
     213          16 :                 dump_data(10, token_blob->data, token_blob->length);
     214          16 :                 return status;
     215             :         }
     216         296 :         return state.status;
     217             : }
     218             : 
     219         280 : 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         280 :         switch (fsctl) {
     227           0 :         case FSCTL_DUP_EXTENTS_TO_FILE:
     228           0 :                 len = 20;
     229           0 :                 break;
     230         280 :         case FSCTL_SRV_REQUEST_RESUME_KEY:
     231         280 :                 len = 24;
     232         280 :                 break;
     233           0 :         default:
     234           0 :                 DBG_ERR("Invalid fsctl [%" PRIu32 "]\n", fsctl);
     235           0 :                 return NT_STATUS_NOT_SUPPORTED;
     236             :         }
     237             : 
     238         280 :         *token_blob = data_blob_talloc_zero(mem_ctx, len);
     239         280 :         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         280 :         SBVAL(token_blob->data,
     245             :               SMB_VFS_ODX_TOKEN_OFFSET_PFID,
     246             :               fsp->op->global->open_persistent_id);
     247         280 :         SBVAL(token_blob->data,
     248             :               SMB_VFS_ODX_TOKEN_OFFSET_VFID,
     249             :               fsp->op->global->open_volatile_id);
     250         280 :         SIVAL(token_blob->data,
     251             :               SMB_VFS_ODX_TOKEN_OFFSET_FSCTL,
     252             :               fsctl);
     253             : 
     254         280 :         return NT_STATUS_OK;
     255             : }
     256             : 
     257             : 
     258         288 : 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         288 :         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         288 :         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         288 :         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         288 :         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         288 :         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         288 :         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         288 :         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         288 :         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         288 :         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         288 :         status = check_any_access_fsp(dst_fsp, FILE_WRITE_DATA|FILE_APPEND_DATA);
     323         288 :         if (!NT_STATUS_IS_OK(status)) {
     324           8 :                 DBG_INFO("dest handle not writable (%s).\n",
     325             :                         smb_fname_str_dbg(dst_fsp->fsp_name));
     326           8 :                 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         280 :         if ((fsctl == FSCTL_SRV_COPYCHUNK) && !CHECK_READ_IOCTL(dst_fsp)) {
     333           8 :                 DBG_INFO("copy chunk no read on dest handle (%s).\n",
     334             :                          smb_fname_str_dbg(dst_fsp->fsp_name));
     335           8 :                 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         272 :         if (!CHECK_READ_SMB2(src_fsp)) {
     342           8 :                 DBG_INFO("src handle not readable (%s).\n",
     343             :                          smb_fname_str_dbg(src_fsp->fsp_name));
     344           8 :                 return NT_STATUS_ACCESS_DENIED;
     345             :         }
     346             : 
     347         264 :         return NT_STATUS_OK;
     348             : }

Generated by: LCOV version 1.14