LCOV - code coverage report
Current view: top level - source4/ntvfs/posix - vfs_posix.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 164 189 86.8 %
Date: 2024-06-13 04:01:37 Functions: 7 9 77.8 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    POSIX NTVFS backend
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2004
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             :    
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             :    
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : /*
      22             :   this implements most of the POSIX NTVFS backend
      23             :   This is the default backend
      24             : */
      25             : 
      26             : #include "includes.h"
      27             : #include "vfs_posix.h"
      28             : #include "librpc/gen_ndr/security.h"
      29             : #include <tdb.h>
      30             : #include "lib/tdb_wrap/tdb_wrap.h"
      31             : #include "libcli/security/security.h"
      32             : #include "lib/events/events.h"
      33             : #include "param/param.h"
      34             : 
      35             : /*
      36             :   setup config options for a posix share
      37             : */
      38        1321 : static void pvfs_setup_options(struct pvfs_state *pvfs)
      39             : {
      40        1321 :         struct share_config *scfg = pvfs->ntvfs->ctx->config;
      41             :         char *eadb;
      42             :         char *xattr_backend;
      43        1321 :         bool def_perm_override = false;
      44             : 
      45        1321 :         if (share_bool_option(scfg, SHARE_MAP_HIDDEN, SHARE_MAP_HIDDEN_DEFAULT))
      46           0 :                 pvfs->flags |= PVFS_FLAG_MAP_HIDDEN;
      47        1321 :         if (share_bool_option(scfg, SHARE_MAP_ARCHIVE, SHARE_MAP_ARCHIVE_DEFAULT))
      48        1321 :                 pvfs->flags |= PVFS_FLAG_MAP_ARCHIVE;
      49        1321 :         if (share_bool_option(scfg, SHARE_MAP_SYSTEM, SHARE_MAP_SYSTEM_DEFAULT))
      50           0 :                 pvfs->flags |= PVFS_FLAG_MAP_SYSTEM;
      51        1321 :         if (share_bool_option(scfg, SHARE_READONLY, SHARE_READONLY_DEFAULT))
      52           0 :                 pvfs->flags |= PVFS_FLAG_READONLY;
      53        1321 :         if (share_bool_option(scfg, SHARE_STRICT_SYNC, SHARE_STRICT_SYNC_DEFAULT))
      54        1321 :                 pvfs->flags |= PVFS_FLAG_STRICT_SYNC;
      55        1321 :         if (share_bool_option(scfg, SHARE_STRICT_LOCKING, SHARE_STRICT_LOCKING_DEFAULT))
      56        1321 :                 pvfs->flags |= PVFS_FLAG_STRICT_LOCKING;
      57        1321 :         if (share_bool_option(scfg, SHARE_CI_FILESYSTEM, SHARE_CI_FILESYSTEM_DEFAULT))
      58           0 :                 pvfs->flags |= PVFS_FLAG_CI_FILESYSTEM;
      59        1321 :         if (share_bool_option(scfg, PVFS_FAKE_OPLOCKS, PVFS_FAKE_OPLOCKS_DEFAULT))
      60           0 :                 pvfs->flags |= PVFS_FLAG_FAKE_OPLOCKS;
      61             : 
      62             : #if defined(O_DIRECTORY) && defined(O_NOFOLLOW)
      63             :         /* set PVFS_PERM_OVERRIDE by default only if the system
      64             :          * supports the necessary capabilities to make it secure
      65             :          */
      66        1321 :         def_perm_override = true;
      67             : #endif
      68        1321 :         if (share_bool_option(scfg, PVFS_PERM_OVERRIDE, def_perm_override))
      69        1321 :                 pvfs->flags |= PVFS_FLAG_PERM_OVERRIDE;
      70             : 
      71             :         /* file perm options */
      72        1321 :         pvfs->options.create_mask       = share_int_option(scfg,
      73             :                                                            SHARE_CREATE_MASK,
      74             :                                                            SHARE_CREATE_MASK_DEFAULT);
      75        1321 :         pvfs->options.dir_mask          = share_int_option(scfg,
      76             :                                                            SHARE_DIR_MASK,
      77             :                                                            SHARE_DIR_MASK_DEFAULT);
      78        1321 :         pvfs->options.force_dir_mode    = share_int_option(scfg,
      79             :                                                            SHARE_FORCE_DIR_MODE,
      80             :                                                            SHARE_FORCE_DIR_MODE_DEFAULT);
      81        1321 :         pvfs->options.force_create_mode = share_int_option(scfg,
      82             :                                                            SHARE_FORCE_CREATE_MODE,
      83             :                                                            SHARE_FORCE_CREATE_MODE_DEFAULT);
      84             :         /* this must be a power of 2 */
      85        1321 :         pvfs->alloc_size_rounding = share_int_option(scfg,
      86             :                                                         PVFS_ALLOCATION_ROUNDING,
      87             :                                                         PVFS_ALLOCATION_ROUNDING_DEFAULT);
      88             : 
      89        1321 :         pvfs->search.inactivity_time = share_int_option(scfg,
      90             :                                                         PVFS_SEARCH_INACTIVITY,
      91             :                                                         PVFS_SEARCH_INACTIVITY_DEFAULT);
      92             : 
      93             : #ifdef HAVE_XATTR_SUPPORT
      94        1321 :         if (share_bool_option(scfg, PVFS_XATTR, PVFS_XATTR_DEFAULT))
      95        1321 :                 pvfs->flags |= PVFS_FLAG_XATTR_ENABLE;
      96             : #endif
      97             : 
      98        1321 :         pvfs->sharing_violation_delay = share_int_option(scfg,
      99             :                                                         PVFS_SHARE_DELAY,
     100             :                                                         PVFS_SHARE_DELAY_DEFAULT);
     101             : 
     102        1321 :         pvfs->oplock_break_timeout = share_int_option(scfg,
     103             :                                                       PVFS_OPLOCK_TIMEOUT,
     104             :                                                       PVFS_OPLOCK_TIMEOUT_DEFAULT);
     105             : 
     106        1321 :         pvfs->writetime_delay = share_int_option(scfg,
     107             :                                                  PVFS_WRITETIME_DELAY,
     108             :                                                  PVFS_WRITETIME_DELAY_DEFAULT);
     109             : 
     110        1321 :         pvfs->share_name = talloc_strdup(pvfs, scfg->name);
     111             : 
     112        1321 :         pvfs->fs_attribs = 
     113             :                 FS_ATTR_CASE_SENSITIVE_SEARCH | 
     114             :                 FS_ATTR_CASE_PRESERVED_NAMES |
     115             :                 FS_ATTR_UNICODE_ON_DISK;
     116             : 
     117             :         /* allow xattrs to be stored in a external tdb */
     118        1321 :         eadb = share_string_option(pvfs, scfg, PVFS_EADB, NULL);
     119        1321 :         if (eadb != NULL) {
     120        1321 :                 pvfs->ea_db = tdb_wrap_open(
     121             :                         pvfs, eadb, 50000,
     122        1321 :                         lpcfg_tdb_flags(pvfs->ntvfs->ctx->lp_ctx, TDB_DEFAULT),
     123             :                         O_RDWR|O_CREAT, 0600);
     124        1321 :                 if (pvfs->ea_db != NULL) {
     125        1321 :                         pvfs->flags |= PVFS_FLAG_XATTR_ENABLE;
     126             :                 } else {
     127           0 :                         DEBUG(0,("Failed to open eadb '%s' - %s\n",
     128             :                                  eadb, strerror(errno)));
     129           0 :                         pvfs->flags &= ~PVFS_FLAG_XATTR_ENABLE;
     130             :                 }
     131        1321 :                 TALLOC_FREE(eadb);
     132             :         }
     133             : 
     134        1321 :         if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
     135        1321 :                 pvfs->fs_attribs |= FS_ATTR_NAMED_STREAMS;
     136             :         }
     137        1321 :         if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
     138        1321 :                 pvfs->fs_attribs |= FS_ATTR_PERSISTANT_ACLS;
     139             :         }
     140             : 
     141        1321 :         pvfs->sid_cache.creator_owner = dom_sid_parse_talloc(pvfs, SID_CREATOR_OWNER);
     142        1321 :         pvfs->sid_cache.creator_group = dom_sid_parse_talloc(pvfs, SID_CREATOR_GROUP);
     143             : 
     144             :         /* check if the system really supports xattrs */
     145        1321 :         if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
     146        1321 :                 pvfs_xattr_probe(pvfs);
     147             :         }
     148             : 
     149             :         /* enable an ACL backend */
     150        1321 :         xattr_backend = share_string_option(pvfs, scfg, PVFS_ACL, "xattr");
     151        1321 :         pvfs->acl_ops = pvfs_acl_backend_byname(xattr_backend);
     152        1321 :         TALLOC_FREE(xattr_backend);
     153        1321 : }
     154             : 
     155        1321 : static int pvfs_state_destructor(struct pvfs_state *pvfs)
     156             : {
     157             :         struct pvfs_file *f, *fn;
     158             :         struct pvfs_search_state *s, *sn;
     159             : 
     160             :         /* 
     161             :          * make sure we cleanup files and searches before anything else
     162             :          * because there destructors need to acess the pvfs_state struct
     163             :          */
     164        1321 :         for (f=pvfs->files.list; f; f=fn) {
     165           0 :                 fn = f->next;
     166           0 :                 talloc_free(f);
     167             :         }
     168             : 
     169        1347 :         for (s=pvfs->search.list; s; s=sn) {
     170          26 :                 sn = s->next;
     171          26 :                 talloc_free(s);
     172             :         }
     173             : 
     174        1321 :         return 0;
     175             : }
     176             : 
     177             : /*
     178             :   connect to a share - used when a tree_connect operation comes
     179             :   in. For a disk based backend we needs to ensure that the base
     180             :   directory exists (tho it doesn't need to be accessible by the user,
     181             :   that comes later)
     182             : */
     183        1321 : static NTSTATUS pvfs_connect(struct ntvfs_module_context *ntvfs,
     184             :                              struct ntvfs_request *req,
     185             :                              union smb_tcon* tcon)
     186             : {
     187             :         struct pvfs_state *pvfs;
     188             :         struct stat st;
     189             :         char *base_directory;
     190             :         NTSTATUS status;
     191             :         const char *sharename;
     192             : 
     193        1321 :         switch (tcon->generic.level) {
     194           0 :         case RAW_TCON_TCON:
     195           0 :                 sharename = tcon->tcon.in.service;
     196           0 :                 break;
     197         780 :         case RAW_TCON_TCONX:
     198         780 :                 sharename = tcon->tconx.in.path;
     199         780 :                 break;
     200         541 :         case RAW_TCON_SMB2:
     201         541 :                 sharename = tcon->smb2.in.path;
     202         541 :                 break;
     203           0 :         default:
     204           0 :                 return NT_STATUS_INVALID_LEVEL;
     205             :         }
     206             : 
     207        1321 :         if (strncmp(sharename, "\\\\", 2) == 0) {
     208        1318 :                 char *p = strchr(sharename+2, '\\');
     209        1318 :                 if (p) {
     210        1318 :                         sharename = p + 1;
     211             :                 }
     212             :         }
     213             : 
     214             :         /*
     215             :          * TODO: call this from ntvfs_posix_init()
     216             :          *       but currently we don't have a lp_ctx there
     217             :          */
     218        1321 :         status = pvfs_acl_init();
     219        1321 :         NT_STATUS_NOT_OK_RETURN(status);
     220             : 
     221        1321 :         pvfs = talloc_zero(ntvfs, struct pvfs_state);
     222        1321 :         NT_STATUS_HAVE_NO_MEMORY(pvfs);
     223             : 
     224             :         /* for simplicity of path construction, remove any trailing slash now */
     225        1321 :         base_directory = share_string_option(pvfs, ntvfs->ctx->config, SHARE_PATH, "");
     226        1321 :         NT_STATUS_HAVE_NO_MEMORY(base_directory);
     227        1321 :         if (strcmp(base_directory, "/") != 0) {
     228        1321 :                 trim_string(base_directory, NULL, "/");
     229             :         }
     230             : 
     231        1321 :         pvfs->ntvfs = ntvfs;
     232        1321 :         pvfs->base_directory = base_directory;
     233             : 
     234             :         /* the directory must exist. Note that we deliberately don't
     235             :            check that it is readable */
     236        1321 :         if (stat(pvfs->base_directory, &st) != 0 || !S_ISDIR(st.st_mode)) {
     237           0 :                 DEBUG(0,("pvfs_connect: '%s' is not a directory, when connecting to [%s]\n", 
     238             :                          pvfs->base_directory, sharename));
     239           0 :                 return NT_STATUS_BAD_NETWORK_NAME;
     240             :         }
     241             : 
     242        1321 :         ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS");
     243        1321 :         NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
     244             : 
     245        1321 :         ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:");
     246        1321 :         NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
     247             : 
     248        1321 :         if (tcon->generic.level == RAW_TCON_TCONX) {
     249         780 :                 tcon->tconx.out.fs_type = ntvfs->ctx->fs_type;
     250         780 :                 tcon->tconx.out.dev_type = ntvfs->ctx->dev_type;
     251             :         }
     252             : 
     253        1321 :         ntvfs->private_data = pvfs;
     254             : 
     255        3918 :         pvfs->brl_context = brlock_init(pvfs, 
     256        1321 :                                      pvfs->ntvfs->ctx->server_id,
     257        1321 :                                      pvfs->ntvfs->ctx->lp_ctx,
     258        1321 :                                      pvfs->ntvfs->ctx->msg_ctx);
     259        1321 :         if (pvfs->brl_context == NULL) {
     260           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     261             :         }
     262             : 
     263        1321 :         pvfs->odb_context = odb_init(pvfs, pvfs->ntvfs->ctx);
     264        1321 :         if (pvfs->odb_context == NULL) {
     265           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     266             :         }
     267             : 
     268             :         /* allow this to be NULL - we just disable change notify */
     269        6470 :         pvfs->notify_context = notify_init(pvfs, 
     270        1321 :                                            pvfs->ntvfs->ctx->server_id,  
     271        1321 :                                            pvfs->ntvfs->ctx->msg_ctx, 
     272        1321 :                                            pvfs->ntvfs->ctx->lp_ctx,
     273        1321 :                                            pvfs->ntvfs->ctx->event_ctx,
     274        1321 :                                            pvfs->ntvfs->ctx->config);
     275             : 
     276             :         /* allocate the search handle -> ptr tree */
     277        1321 :         pvfs->search.idtree = idr_init(pvfs);
     278        1321 :         NT_STATUS_HAVE_NO_MEMORY(pvfs->search.idtree);
     279             : 
     280        1321 :         status = pvfs_mangle_init(pvfs);
     281        1321 :         NT_STATUS_NOT_OK_RETURN(status);
     282             : 
     283        1321 :         pvfs_setup_options(pvfs);
     284             : 
     285        1321 :         talloc_set_destructor(pvfs, pvfs_state_destructor);
     286             : 
     287             : #ifdef SIGXFSZ
     288             :         /* who had the stupid idea to generate a signal on a large
     289             :            file write instead of just failing it!? */
     290        1321 :         BlockSignals(true, SIGXFSZ);
     291             : #endif
     292             : 
     293        1321 :         return NT_STATUS_OK;
     294             : }
     295             : 
     296             : /*
     297             :   disconnect from a share
     298             : */
     299        1321 : static NTSTATUS pvfs_disconnect(struct ntvfs_module_context *ntvfs)
     300             : {
     301        1321 :         return NT_STATUS_OK;
     302             : }
     303             : 
     304             : /*
     305             :   check if a directory exists
     306             : */
     307         742 : static NTSTATUS pvfs_chkpath(struct ntvfs_module_context *ntvfs,
     308             :                              struct ntvfs_request *req,
     309             :                              union smb_chkpath *cp)
     310             : {
     311         742 :         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
     312             :                                   struct pvfs_state);
     313             :         struct pvfs_filename *name;
     314             :         NTSTATUS status;
     315             : 
     316             :         /* resolve the cifs name to a posix name */
     317         742 :         status = pvfs_resolve_name(pvfs, req, cp->chkpath.in.path, 0, &name);
     318         742 :         NT_STATUS_NOT_OK_RETURN(status);
     319             : 
     320         649 :         if (!name->exists) {
     321          95 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     322             :         }
     323             : 
     324         554 :         if (!S_ISDIR(name->st.st_mode)) {
     325           9 :                 return NT_STATUS_NOT_A_DIRECTORY;
     326             :         }
     327             : 
     328         545 :         return NT_STATUS_OK;
     329             : }
     330             : 
     331             : /*
     332             :   copy a set of files
     333             : */
     334           0 : static NTSTATUS pvfs_copy(struct ntvfs_module_context *ntvfs,
     335             :                           struct ntvfs_request *req, struct smb_copy *cp)
     336             : {
     337           0 :         DEBUG(0,("pvfs_copy not implemented\n"));
     338           0 :         return NT_STATUS_NOT_SUPPORTED;
     339             : }
     340             : 
     341             : /*
     342             :   return print queue info
     343             : */
     344           0 : static NTSTATUS pvfs_lpq(struct ntvfs_module_context *ntvfs,
     345             :                          struct ntvfs_request *req, union smb_lpq *lpq)
     346             : {
     347           0 :         return NT_STATUS_NOT_SUPPORTED;
     348             : }
     349             : 
     350             : /* SMBtrans - not used on file shares */
     351           2 : static NTSTATUS pvfs_trans(struct ntvfs_module_context *ntvfs,
     352             :                            struct ntvfs_request *req, struct smb_trans2 *trans2)
     353             : {
     354           2 :         return NT_STATUS_ACCESS_DENIED;
     355             : }
     356             : 
     357             : /*
     358             :   initialialise the POSIX disk backend, registering ourselves with the ntvfs subsystem
     359             :  */
     360          55 : NTSTATUS ntvfs_posix_init(TALLOC_CTX *ctx)
     361             : {
     362             :         NTSTATUS ret;
     363             :         struct ntvfs_ops ops;
     364          55 :         NTVFS_CURRENT_CRITICAL_SIZES(vers);
     365             : 
     366          55 :         ZERO_STRUCT(ops);
     367             : 
     368          55 :         ops.type = NTVFS_DISK;
     369             :         
     370             :         /* fill in all the operations */
     371          55 :         ops.connect_fn = pvfs_connect;
     372          55 :         ops.disconnect_fn = pvfs_disconnect;
     373          55 :         ops.unlink_fn = pvfs_unlink;
     374          55 :         ops.chkpath_fn = pvfs_chkpath;
     375          55 :         ops.qpathinfo_fn = pvfs_qpathinfo;
     376          55 :         ops.setpathinfo_fn = pvfs_setpathinfo;
     377          55 :         ops.open_fn = pvfs_open;
     378          55 :         ops.mkdir_fn = pvfs_mkdir;
     379          55 :         ops.rmdir_fn = pvfs_rmdir;
     380          55 :         ops.rename_fn = pvfs_rename;
     381          55 :         ops.copy_fn = pvfs_copy;
     382          55 :         ops.ioctl_fn = pvfs_ioctl;
     383          55 :         ops.read_fn = pvfs_read;
     384          55 :         ops.write_fn = pvfs_write;
     385          55 :         ops.seek_fn = pvfs_seek;
     386          55 :         ops.flush_fn = pvfs_flush;
     387          55 :         ops.close_fn = pvfs_close;
     388          55 :         ops.exit_fn = pvfs_exit;
     389          55 :         ops.lock_fn = pvfs_lock;
     390          55 :         ops.setfileinfo_fn = pvfs_setfileinfo;
     391          55 :         ops.qfileinfo_fn = pvfs_qfileinfo;
     392          55 :         ops.fsinfo_fn = pvfs_fsinfo;
     393          55 :         ops.lpq_fn = pvfs_lpq;
     394          55 :         ops.search_first_fn = pvfs_search_first;
     395          55 :         ops.search_next_fn = pvfs_search_next;
     396          55 :         ops.search_close_fn = pvfs_search_close;
     397          55 :         ops.trans_fn = pvfs_trans;
     398          55 :         ops.logoff_fn = pvfs_logoff;
     399          55 :         ops.async_setup_fn = pvfs_async_setup;
     400          55 :         ops.cancel_fn = pvfs_cancel;
     401          55 :         ops.notify_fn = pvfs_notify;
     402             : 
     403             :         /* register ourselves with the NTVFS subsystem. We register
     404             :            under the name 'default' as we wish to be the default
     405             :            backend, and also register as 'posix' */
     406          55 :         ops.name = "default";
     407          55 :         ret = ntvfs_register(&ops, &vers);
     408             : 
     409          55 :         if (!NT_STATUS_IS_OK(ret)) {
     410           0 :                 DEBUG(0,("Failed to register POSIX backend as '%s'!\n", ops.name));
     411             :         }
     412             : 
     413          55 :         ops.name = "posix";
     414          55 :         ret = ntvfs_register(&ops, &vers);
     415             : 
     416          55 :         if (!NT_STATUS_IS_OK(ret)) {
     417           0 :                 DEBUG(0,("Failed to register POSIX backend as '%s'!\n", ops.name));
     418             :         }
     419             : 
     420          55 :         if (NT_STATUS_IS_OK(ret)) {
     421          55 :                 ret = ntvfs_common_init();
     422             :         }
     423             : 
     424          55 :         return ret;
     425             : }

Generated by: LCOV version 1.13