LCOV - code coverage report
Current view: top level - source4/ntvfs/posix - pvfs_xattr.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 125 176 71.0 %
Date: 2021-09-23 10:06:22 Functions: 18 19 94.7 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    POSIX NTVFS backend - xattr support
       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             : #include "includes.h"
      23             : #include "vfs_posix.h"
      24             : #include "../lib/util/unix_privs.h"
      25             : #include "librpc/gen_ndr/ndr_xattr.h"
      26             : #include "param/param.h"
      27             : #include "ntvfs/posix/posix_eadb_proto.h"
      28             : 
      29             : /*
      30             :   pull a xattr as a blob
      31             : */
      32     1277377 : static NTSTATUS pull_xattr_blob(struct pvfs_state *pvfs,
      33             :                                 TALLOC_CTX *mem_ctx,
      34             :                                 const char *attr_name, 
      35             :                                 const char *fname, 
      36             :                                 int fd, 
      37             :                                 size_t estimated_size,
      38             :                                 DATA_BLOB *blob)
      39             : {
      40             :         NTSTATUS status;
      41             : 
      42     1277377 :         if (pvfs->ea_db) {
      43     1277377 :                 return pull_xattr_blob_tdb(pvfs, mem_ctx, attr_name, fname, 
      44             :                                            fd, estimated_size, blob);
      45             :         }
      46             : 
      47           0 :         status = pull_xattr_blob_system(pvfs, mem_ctx, attr_name, fname, 
      48             :                                         fd, estimated_size, blob);
      49             : 
      50             :         /* if the filesystem doesn't support them, then tell pvfs not to try again */
      51           0 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)||
      52           0 :             NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)||
      53           0 :             NT_STATUS_EQUAL(status, NT_STATUS_INVALID_SYSTEM_SERVICE)) {
      54           0 :                 DEBUG(2,("pvfs_xattr: xattr not supported in filesystem: %s\n", nt_errstr(status)));
      55           0 :                 pvfs->flags &= ~PVFS_FLAG_XATTR_ENABLE;
      56           0 :                 status = NT_STATUS_NOT_FOUND;
      57             :         }
      58             : 
      59           0 :         return status;
      60             : }
      61             : 
      62             : /*
      63             :   push a xattr as a blob
      64             : */
      65      100729 : static NTSTATUS push_xattr_blob(struct pvfs_state *pvfs,
      66             :                                 const char *attr_name, 
      67             :                                 const char *fname, 
      68             :                                 int fd, 
      69             :                                 const DATA_BLOB *blob)
      70             : {
      71      100729 :         if (pvfs->ea_db) {
      72      100729 :                 return push_xattr_blob_tdb(pvfs, attr_name, fname, fd, blob);
      73             :         }
      74           0 :         return push_xattr_blob_system(pvfs, attr_name, fname, fd, blob);
      75             : }
      76             : 
      77             : 
      78             : /*
      79             :   delete a xattr
      80             : */
      81           7 : static NTSTATUS delete_xattr(struct pvfs_state *pvfs, const char *attr_name, 
      82             :                              const char *fname, int fd)
      83             : {
      84           7 :         if (pvfs->ea_db) {
      85           7 :                 return delete_posix_eadb(pvfs, attr_name, fname, fd);
      86             :         }
      87           0 :         return delete_xattr_system(pvfs, attr_name, fname, fd);
      88             : }
      89             : 
      90             : /*
      91             :   a hook called on unlink - allows the tdb xattr backend to cleanup
      92             : */
      93      208448 : NTSTATUS pvfs_xattr_unlink_hook(struct pvfs_state *pvfs, const char *fname)
      94             : {
      95      208448 :         if (pvfs->ea_db) {
      96      208448 :                 return unlink_posix_eadb(pvfs, fname);
      97             :         }
      98           0 :         return unlink_xattr_system(pvfs, fname);
      99             : }
     100             : 
     101             : 
     102             : /*
     103             :   load a NDR structure from a xattr
     104             : */
     105     1274660 : NTSTATUS pvfs_xattr_ndr_load(struct pvfs_state *pvfs,
     106             :                              TALLOC_CTX *mem_ctx,
     107             :                              const char *fname, int fd, const char *attr_name,
     108             :                              void *p, void *pull_fn)
     109             : {
     110             :         NTSTATUS status;
     111             :         DATA_BLOB blob;
     112             :         enum ndr_err_code ndr_err;
     113             : 
     114     1274660 :         status = pull_xattr_blob(pvfs, mem_ctx, attr_name, fname, 
     115             :                                  fd, XATTR_DOSATTRIB_ESTIMATED_SIZE, &blob);
     116     1274660 :         if (!NT_STATUS_IS_OK(status)) {
     117      931027 :                 return status;
     118             :         }
     119             : 
     120             :         /* pull the blob */
     121      343633 :         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, p,
     122             :                                                                    (ndr_pull_flags_fn_t)pull_fn);
     123      343633 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     124           0 :                 return ndr_map_error2ntstatus(ndr_err);
     125             :         }
     126             : 
     127      343633 :         data_blob_free(&blob);
     128             : 
     129      343633 :         return NT_STATUS_OK;
     130             : }
     131             : 
     132             : /*
     133             :   save a NDR structure into a xattr
     134             : */
     135      100667 : NTSTATUS pvfs_xattr_ndr_save(struct pvfs_state *pvfs,
     136             :                              const char *fname, int fd, const char *attr_name, 
     137             :                              void *p, void *push_fn)
     138             : {
     139      100667 :         TALLOC_CTX *mem_ctx = talloc_new(NULL);
     140             :         DATA_BLOB blob;
     141             :         NTSTATUS status;
     142             :         enum ndr_err_code ndr_err;
     143             : 
     144      100667 :         ndr_err = ndr_push_struct_blob(&blob, mem_ctx, p, (ndr_push_flags_fn_t)push_fn);
     145      100667 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     146           0 :                 talloc_free(mem_ctx);
     147           0 :                 return ndr_map_error2ntstatus(ndr_err);
     148             :         }
     149             : 
     150      100667 :         status = push_xattr_blob(pvfs, attr_name, fname, fd, &blob);
     151      100667 :         talloc_free(mem_ctx);
     152             : 
     153      100667 :         return status;
     154             : }
     155             : 
     156             : 
     157             : /*
     158             :   fill in file attributes from extended attributes
     159             : */
     160      801912 : NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
     161             : {
     162             :         NTSTATUS status;
     163             :         struct xattr_DosAttrib attrib;
     164      801912 :         TALLOC_CTX *mem_ctx = talloc_new(name);
     165             :         struct xattr_DosInfo1 *info1;
     166             :         struct xattr_DosInfo2Old *info2;
     167             : 
     168      801912 :         if (name->stream_name != NULL) {
     169         486 :                 name->stream_exists = false;
     170             :         } else {
     171      801426 :                 name->stream_exists = true;
     172             :         }
     173             : 
     174      801912 :         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
     175           0 :                 return NT_STATUS_OK;
     176             :         }
     177             : 
     178      801912 :         status = pvfs_xattr_ndr_load(pvfs, mem_ctx, name->full_name, 
     179             :                                      fd, XATTR_DOSATTRIB_NAME,
     180             :                                      &attrib,
     181             :                                      (void *) ndr_pull_xattr_DosAttrib);
     182             : 
     183             :         /* not having a DosAttrib is not an error */
     184      801912 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
     185      462067 :                 talloc_free(mem_ctx);
     186      462067 :                 return pvfs_stream_info(pvfs, name, fd);
     187             :         }
     188             : 
     189      339845 :         if (!NT_STATUS_IS_OK(status)) {
     190           0 :                 talloc_free(mem_ctx);
     191           0 :                 return status;
     192             :         }
     193             : 
     194      339845 :         switch (attrib.version) {
     195      339845 :         case 1:
     196      339845 :                 info1 = &attrib.info.info1;
     197      339845 :                 name->dos.attrib = pvfs_attrib_normalise(info1->attrib, 
     198             :                                                          name->st.st_mode);
     199      339845 :                 name->dos.ea_size = info1->ea_size;
     200      339845 :                 if (name->st.st_size == info1->size) {
     201      296188 :                         name->dos.alloc_size = 
     202      296188 :                                 pvfs_round_alloc_size(pvfs, info1->alloc_size);
     203             :                 }
     204      339845 :                 if (!null_nttime(info1->create_time)) {
     205      339845 :                         name->dos.create_time = info1->create_time;
     206             :                 }
     207      339845 :                 if (!null_nttime(info1->change_time)) {
     208      339845 :                         name->dos.change_time = info1->change_time;
     209             :                 }
     210      339845 :                 name->dos.flags = 0;
     211      339845 :                 break;
     212             : 
     213           0 :         case 2:
     214             :                 /*
     215             :                  * Note: This is only used to parse existing values from disk
     216             :                  *       We use xattr_DosInfo1 again for storing new values
     217             :                  */
     218           0 :                 info2 = &attrib.info.oldinfo2;
     219           0 :                 name->dos.attrib = pvfs_attrib_normalise(info2->attrib, 
     220             :                                                          name->st.st_mode);
     221           0 :                 name->dos.ea_size = info2->ea_size;
     222           0 :                 if (name->st.st_size == info2->size) {
     223           0 :                         name->dos.alloc_size = 
     224           0 :                                 pvfs_round_alloc_size(pvfs, info2->alloc_size);
     225             :                 }
     226           0 :                 if (!null_nttime(info2->create_time)) {
     227           0 :                         name->dos.create_time = info2->create_time;
     228             :                 }
     229           0 :                 if (!null_nttime(info2->change_time)) {
     230           0 :                         name->dos.change_time = info2->change_time;
     231             :                 }
     232           0 :                 name->dos.flags = info2->flags;
     233           0 :                 break;
     234             : 
     235           0 :         default:
     236           0 :                 DEBUG(0,("ERROR: Unsupported xattr DosAttrib version %d on '%s'\n",
     237             :                          attrib.version, name->full_name));
     238           0 :                 talloc_free(mem_ctx);
     239           0 :                 return NT_STATUS_INVALID_LEVEL;
     240             :         }
     241      339845 :         talloc_free(mem_ctx);
     242             :         
     243      339845 :         status = pvfs_stream_info(pvfs, name, fd);
     244             : 
     245      339845 :         return status;
     246             : }
     247             : 
     248             : 
     249             : /*
     250             :   save the file attribute into the xattr
     251             : */
     252       99710 : NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
     253             : {
     254             :         struct xattr_DosAttrib attrib;
     255             :         struct xattr_DosInfo1 *info1;
     256             : 
     257       99710 :         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
     258           0 :                 return NT_STATUS_OK;
     259             :         }
     260             : 
     261       99710 :         attrib.version = 1;
     262       99710 :         info1 = &attrib.info.info1;
     263             : 
     264       99710 :         name->dos.attrib = pvfs_attrib_normalise(name->dos.attrib, name->st.st_mode);
     265             : 
     266       99710 :         info1->attrib      = name->dos.attrib;
     267       99710 :         info1->ea_size     = name->dos.ea_size;
     268       99710 :         info1->size        = name->st.st_size;
     269       99710 :         info1->alloc_size  = name->dos.alloc_size;
     270       99710 :         info1->create_time = name->dos.create_time;
     271       99710 :         info1->change_time = name->dos.change_time;
     272             : 
     273       99710 :         return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, 
     274             :                                    XATTR_DOSATTRIB_NAME, &attrib, 
     275             :                                    (void *) ndr_push_xattr_DosAttrib);
     276             : }
     277             : 
     278             : 
     279             : /*
     280             :   load the set of DOS EAs
     281             : */
     282         322 : NTSTATUS pvfs_doseas_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
     283             :                           struct xattr_DosEAs *eas)
     284             : {
     285             :         NTSTATUS status;
     286         322 :         ZERO_STRUCTP(eas);
     287             : 
     288         322 :         if (name->stream_name) {
     289             :                 /* We don't support EAs on streams */
     290           3 :                 return NT_STATUS_INVALID_PARAMETER;
     291             :         }
     292             : 
     293         319 :         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
     294           0 :                 return NT_STATUS_OK;
     295             :         }
     296         319 :         status = pvfs_xattr_ndr_load(pvfs, eas, name->full_name, fd, XATTR_DOSEAS_NAME,
     297             :                                      eas, (void *) ndr_pull_xattr_DosEAs);
     298         319 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
     299         297 :                 return NT_STATUS_OK;
     300             :         }
     301          22 :         return status;
     302             : }
     303             : 
     304             : /*
     305             :   save the set of DOS EAs
     306             : */
     307         294 : NTSTATUS pvfs_doseas_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
     308             :                           struct xattr_DosEAs *eas)
     309             : {
     310         294 :         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
     311           0 :                 return NT_STATUS_OK;
     312             :         }
     313         294 :         return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, XATTR_DOSEAS_NAME, eas, 
     314             :                                    (void *) ndr_push_xattr_DosEAs);
     315             : }
     316             : 
     317             : 
     318             : /*
     319             :   load the set of streams from extended attributes
     320             : */
     321         609 : NTSTATUS pvfs_streams_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
     322             :                            struct xattr_DosStreams *streams)
     323             : {
     324             :         NTSTATUS status;
     325         609 :         ZERO_STRUCTP(streams);
     326         609 :         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
     327           0 :                 return NT_STATUS_OK;
     328             :         }
     329         609 :         status = pvfs_xattr_ndr_load(pvfs, streams, name->full_name, fd, 
     330             :                                      XATTR_DOSSTREAMS_NAME,
     331             :                                      streams, 
     332             :                                      (void *) ndr_pull_xattr_DosStreams);
     333         609 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
     334         311 :                 return NT_STATUS_OK;
     335             :         }
     336         298 :         return status;
     337             : }
     338             : 
     339             : /*
     340             :   save the set of streams into filesystem xattr
     341             : */
     342          79 : NTSTATUS pvfs_streams_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
     343             :                            struct xattr_DosStreams *streams)
     344             : {
     345          79 :         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
     346           0 :                 return NT_STATUS_OK;
     347             :         }
     348          79 :         return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, 
     349             :                                    XATTR_DOSSTREAMS_NAME, 
     350             :                                    streams, 
     351             :                                    (void *) ndr_push_xattr_DosStreams);
     352             : }
     353             : 
     354             : 
     355             : /*
     356             :   load the current ACL from extended attributes
     357             : */
     358      470209 : NTSTATUS pvfs_acl_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
     359             :                        struct xattr_NTACL *acl)
     360             : {
     361             :         NTSTATUS status;
     362      470209 :         ZERO_STRUCTP(acl);
     363      470209 :         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
     364           0 :                 return NT_STATUS_NOT_FOUND;
     365             :         }
     366      470209 :         status = pvfs_xattr_ndr_load(pvfs, acl, name->full_name, fd, 
     367             :                                      XATTR_NTACL_NAME,
     368             :                                      acl, 
     369             :                                      (void *) ndr_pull_xattr_NTACL);
     370      470209 :         return status;
     371             : }
     372             : 
     373             : /*
     374             :   save the acl for a file into filesystem xattr
     375             : */
     376           0 : NTSTATUS pvfs_acl_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
     377             :                        struct xattr_NTACL *acl)
     378             : {
     379             :         NTSTATUS status;
     380             :         void *privs;
     381             : 
     382           0 :         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
     383           0 :                 return NT_STATUS_OK;
     384             :         }
     385             : 
     386             :         /* this xattr is in the "system" namespace, so we need
     387             :            admin privileges to set it */
     388           0 :         privs = root_privileges();
     389           0 :         status = pvfs_xattr_ndr_save(pvfs, name->full_name, fd, 
     390             :                                      XATTR_NTACL_NAME, 
     391             :                                      acl, 
     392             :                                      (void *) ndr_push_xattr_NTACL);
     393           0 :         talloc_free(privs);
     394           0 :         return status;
     395             : }
     396             : 
     397             : /*
     398             :   create a zero length xattr with the given name
     399             : */
     400          45 : NTSTATUS pvfs_xattr_create(struct pvfs_state *pvfs, 
     401             :                            const char *fname, int fd,
     402             :                            const char *attr_prefix,
     403             :                            const char *attr_name)
     404             : {
     405             :         NTSTATUS status;
     406          45 :         DATA_BLOB blob = data_blob(NULL, 0);
     407          45 :         char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
     408          45 :         if (aname == NULL) {
     409           0 :                 return NT_STATUS_NO_MEMORY;
     410             :         }
     411          45 :         status = push_xattr_blob(pvfs, aname, fname, fd, &blob);
     412          45 :         talloc_free(aname);
     413          45 :         return status;
     414             : }
     415             : 
     416             : 
     417             : /*
     418             :   delete a xattr with the given name
     419             : */
     420           7 : NTSTATUS pvfs_xattr_delete(struct pvfs_state *pvfs, 
     421             :                            const char *fname, int fd,
     422             :                            const char *attr_prefix,
     423             :                            const char *attr_name)
     424             : {
     425             :         NTSTATUS status;
     426           7 :         char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
     427           7 :         if (aname == NULL) {
     428           0 :                 return NT_STATUS_NO_MEMORY;
     429             :         }
     430           7 :         status = delete_xattr(pvfs, aname, fname, fd);
     431           7 :         talloc_free(aname);
     432           7 :         return status;
     433             : }
     434             : 
     435             : /*
     436             :   load a xattr with the given name
     437             : */
     438          31 : NTSTATUS pvfs_xattr_load(struct pvfs_state *pvfs, 
     439             :                          TALLOC_CTX *mem_ctx,
     440             :                          const char *fname, int fd,
     441             :                          const char *attr_prefix,
     442             :                          const char *attr_name,
     443             :                          size_t estimated_size,
     444             :                          DATA_BLOB *blob)
     445             : {
     446             :         NTSTATUS status;
     447          31 :         char *aname = talloc_asprintf(mem_ctx, "%s%s", attr_prefix, attr_name);
     448          31 :         if (aname == NULL) {
     449           0 :                 return NT_STATUS_NO_MEMORY;
     450             :         }
     451          31 :         status = pull_xattr_blob(pvfs, mem_ctx, aname, fname, fd, estimated_size, blob);
     452          31 :         talloc_free(aname);
     453          31 :         return status;
     454             : }
     455             : 
     456             : /*
     457             :   save a xattr with the given name
     458             : */
     459          17 : NTSTATUS pvfs_xattr_save(struct pvfs_state *pvfs, 
     460             :                          const char *fname, int fd,
     461             :                          const char *attr_prefix,
     462             :                          const char *attr_name,
     463             :                          const DATA_BLOB *blob)
     464             : {
     465             :         NTSTATUS status;
     466          17 :         char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
     467          17 :         if (aname == NULL) {
     468           0 :                 return NT_STATUS_NO_MEMORY;
     469             :         }
     470          17 :         status = push_xattr_blob(pvfs, aname, fname, fd, blob);
     471          17 :         talloc_free(aname);
     472          17 :         return status;
     473             : }
     474             : 
     475             : 
     476             : /*
     477             :   probe for system support for xattrs
     478             : */
     479        1343 : void pvfs_xattr_probe(struct pvfs_state *pvfs)
     480             : {
     481        1343 :         TALLOC_CTX *tmp_ctx = talloc_new(pvfs);
     482             :         DATA_BLOB blob;
     483        1343 :         pull_xattr_blob(pvfs, tmp_ctx, "user.XattrProbe", pvfs->base_directory, 
     484             :                         -1, 1, &blob);
     485        1343 :         pull_xattr_blob(pvfs, tmp_ctx, "security.XattrProbe", pvfs->base_directory, 
     486             :                         -1, 1, &blob);
     487        1343 :         talloc_free(tmp_ctx);
     488        1343 : }

Generated by: LCOV version 1.13