LCOV - code coverage report
Current view: top level - source3/modules - vfs_error_inject.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 2 65 3.1 %
Date: 2024-06-13 04:01:37 Functions: 1 7 14.3 %

          Line data    Source code
       1             : /*
       2             :  *  Unix SMB/CIFS implementation.
       3             :  *  Samba VFS module for error injection in VFS calls
       4             :  *  Copyright (C) Christof Schmitt 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             : 
      23             : #undef DBGC_CLASS
      24             : #define DBGC_CLASS DBGC_VFS
      25             : 
      26             : struct unix_error_map {
      27             :         const char *err_str;
      28             :         int error;
      29             : } unix_error_map_array[] = {
      30             :         {       "ESTALE",     ESTALE  },
      31             :         {       "EBADF",      EBADF   },
      32             :         {       "EINTR",      EINTR   },
      33             :         {       "EACCES",     EACCES  },
      34             : };
      35             : 
      36           0 : static int find_unix_error_from_string(const char *err_str)
      37             : {
      38             :         size_t i;
      39             : 
      40           0 :         for (i = 0; i < ARRAY_SIZE(unix_error_map_array); i++) {
      41           0 :                 struct unix_error_map *m = &unix_error_map_array[i];
      42             : 
      43           0 :                 if (strequal(err_str, m->err_str)) {
      44           0 :                         return m->error;
      45             :                 }
      46             :         }
      47             : 
      48           0 :         return 0;
      49             : }
      50             : 
      51           0 : static int inject_unix_error(const char *vfs_func, vfs_handle_struct *handle)
      52             : {
      53             :         const char *err_str;
      54             : 
      55           0 :         err_str = lp_parm_const_string(SNUM(handle->conn),
      56             :                                        "error_inject", vfs_func, NULL);
      57             : 
      58           0 :         if (err_str != NULL) {
      59             :                 int error;
      60             : 
      61           0 :                 error = find_unix_error_from_string(err_str);
      62           0 :                 if (error != 0) {
      63           0 :                         DBG_WARNING("Returning error %s for VFS function %s\n",
      64             :                                     err_str, vfs_func);
      65           0 :                         return error;
      66             :                 }
      67             : 
      68           0 :                 if (strequal(err_str, "panic")) {
      69           0 :                         DBG_ERR("Panic in VFS function %s\n", vfs_func);
      70           0 :                         smb_panic("error_inject");
      71             :                 }
      72             : 
      73           0 :                 DBG_ERR("Unknown error inject %s requested "
      74             :                         "for vfs function %s\n", err_str, vfs_func);
      75             :         }
      76             : 
      77           0 :         return 0;
      78             : }
      79             : 
      80           0 : static int vfs_error_inject_chdir(vfs_handle_struct *handle,
      81             :                                   const struct smb_filename *smb_fname)
      82             : {
      83             :         int error;
      84             : 
      85           0 :         error = inject_unix_error("chdir", handle);
      86           0 :         if (error != 0) {
      87           0 :                 errno = error;
      88           0 :                 return -1;
      89             :         }
      90             : 
      91           0 :         return SMB_VFS_NEXT_CHDIR(handle, smb_fname);
      92             : }
      93             : 
      94           0 : static ssize_t vfs_error_inject_pwrite(vfs_handle_struct *handle,
      95             :                                        files_struct *fsp,
      96             :                                        const void *data,
      97             :                                        size_t n,
      98             :                                        off_t offset)
      99             : {
     100             :         int error;
     101             : 
     102           0 :         error = inject_unix_error("pwrite", handle);
     103           0 :         if (error != 0) {
     104           0 :                 errno = error;
     105           0 :                 return -1;
     106             :         }
     107             : 
     108           0 :         return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
     109             : }
     110             : 
     111           0 : static int vfs_error_inject_openat(struct vfs_handle_struct *handle,
     112             :                                    const struct files_struct *dirfsp,
     113             :                                    const struct smb_filename *smb_fname,
     114             :                                    files_struct *fsp,
     115             :                                    const struct vfs_open_how *how)
     116             : {
     117           0 :         int error = inject_unix_error("openat", handle);
     118           0 :         int dirfsp_flags = (O_NOFOLLOW|O_DIRECTORY);
     119             :         bool return_error;
     120             : 
     121             : #ifdef O_PATH
     122           0 :         dirfsp_flags |= O_PATH;
     123             : #else
     124             : #ifdef O_SEARCH
     125             :         dirfsp_flags |= O_SEARCH;
     126             : #endif
     127             : #endif
     128             : 
     129           0 :         return_error = (error != 0);
     130           0 :         return_error &= !fsp->fsp_flags.is_pathref;
     131           0 :         return_error &= ((how->flags & dirfsp_flags) != dirfsp_flags);
     132             : 
     133           0 :         if (return_error) {
     134           0 :                 errno = error;
     135           0 :                 return -1;
     136             :         }
     137           0 :         return SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname, fsp, how);
     138             : }
     139             : 
     140           0 : static int vfs_error_inject_unlinkat(struct vfs_handle_struct *handle,
     141             :                                      struct files_struct *dirfsp,
     142             :                                      const struct smb_filename *smb_fname,
     143             :                                      int flags)
     144             : {
     145           0 :         struct smb_filename *full_fname = NULL;
     146           0 :         struct smb_filename *parent_fname = NULL;
     147           0 :         int error = inject_unix_error("unlinkat", handle);
     148             :         int ret;
     149             :         NTSTATUS status;
     150             : 
     151           0 :         if (error == 0) {
     152           0 :                 return SMB_VFS_NEXT_UNLINKAT(handle, dirfsp, smb_fname, flags);
     153             :         }
     154             : 
     155           0 :         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
     156             :                                                   dirfsp,
     157             :                                                   smb_fname);
     158           0 :         if (full_fname == NULL) {
     159           0 :                 return -1;
     160             :         }
     161             : 
     162           0 :         status = SMB_VFS_PARENT_PATHNAME(handle->conn,
     163             :                                          full_fname, /* TALLOC_CTX. */
     164             :                                          full_fname,
     165             :                                          &parent_fname,
     166             :                                          NULL);
     167           0 :         if (!NT_STATUS_IS_OK(status)) {
     168           0 :                 TALLOC_FREE(full_fname);
     169           0 :                 errno = map_errno_from_nt_status(status);
     170           0 :                 return -1;
     171             :         }
     172             : 
     173           0 :         ret = SMB_VFS_STAT(handle->conn, parent_fname);
     174           0 :         if (ret != 0) {
     175           0 :                 TALLOC_FREE(full_fname);
     176           0 :                 return -1;
     177             :         }
     178             : 
     179           0 :         if (parent_fname->st.st_ex_uid == get_current_uid(dirfsp->conn)) {
     180           0 :                 return SMB_VFS_NEXT_UNLINKAT(handle, dirfsp, smb_fname, flags);
     181             :         }
     182             : 
     183           0 :         errno = error;
     184           0 :         return -1;
     185             : }
     186             : 
     187             : static struct vfs_fn_pointers vfs_error_inject_fns = {
     188             :         .chdir_fn = vfs_error_inject_chdir,
     189             :         .pwrite_fn = vfs_error_inject_pwrite,
     190             :         .openat_fn = vfs_error_inject_openat,
     191             :         .unlinkat_fn = vfs_error_inject_unlinkat,
     192             : };
     193             : 
     194             : static_decl_vfs;
     195          26 : NTSTATUS vfs_error_inject_init(TALLOC_CTX *ctx)
     196             : {
     197          26 :         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "error_inject",
     198             :                                 &vfs_error_inject_fns);
     199             : }

Generated by: LCOV version 1.13