LCOV - code coverage report
Current view: top level - source3/modules - vfs_error_inject.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 46 60 76.7 %
Date: 2021-09-23 10:06:22 Functions: 8 8 100.0 %

          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          21 : static int find_unix_error_from_string(const char *err_str)
      37             : {
      38             :         size_t i;
      39             : 
      40          50 :         for (i = 0; i < ARRAY_SIZE(unix_error_map_array); i++) {
      41          50 :                 struct unix_error_map *m = &unix_error_map_array[i];
      42             : 
      43          50 :                 if (strequal(err_str, m->err_str)) {
      44          21 :                         return m->error;
      45             :                 }
      46             :         }
      47             : 
      48           0 :         return 0;
      49             : }
      50             : 
      51         384 : static int inject_unix_error(const char *vfs_func, vfs_handle_struct *handle)
      52             : {
      53             :         const char *err_str;
      54             : 
      55         384 :         err_str = lp_parm_const_string(SNUM(handle->conn),
      56             :                                        "error_inject", vfs_func, NULL);
      57             : 
      58         384 :         if (err_str != NULL) {
      59             :                 int error;
      60             : 
      61          21 :                 error = find_unix_error_from_string(err_str);
      62          21 :                 if (error != 0) {
      63          21 :                         DBG_WARNING("Returning error %s for VFS function %s\n",
      64             :                                     err_str, vfs_func);
      65          21 :                         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         363 :         return 0;
      78             : }
      79             : 
      80         188 : static int vfs_error_inject_chdir(vfs_handle_struct *handle,
      81             :                                   const struct smb_filename *smb_fname)
      82             : {
      83             :         int error;
      84             : 
      85         188 :         error = inject_unix_error("chdir", handle);
      86         188 :         if (error != 0) {
      87           6 :                 errno = error;
      88           6 :                 return -1;
      89             :         }
      90             : 
      91         182 :         return SMB_VFS_NEXT_CHDIR(handle, smb_fname);
      92             : }
      93             : 
      94           2 : 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           2 :         error = inject_unix_error("pwrite", handle);
     103           2 :         if (error != 0) {
     104           2 :                 errno = error;
     105           2 :                 return -1;
     106             :         }
     107             : 
     108           0 :         return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
     109             : }
     110             : 
     111         192 : 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             :                                    int flags,
     116             :                                    mode_t mode)
     117             : {
     118         192 :         int error = inject_unix_error("openat", handle);
     119             : 
     120         192 :         if (!fsp->fsp_flags.is_pathref && error != 0) {
     121           4 :                 errno = error;
     122           4 :                 return -1;
     123             :         }
     124         188 :         return SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname, fsp, flags, mode);
     125             : }
     126             : 
     127           2 : static int vfs_error_inject_unlinkat(struct vfs_handle_struct *handle,
     128             :                                      struct files_struct *dirfsp,
     129             :                                      const struct smb_filename *smb_fname,
     130             :                                      int flags)
     131             : {
     132           2 :         struct smb_filename *full_fname = NULL;
     133           2 :         struct smb_filename *parent_fname = NULL;
     134           2 :         int error = inject_unix_error("unlinkat", handle);
     135             :         int ret;
     136             :         NTSTATUS status;
     137             : 
     138           2 :         if (error == 0) {
     139           1 :                 return SMB_VFS_NEXT_UNLINKAT(handle, dirfsp, smb_fname, flags);
     140             :         }
     141             : 
     142           1 :         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
     143             :                                                   dirfsp,
     144             :                                                   smb_fname);
     145           1 :         if (full_fname == NULL) {
     146           0 :                 return -1;
     147             :         }
     148             : 
     149           1 :         status = SMB_VFS_PARENT_PATHNAME(handle->conn,
     150             :                                          full_fname, /* TALLOC_CTX. */
     151             :                                          full_fname,
     152             :                                          &parent_fname,
     153             :                                          NULL);
     154           1 :         if (!NT_STATUS_IS_OK(status)) {
     155           0 :                 TALLOC_FREE(full_fname);
     156           0 :                 errno = map_errno_from_nt_status(status);
     157           0 :                 return -1;
     158             :         }
     159             : 
     160           1 :         ret = SMB_VFS_STAT(handle->conn, parent_fname);
     161           1 :         if (ret != 0) {
     162           0 :                 TALLOC_FREE(full_fname);
     163           0 :                 return -1;
     164             :         }
     165             : 
     166           1 :         if (parent_fname->st.st_ex_uid == get_current_uid(dirfsp->conn)) {
     167           1 :                 return SMB_VFS_NEXT_UNLINKAT(handle, dirfsp, smb_fname, flags);
     168             :         }
     169             : 
     170           0 :         errno = error;
     171           0 :         return -1;
     172             : }
     173             : 
     174             : static struct vfs_fn_pointers vfs_error_inject_fns = {
     175             :         .chdir_fn = vfs_error_inject_chdir,
     176             :         .pwrite_fn = vfs_error_inject_pwrite,
     177             :         .openat_fn = vfs_error_inject_openat,
     178             :         .unlinkat_fn = vfs_error_inject_unlinkat,
     179             : };
     180             : 
     181             : static_decl_vfs;
     182          44 : NTSTATUS vfs_error_inject_init(TALLOC_CTX *ctx)
     183             : {
     184          44 :         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "error_inject",
     185             :                                 &vfs_error_inject_fns);
     186             : }

Generated by: LCOV version 1.13