LCOV - code coverage report
Current view: top level - source3/modules - posixacl_xattr.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 0 200 0.0 %
Date: 2024-04-21 15:09:00 Functions: 0 7 0.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/Netbios implementation.
       3             :    VFS module to get and set posix acls through xattr
       4             :    Copyright (c) 2013 Anand Avati <avati@redhat.com>
       5             :    Copyright (c) 2016 Yan, Zheng <zyan@redhat.com>
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "includes.h"
      22             : #include "system/filesys.h"
      23             : #include "smbd/smbd.h"
      24             : #include "modules/posixacl_xattr.h"
      25             : 
      26             : /*
      27             :    POSIX ACL Format:
      28             : 
      29             :    Size = 4 (header) + N * 8 (entry)
      30             : 
      31             :    Offset  Size    Field (Little Endian)
      32             :    -------------------------------------
      33             :    0-3     4-byte  Version
      34             : 
      35             :    4-5     2-byte  Entry-1 tag
      36             :    6-7     2-byte  Entry-1 perm
      37             :    8-11    4-byte  Entry-1 id
      38             : 
      39             :    12-13   2-byte  Entry-2 tag
      40             :    14-15   2-byte  Entry-2 perm
      41             :    16-19   4-byte  Entry-2 id
      42             : 
      43             :    ...
      44             : 
      45             :  */
      46             : 
      47             : 
      48             : 
      49             : /* private functions */
      50             : 
      51             : #define ACL_EA_ACCESS           "system.posix_acl_access"
      52             : #define ACL_EA_DEFAULT          "system.posix_acl_default"
      53             : #define ACL_EA_VERSION          0x0002
      54             : #define ACL_EA_HEADER_SIZE      4
      55             : #define ACL_EA_ENTRY_SIZE       8
      56             : 
      57             : #define ACL_EA_SIZE(n)  (ACL_EA_HEADER_SIZE + ((n) * ACL_EA_ENTRY_SIZE))
      58             : 
      59           0 : static SMB_ACL_T mode_to_smb_acl(mode_t mode, TALLOC_CTX *mem_ctx)
      60             : {
      61             :         struct smb_acl_t *result;
      62             :         int count;
      63             : 
      64           0 :         count = 3;
      65           0 :         result = sys_acl_init(mem_ctx);
      66           0 :         if (!result) {
      67           0 :                 return NULL;
      68             :         }
      69             : 
      70           0 :         result->acl = talloc_array(result, struct smb_acl_entry, count);
      71           0 :         if (!result->acl) {
      72           0 :                 errno = ENOMEM;
      73           0 :                 talloc_free(result);
      74           0 :                 return NULL;
      75             :         }
      76             : 
      77           0 :         result->count = count;
      78             : 
      79           0 :         result->acl[0].a_type = SMB_ACL_USER_OBJ;
      80           0 :         result->acl[0].a_perm = (mode & S_IRWXU) >> 6;
      81             : 
      82           0 :         result->acl[1].a_type = SMB_ACL_GROUP_OBJ;
      83           0 :         result->acl[1].a_perm = (mode & S_IRWXG) >> 3;
      84             : 
      85           0 :         result->acl[2].a_type = SMB_ACL_OTHER;
      86           0 :         result->acl[2].a_perm = mode & S_IRWXO;
      87             : 
      88           0 :         return result;
      89             : }
      90             : 
      91           0 : static SMB_ACL_T posixacl_xattr_to_smb_acl(const char *buf, size_t xattr_size,
      92             :                                            TALLOC_CTX *mem_ctx)
      93             : {
      94             :         int count;
      95             :         int size;
      96             :         struct smb_acl_entry *smb_ace;
      97             :         struct smb_acl_t *result;
      98             :         int i;
      99             :         int offset;
     100             :         uint16_t tag;
     101             :         uint16_t perm;
     102             :         uint32_t id;
     103             : 
     104           0 :         size = xattr_size;
     105             : 
     106           0 :         if (size < ACL_EA_HEADER_SIZE) {
     107             :                 /* ACL should be at least as big as the header (4 bytes) */
     108           0 :                 errno = EINVAL;
     109           0 :                 return NULL;
     110             :         }
     111             : 
     112             :         /* Version is the first 4 bytes of the ACL */
     113           0 :         if (IVAL(buf, 0) != ACL_EA_VERSION) {
     114           0 :                 DEBUG(0, ("Unknown ACL EA version: %d\n",
     115             :                           IVAL(buf, 0)));
     116           0 :                 errno = EINVAL;
     117           0 :                 return NULL;
     118             :         }
     119           0 :         offset = ACL_EA_HEADER_SIZE;
     120             : 
     121           0 :         size -= ACL_EA_HEADER_SIZE;
     122           0 :         if (size % ACL_EA_ENTRY_SIZE) {
     123             :                 /* Size of entries must strictly be a multiple of
     124             :                    size of an ACE (8 bytes)
     125             :                 */
     126           0 :                 DEBUG(0, ("Invalid ACL EA size: %d\n", size));
     127           0 :                 errno = EINVAL;
     128           0 :                 return NULL;
     129             :         }
     130             : 
     131           0 :         count = size / ACL_EA_ENTRY_SIZE;
     132             : 
     133           0 :         result = sys_acl_init(mem_ctx);
     134           0 :         if (!result) {
     135           0 :                 return NULL;
     136             :         }
     137             : 
     138           0 :         result->acl = talloc_array(result, struct smb_acl_entry, count);
     139           0 :         if (!result->acl) {
     140           0 :                 errno = ENOMEM;
     141           0 :                 talloc_free(result);
     142           0 :                 return NULL;
     143             :         }
     144             : 
     145           0 :         result->count = count;
     146             : 
     147           0 :         smb_ace = result->acl;
     148             : 
     149           0 :         for (i = 0; i < count; i++) {
     150             :                 /* TAG is the first 2 bytes of an entry */
     151           0 :                 tag = SVAL(buf, offset);
     152           0 :                 offset += 2;
     153             : 
     154             :                 /* PERM is the next 2 bytes of an entry */
     155           0 :                 perm = SVAL(buf, offset);
     156           0 :                 offset += 2;
     157             : 
     158             :                 /* ID is the last 4 bytes of an entry */
     159           0 :                 id = IVAL(buf, offset);
     160           0 :                 offset += 4;
     161             : 
     162           0 :                 switch(tag) {
     163           0 :                 case ACL_USER:
     164           0 :                         smb_ace->a_type = SMB_ACL_USER;
     165           0 :                         break;
     166           0 :                 case ACL_USER_OBJ:
     167           0 :                         smb_ace->a_type = SMB_ACL_USER_OBJ;
     168           0 :                         break;
     169           0 :                 case ACL_GROUP:
     170           0 :                         smb_ace->a_type = SMB_ACL_GROUP;
     171           0 :                         break;
     172           0 :                 case ACL_GROUP_OBJ:
     173           0 :                         smb_ace->a_type = SMB_ACL_GROUP_OBJ;
     174           0 :                         break;
     175           0 :                 case ACL_OTHER:
     176           0 :                         smb_ace->a_type = SMB_ACL_OTHER;
     177           0 :                         break;
     178           0 :                 case ACL_MASK:
     179           0 :                         smb_ace->a_type = SMB_ACL_MASK;
     180           0 :                         break;
     181           0 :                 default:
     182           0 :                         DEBUG(0, ("unknown tag type %d\n", (unsigned int) tag));
     183           0 :                         errno = EINVAL;
     184           0 :                         return NULL;
     185             :                 }
     186             : 
     187             : 
     188           0 :                 switch(smb_ace->a_type) {
     189           0 :                 case SMB_ACL_USER:
     190           0 :                         smb_ace->info.user.uid = id;
     191           0 :                         break;
     192           0 :                 case SMB_ACL_GROUP:
     193           0 :                         smb_ace->info.group.gid = id;
     194           0 :                         break;
     195           0 :                 default:
     196           0 :                         break;
     197             :                 }
     198             : 
     199           0 :                 smb_ace->a_perm = 0;
     200           0 :                 smb_ace->a_perm |= ((perm & ACL_READ) ? SMB_ACL_READ : 0);
     201           0 :                 smb_ace->a_perm |= ((perm & ACL_WRITE) ? SMB_ACL_WRITE : 0);
     202           0 :                 smb_ace->a_perm |= ((perm & ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
     203             : 
     204           0 :                 smb_ace++;
     205             :         }
     206             : 
     207           0 :         return result;
     208             : }
     209             : 
     210             : 
     211           0 : static int posixacl_xattr_entry_compare(const void *left, const void *right)
     212             : {
     213           0 :         int ret = 0;
     214             :         uint16_t tag_left, tag_right;
     215             :         uint32_t id_left, id_right;
     216             : 
     217             :         /*
     218             :           Sorting precedence:
     219             :            - Smaller TAG values must be earlier.
     220             :            - Within same TAG, smaller identifiers must be earlier, E.g:
     221             :              UID 0 entry must be earlier than UID 200
     222             :              GID 17 entry must be earlier than GID 19
     223             :         */
     224             : 
     225             :         /* TAG is the first element in the entry */
     226           0 :         tag_left = SVAL(left, 0);
     227           0 :         tag_right = SVAL(right, 0);
     228             : 
     229           0 :         ret = (tag_left - tag_right);
     230           0 :         if (!ret) {
     231             :                 /* ID is the third element in the entry, after two short
     232             :                    integers (tag and perm), i.e at offset 4.
     233             :                 */
     234           0 :                 id_left = IVAL(left, 4);
     235           0 :                 id_right = IVAL(right, 4);
     236           0 :                 ret = id_left - id_right;
     237             :         }
     238             : 
     239           0 :         return ret;
     240             : }
     241             : 
     242             : 
     243           0 : static int smb_acl_to_posixacl_xattr(SMB_ACL_T theacl, char *buf, size_t len)
     244             : {
     245             :         ssize_t size;
     246             :         struct smb_acl_entry *smb_ace;
     247             :         int i;
     248             :         int count;
     249             :         uint16_t tag;
     250             :         uint16_t perm;
     251             :         uint32_t id;
     252             :         int offset;
     253             : 
     254           0 :         count = theacl->count;
     255             : 
     256           0 :         size = ACL_EA_SIZE(count);
     257           0 :         if (!buf) {
     258           0 :                 return size;
     259             :         }
     260           0 :         if (len < size) {
     261           0 :                 return -ERANGE;
     262             :         }
     263           0 :         smb_ace = theacl->acl;
     264             : 
     265             :         /* Version is the first 4 bytes of the ACL */
     266           0 :         SIVAL(buf, 0, ACL_EA_VERSION);
     267           0 :         offset = ACL_EA_HEADER_SIZE;
     268             : 
     269           0 :         for (i = 0; i < count; i++) {
     270             :                 /* Calculate tag */
     271           0 :                 switch(smb_ace->a_type) {
     272           0 :                 case SMB_ACL_USER:
     273           0 :                         tag = ACL_USER;
     274           0 :                         break;
     275           0 :                 case SMB_ACL_USER_OBJ:
     276           0 :                         tag = ACL_USER_OBJ;
     277           0 :                         break;
     278           0 :                 case SMB_ACL_GROUP:
     279           0 :                         tag = ACL_GROUP;
     280           0 :                         break;
     281           0 :                 case SMB_ACL_GROUP_OBJ:
     282           0 :                         tag = ACL_GROUP_OBJ;
     283           0 :                         break;
     284           0 :                 case SMB_ACL_OTHER:
     285           0 :                         tag = ACL_OTHER;
     286           0 :                         break;
     287           0 :                 case SMB_ACL_MASK:
     288           0 :                         tag = ACL_MASK;
     289           0 :                         break;
     290           0 :                 default:
     291           0 :                         DEBUG(0, ("Unknown tag value %d\n",
     292             :                                   smb_ace->a_type));
     293           0 :                         return -EINVAL;
     294             :                 }
     295             : 
     296             : 
     297             :                 /* Calculate id */
     298           0 :                 switch(smb_ace->a_type) {
     299           0 :                 case SMB_ACL_USER:
     300           0 :                         id = smb_ace->info.user.uid;
     301           0 :                         break;
     302           0 :                 case SMB_ACL_GROUP:
     303           0 :                         id = smb_ace->info.group.gid;
     304           0 :                         break;
     305           0 :                 default:
     306           0 :                         id = ACL_UNDEFINED_ID;
     307           0 :                         break;
     308             :                 }
     309             : 
     310             :                 /* Calculate perm */
     311           0 :                 perm = 0;
     312           0 :                 perm |= (smb_ace->a_perm & SMB_ACL_READ) ? ACL_READ : 0;
     313           0 :                 perm |= (smb_ace->a_perm & SMB_ACL_WRITE) ? ACL_WRITE : 0;
     314           0 :                 perm |= (smb_ace->a_perm & SMB_ACL_EXECUTE) ? ACL_EXECUTE : 0;
     315             : 
     316             :                 /* TAG is the first 2 bytes of an entry */
     317           0 :                 SSVAL(buf, offset, tag);
     318           0 :                 offset += 2;
     319             : 
     320             :                 /* PERM is the next 2 bytes of an entry */
     321           0 :                 SSVAL(buf, offset, perm);
     322           0 :                 offset += 2;
     323             : 
     324             :                 /* ID is the last 4 bytes of an entry */
     325           0 :                 SIVAL(buf, offset, id);
     326           0 :                 offset += 4;
     327             : 
     328           0 :                 smb_ace++;
     329             :         }
     330             : 
     331             :         /* Skip the header, sort @count number of 8-byte entries */
     332           0 :         qsort(buf+ACL_EA_HEADER_SIZE, count, ACL_EA_ENTRY_SIZE,
     333             :               posixacl_xattr_entry_compare);
     334             : 
     335           0 :         return size;
     336             : }
     337             : 
     338           0 : SMB_ACL_T posixacl_xattr_acl_get_fd(vfs_handle_struct *handle,
     339             :                                     files_struct *fsp,
     340             :                                     SMB_ACL_TYPE_T type,
     341             :                                     TALLOC_CTX *mem_ctx)
     342             : {
     343             :         int ret;
     344           0 :         int size = ACL_EA_SIZE(20);
     345           0 :         char *buf = alloca(size);
     346             :         const char *name;
     347             : 
     348           0 :         if (type == SMB_ACL_TYPE_ACCESS) {
     349           0 :                 name = ACL_EA_ACCESS;
     350           0 :         } else if (type == SMB_ACL_TYPE_DEFAULT) {
     351           0 :                 name = ACL_EA_DEFAULT;
     352             :         } else {
     353           0 :                 errno = EINVAL;
     354           0 :                 return NULL;
     355             :         }
     356             : 
     357           0 :         if (!buf) {
     358           0 :                 return NULL;
     359             :         }
     360             : 
     361           0 :         ret = SMB_VFS_FGETXATTR(fsp, name, buf, size);
     362           0 :         if (ret < 0 && errno == ERANGE) {
     363           0 :                 size = SMB_VFS_FGETXATTR(fsp, name, NULL, 0);
     364           0 :                 if (size > 0) {
     365           0 :                         buf = alloca(size);
     366           0 :                         if (!buf) {
     367           0 :                                 return NULL;
     368             :                         }
     369           0 :                         ret = SMB_VFS_FGETXATTR(fsp, name, buf, size);
     370             :                 }
     371             :         }
     372             : 
     373           0 :         if (ret > 0) {
     374           0 :                 return posixacl_xattr_to_smb_acl(buf, ret, mem_ctx);
     375             :         }
     376           0 :         if (ret == 0 || errno == ENOATTR) {
     377             :                 SMB_STRUCT_STAT sbuf;
     378           0 :                 ret = SMB_VFS_FSTAT(fsp, &sbuf);
     379           0 :                 if (ret == 0)
     380           0 :                         return mode_to_smb_acl(sbuf.st_ex_mode, mem_ctx);
     381             :         }
     382           0 :         return NULL;
     383             : }
     384             : 
     385           0 : int posixacl_xattr_acl_set_fd(vfs_handle_struct *handle,
     386             :                               files_struct *fsp,
     387             :                               SMB_ACL_TYPE_T type,
     388             :                               SMB_ACL_T theacl)
     389             : {
     390           0 :         const char *name = NULL;
     391             :         char *buf;
     392             :         ssize_t size;
     393             :         int ret;
     394             : 
     395           0 :         if (type == SMB_ACL_TYPE_ACCESS) {
     396           0 :                 name = ACL_EA_ACCESS;
     397           0 :         } else if (type == SMB_ACL_TYPE_DEFAULT) {
     398           0 :                 name = ACL_EA_DEFAULT;
     399             :         } else {
     400           0 :                 errno = EINVAL;
     401           0 :                 return -1;
     402             :         }
     403             : 
     404           0 :         size = smb_acl_to_posixacl_xattr(theacl, NULL, 0);
     405           0 :         buf = alloca(size);
     406           0 :         if (!buf) {
     407           0 :                 return -1;
     408             :         }
     409             : 
     410           0 :         ret = smb_acl_to_posixacl_xattr(theacl, buf, size);
     411           0 :         if (ret < 0) {
     412           0 :                 errno = -ret;
     413           0 :                 return -1;
     414             :         }
     415             : 
     416           0 :         return SMB_VFS_FSETXATTR(fsp, name, buf, size, 0);
     417             : }
     418             : 
     419           0 : int posixacl_xattr_acl_delete_def_fd(vfs_handle_struct *handle,
     420             :                                 files_struct *fsp)
     421             : {
     422           0 :         return SMB_VFS_FREMOVEXATTR(fsp, ACL_EA_DEFAULT);
     423             : }

Generated by: LCOV version 1.14