LCOV - code coverage report
Current view: top level - source3/modules - vfs_error_inject.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 51 73 69.9 %
Date: 2024-04-21 15:09:00 Functions: 7 8 87.5 %

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

Generated by: LCOV version 1.14