LCOV - code coverage report
Current view: top level - source3/modules - vfs_posixacl.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 146 212 68.9 %
Date: 2021-09-23 10:06:22 Functions: 7 8 87.5 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/Netbios implementation.
       3             :    VFS module to get and set posix acls
       4             :    Copyright (C) Volker Lendecke 2006
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "system/filesys.h"
      22             : #include "smbd/smbd.h"
      23             : #include "modules/vfs_posixacl.h"
      24             : 
      25             : /* prototypes for static functions first - for clarity */
      26             : 
      27             : static bool smb_ace_to_internal(acl_entry_t posix_ace,
      28             :                                 struct smb_acl_entry *ace);
      29             : static struct smb_acl_t *smb_acl_to_internal(acl_t acl, TALLOC_CTX *mem_ctx);
      30             : static int smb_acl_set_mode(acl_entry_t entry, SMB_ACL_PERM_T perm);
      31             : static acl_t smb_acl_to_posix(const struct smb_acl_t *acl);
      32             : 
      33             : 
      34             : /* public functions - the api */
      35             : 
      36      208104 : SMB_ACL_T posixacl_sys_acl_get_fd(vfs_handle_struct *handle,
      37             :                                   files_struct *fsp,
      38             :                                   SMB_ACL_TYPE_T type,
      39             :                                   TALLOC_CTX *mem_ctx)
      40             : {
      41             :         struct smb_acl_t *result;
      42      208104 :         acl_t acl = NULL;
      43             :         acl_type_t acl_type;
      44             : 
      45      208104 :         switch(type) {
      46      155328 :         case SMB_ACL_TYPE_ACCESS:
      47      155328 :                 acl_type = ACL_TYPE_ACCESS;
      48      155328 :                 break;
      49       52776 :         case SMB_ACL_TYPE_DEFAULT:
      50       52776 :                 acl_type = ACL_TYPE_DEFAULT;
      51       52776 :                 break;
      52           0 :         default:
      53           0 :                 errno = EINVAL;
      54           0 :                 return NULL;
      55             :         }
      56      208104 :         if (!fsp->fsp_flags.is_pathref && (acl_type == ACL_TYPE_ACCESS)) {
      57             :                 /* POSIX API only allows ACL_TYPE_ACCESS fetched on fd. */
      58       48600 :                 acl = acl_get_fd(fsp_get_io_fd(fsp));
      59      159504 :         } else if (fsp->fsp_flags.have_proc_fds) {
      60       38206 :                 int fd = fsp_get_pathref_fd(fsp);
      61       38206 :                 const char *proc_fd_path = NULL;
      62             :                 char buf[PATH_MAX];
      63             : 
      64       38206 :                 proc_fd_path = sys_proc_fd_path(fd, buf, sizeof(buf));
      65       38206 :                 if (proc_fd_path == NULL) {
      66           0 :                         return NULL;
      67             :                 }
      68             : 
      69       38206 :                 acl = acl_get_file(proc_fd_path, acl_type);
      70             :         } else {
      71             :                 /*
      72             :                  * This is no longer a handle based call.
      73             :                  */
      74      121298 :                 acl = acl_get_file(fsp->fsp_name->base_name, acl_type);
      75             :         }
      76      208104 :         if (acl == NULL) {
      77        1802 :                 return NULL;
      78             :         }
      79             : 
      80      206302 :         result = smb_acl_to_internal(acl, mem_ctx);
      81      206302 :         acl_free(acl);
      82      206302 :         return result;
      83             : }
      84             : 
      85         938 : int posixacl_sys_acl_set_fd(vfs_handle_struct *handle,
      86             :                             files_struct *fsp,
      87             :                             SMB_ACL_TYPE_T type,
      88             :                             SMB_ACL_T theacl)
      89             : {
      90             :         int res;
      91         938 :         acl_t acl = smb_acl_to_posix(theacl);
      92             :         acl_type_t acl_type;
      93         938 :         int fd = fsp_get_pathref_fd(fsp);
      94             : 
      95         938 :         if (acl == NULL) {
      96           0 :                 return -1;
      97             :         }
      98             : 
      99         938 :         switch(type) {
     100         728 :         case SMB_ACL_TYPE_ACCESS:
     101         728 :                 acl_type = ACL_TYPE_ACCESS;
     102         728 :                 break;
     103         210 :         case SMB_ACL_TYPE_DEFAULT:
     104         210 :                 acl_type = ACL_TYPE_DEFAULT;
     105         210 :                 break;
     106           0 :         default:
     107           0 :                 acl_free(acl);
     108           0 :                 errno = EINVAL;
     109           0 :                 return -1;
     110             :         }
     111             : 
     112         938 :         if (!fsp->fsp_flags.is_pathref && type == SMB_ACL_TYPE_ACCESS) {
     113         726 :                 res = acl_set_fd(fd, acl);
     114         212 :         } else if (fsp->fsp_flags.have_proc_fds) {
     115         212 :                 const char *proc_fd_path = NULL;
     116             :                 char buf[PATH_MAX];
     117             : 
     118         212 :                 proc_fd_path = sys_proc_fd_path(fd, buf, sizeof(buf));
     119         212 :                 if (proc_fd_path == NULL) {
     120           0 :                         acl_free(acl);
     121           0 :                         return -1;
     122             :                 }
     123         212 :                 res = acl_set_file(proc_fd_path, acl_type, acl);
     124             :         } else {
     125             :                 /*
     126             :                  * This is no longer a handle based call.
     127             :                  */
     128           0 :                 res = acl_set_file(fsp->fsp_name->base_name,
     129             :                                    acl_type,
     130             :                                    acl);
     131             :         }
     132             : 
     133         938 :         acl_free(acl);
     134         938 :         return res;
     135             : }
     136             : 
     137           0 : int posixacl_sys_acl_delete_def_fd(vfs_handle_struct *handle,
     138             :                                 files_struct *fsp)
     139             : {
     140           0 :         if (fsp->fsp_flags.have_proc_fds) {
     141           0 :                 int fd = fsp_get_pathref_fd(fsp);
     142           0 :                 const char *proc_fd_path = NULL;
     143             :                 char buf[PATH_MAX];
     144             : 
     145           0 :                 proc_fd_path = sys_proc_fd_path(fd, buf, sizeof(buf));
     146           0 :                 if (proc_fd_path == NULL) {
     147           0 :                         return -1;
     148             :                 }
     149           0 :                 return acl_delete_def_file(proc_fd_path);
     150             :         }
     151             : 
     152             :         /*
     153             :          * This is no longer a handle based call.
     154             :          */
     155           0 :         return acl_delete_def_file(fsp->fsp_name->base_name);
     156             : }
     157             : 
     158             : /* private functions */
     159             : 
     160      544618 : static bool smb_ace_to_internal(acl_entry_t posix_ace,
     161             :                                 struct smb_acl_entry *ace)
     162             : {
     163             :         acl_tag_t tag;
     164             :         acl_permset_t permset;
     165             : 
     166      544618 :         if (acl_get_tag_type(posix_ace, &tag) != 0) {
     167           0 :                 DEBUG(0, ("smb_acl_get_tag_type failed\n"));
     168           0 :                 return False;
     169             :         }
     170             : 
     171      544618 :         switch(tag) {
     172       19614 :         case ACL_USER:
     173       19614 :                 ace->a_type = SMB_ACL_USER;
     174       19614 :                 break;
     175      156756 :         case ACL_USER_OBJ:
     176      156756 :                 ace->a_type = SMB_ACL_USER_OBJ;
     177      156756 :                 break;
     178       35122 :         case ACL_GROUP:
     179       35122 :                 ace->a_type = SMB_ACL_GROUP;
     180       35122 :                 break;
     181      156756 :         case ACL_GROUP_OBJ:
     182      156756 :                 ace->a_type = SMB_ACL_GROUP_OBJ;
     183      156756 :                 break;
     184      156756 :         case ACL_OTHER:
     185      156756 :                 ace->a_type = SMB_ACL_OTHER;
     186      156756 :                 break;
     187       19614 :         case ACL_MASK:
     188       19614 :                 ace->a_type = SMB_ACL_MASK;
     189       19614 :                 break;
     190             : #ifdef HAVE_ACL_EVERYONE
     191             :         case ACL_EVERYONE:
     192             :                 DEBUG(1, ("ACL tag type ACL_EVERYONE. FreeBSD with ZFS? Use 'vfs objects = zfsacl'\n"));
     193             :                 return false;
     194             : #endif
     195           0 :         default:
     196           0 :                 DEBUG(0, ("unknown tag type %d\n", (unsigned int)tag));
     197           0 :                 return False;
     198             :         }
     199      544618 :         switch(ace->a_type) {
     200       19614 :         case SMB_ACL_USER: {
     201       19614 :                 uid_t *puid = (uid_t *)acl_get_qualifier(posix_ace);
     202       19614 :                 if (puid == NULL) {
     203           0 :                         DEBUG(0, ("smb_acl_get_qualifier failed\n"));
     204           0 :                         return False;
     205             :                 }
     206       19614 :                 ace->info.user.uid = *puid;
     207       19614 :                 acl_free(puid);
     208       19614 :                 break;
     209             :         }
     210             : 
     211       35122 :         case SMB_ACL_GROUP: {
     212       35122 :                 gid_t *pgid = (uid_t *)acl_get_qualifier(posix_ace);
     213       35122 :                 if (pgid == NULL) {
     214           0 :                         DEBUG(0, ("smb_acl_get_qualifier failed\n"));
     215           0 :                         return False;
     216             :                 }
     217       35122 :                 ace->info.group.gid = *pgid;
     218       35122 :                 acl_free(pgid);
     219       35122 :                 break;
     220             :         }
     221      489882 :         default:
     222      489882 :                 break;
     223             :         }
     224      544618 :         if (acl_get_permset(posix_ace, &permset) != 0) {
     225           0 :                 DEBUG(0, ("smb_acl_get_mode failed\n"));
     226           0 :                 return False;
     227             :         }
     228      544618 :         ace->a_perm = 0;
     229             : #ifdef HAVE_ACL_GET_PERM_NP
     230             :         ace->a_perm |= (acl_get_perm_np(permset, ACL_READ) ? SMB_ACL_READ : 0);
     231             :         ace->a_perm |= (acl_get_perm_np(permset, ACL_WRITE) ? SMB_ACL_WRITE : 0);
     232             :         ace->a_perm |= (acl_get_perm_np(permset, ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
     233             : #else
     234      544618 :         ace->a_perm |= (acl_get_perm(permset, ACL_READ) ? SMB_ACL_READ : 0);
     235      544618 :         ace->a_perm |= (acl_get_perm(permset, ACL_WRITE) ? SMB_ACL_WRITE : 0);
     236      544618 :         ace->a_perm |= (acl_get_perm(permset, ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
     237             : #endif
     238      544618 :         return True;
     239             : }
     240             : 
     241      206302 : static struct smb_acl_t *smb_acl_to_internal(acl_t acl, TALLOC_CTX *mem_ctx)
     242             : {
     243      206302 :         struct smb_acl_t *result = sys_acl_init(mem_ctx);
     244      206302 :         int entry_id = ACL_FIRST_ENTRY;
     245             :         acl_entry_t e;
     246      206302 :         if (result == NULL) {
     247           0 :                 return NULL;
     248             :         }
     249      957127 :         while (acl_get_entry(acl, entry_id, &e) == 1) {
     250             : 
     251      544618 :                 entry_id = ACL_NEXT_ENTRY;
     252             : 
     253      544618 :                 result->acl = talloc_realloc(result, result->acl,
     254             :                                              struct smb_acl_entry, result->count+1);
     255      544618 :                 if (result->acl == NULL) {
     256           0 :                         TALLOC_FREE(result);
     257           0 :                         DEBUG(0, ("talloc_realloc failed\n"));
     258           0 :                         errno = ENOMEM;
     259           0 :                         return NULL;
     260             :                 }
     261             : 
     262      544618 :                 if (!smb_ace_to_internal(e, &result->acl[result->count])) {
     263           0 :                         TALLOC_FREE(result);
     264           0 :                         return NULL;
     265             :                 }
     266             : 
     267      544618 :                 result->count += 1;
     268             :         }
     269      206302 :         return result;
     270             : }
     271             : 
     272        6353 : static int smb_acl_set_mode(acl_entry_t entry, SMB_ACL_PERM_T perm)
     273             : {
     274             :         int ret;
     275             :         acl_permset_t permset;
     276             : 
     277        6353 :         if ((ret = acl_get_permset(entry, &permset)) != 0) {
     278           0 :                 return ret;
     279             :         }
     280        6353 :         if ((ret = acl_clear_perms(permset)) != 0) {
     281           0 :                 return ret;
     282             :         }
     283       12704 :         if ((perm & SMB_ACL_READ) &&
     284        6351 :             ((ret = acl_add_perm(permset, ACL_READ)) != 0)) {
     285           0 :                 return ret;
     286             :         }
     287        9178 :         if ((perm & SMB_ACL_WRITE) &&
     288        2825 :             ((ret = acl_add_perm(permset, ACL_WRITE)) != 0)) {
     289           0 :                 return ret;
     290             :         }
     291       12698 :         if ((perm & SMB_ACL_EXECUTE) &&
     292        6345 :             ((ret = acl_add_perm(permset, ACL_EXECUTE)) != 0)) {
     293           0 :                 return ret;
     294             :         }
     295             : 
     296        6350 :         return 0;
     297             : }
     298             : 
     299         939 : static acl_t smb_acl_to_posix(const struct smb_acl_t *acl)
     300             : {
     301             :         acl_t result;
     302             :         int i;
     303             : 
     304         939 :         result = acl_init(acl->count);
     305         939 :         if (result == NULL) {
     306           0 :                 DEBUG(10, ("acl_init failed\n"));
     307           0 :                 return NULL;
     308             :         }
     309             : 
     310       14583 :         for (i=0; i<acl->count; i++) {
     311        6353 :                 const struct smb_acl_entry *entry = &acl->acl[i];
     312             :                 acl_entry_t e;
     313             :                 acl_tag_t tag;
     314             : 
     315        6353 :                 if (acl_create_entry(&result, &e) != 0) {
     316           0 :                         DEBUG(1, ("acl_create_entry failed: %s\n",
     317             :                                   strerror(errno)));
     318           0 :                         goto fail;
     319             :                 }
     320             : 
     321        6353 :                 switch (entry->a_type) {
     322         938 :                 case SMB_ACL_USER:
     323         938 :                         tag = ACL_USER;
     324         938 :                         break;
     325         939 :                 case SMB_ACL_USER_OBJ:
     326         939 :                         tag = ACL_USER_OBJ;
     327         939 :                         break;
     328        1660 :                 case SMB_ACL_GROUP:
     329        1660 :                         tag = ACL_GROUP;
     330        1660 :                         break;
     331         939 :                 case SMB_ACL_GROUP_OBJ:
     332         939 :                         tag = ACL_GROUP_OBJ;
     333         939 :                         break;
     334         939 :                 case SMB_ACL_OTHER:
     335         939 :                         tag = ACL_OTHER;
     336         939 :                         break;
     337         938 :                 case SMB_ACL_MASK:
     338         938 :                         tag = ACL_MASK;
     339         938 :                         break;
     340           0 :                 default:
     341           0 :                         DEBUG(1, ("Unknown tag value %d\n", entry->a_type));
     342           0 :                         goto fail;
     343             :                 }
     344             : 
     345        6353 :                 if (acl_set_tag_type(e, tag) != 0) {
     346           0 :                         DEBUG(10, ("acl_set_tag_type(%d) failed: %s\n",
     347             :                                    tag, strerror(errno)));
     348           0 :                         goto fail;
     349             :                 }
     350             : 
     351        6353 :                 switch (entry->a_type) {
     352         938 :                 case SMB_ACL_USER:
     353         938 :                         if (acl_set_qualifier(e, &entry->info.user.uid) != 0) {
     354           0 :                                 DEBUG(1, ("acl_set_qualifiier failed: %s\n",
     355             :                                           strerror(errno)));
     356           0 :                                 goto fail;
     357             :                         }
     358         938 :                         break;
     359        1660 :                 case SMB_ACL_GROUP:
     360        1660 :                         if (acl_set_qualifier(e, &entry->info.group.gid) != 0) {
     361           0 :                                 DEBUG(1, ("acl_set_qualifiier failed: %s\n",
     362             :                                           strerror(errno)));
     363           0 :                                 goto fail;
     364             :                         }
     365        1660 :                         break;
     366        3752 :                 default:        /* Shut up, compiler! :-) */
     367        3752 :                         break;
     368             :                 }
     369             : 
     370        6353 :                 if (smb_acl_set_mode(e, entry->a_perm) != 0) {
     371           0 :                         goto fail;
     372             :                 }
     373             :         }
     374             : 
     375         939 :         if (acl_valid(result) != 0) {
     376           0 :                 char *acl_string = sys_acl_to_text(acl, NULL);
     377           0 :                 DEBUG(0, ("smb_acl_to_posix: ACL %s is invalid for set (%s)\n",
     378             :                           acl_string, strerror(errno)));
     379           0 :                 SAFE_FREE(acl_string);
     380           0 :                 goto fail;
     381             :         }
     382             : 
     383         939 :         return result;
     384             : 
     385           0 :  fail:
     386           0 :         if (result != NULL) {
     387           0 :                 acl_free(result);
     388             :         }
     389           0 :         return NULL;
     390             : }
     391             : 
     392             : /* VFS operations structure */
     393             : 
     394             : static struct vfs_fn_pointers posixacl_fns = {
     395             :         .sys_acl_get_fd_fn = posixacl_sys_acl_get_fd,
     396             :         .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
     397             :         .sys_acl_set_fd_fn = posixacl_sys_acl_set_fd,
     398             :         .sys_acl_delete_def_fd_fn = posixacl_sys_acl_delete_def_fd,
     399             : };
     400             : 
     401             : static_decl_vfs;
     402       25301 : NTSTATUS vfs_posixacl_init(TALLOC_CTX *ctx)
     403             : {
     404       25301 :         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "posixacl",
     405             :                                 &posixacl_fns);
     406             : }

Generated by: LCOV version 1.13