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

Generated by: LCOV version 1.14