LCOV - code coverage report
Current view: top level - source3/modules - vfs_posixacl.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 55 212 25.9 %
Date: 2024-06-13 04:01:37 Functions: 4 8 50.0 %

          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          92 : 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          92 :         acl_t acl = NULL;
      43             :         acl_type_t acl_type;
      44             : 
      45          92 :         switch(type) {
      46          52 :         case SMB_ACL_TYPE_ACCESS:
      47          52 :                 acl_type = ACL_TYPE_ACCESS;
      48          52 :                 break;
      49          40 :         case SMB_ACL_TYPE_DEFAULT:
      50          40 :                 acl_type = ACL_TYPE_DEFAULT;
      51          40 :                 break;
      52           0 :         default:
      53           0 :                 errno = EINVAL;
      54           0 :                 return NULL;
      55             :         }
      56          92 :         if (!fsp->fsp_flags.is_pathref && (acl_type == ACL_TYPE_ACCESS)) {
      57             :                 /* POSIX API only allows ACL_TYPE_ACCESS fetched on fd. */
      58          16 :                 acl = acl_get_fd(fsp_get_io_fd(fsp));
      59          76 :         } else if (fsp->fsp_flags.have_proc_fds) {
      60          76 :                 int fd = fsp_get_pathref_fd(fsp);
      61          76 :                 const char *proc_fd_path = NULL;
      62             :                 char buf[PATH_MAX];
      63             : 
      64          76 :                 proc_fd_path = sys_proc_fd_path(fd, buf, sizeof(buf));
      65          76 :                 if (proc_fd_path == NULL) {
      66           0 :                         return NULL;
      67             :                 }
      68             : 
      69          76 :                 acl = acl_get_file(proc_fd_path, acl_type);
      70             :         } else {
      71             :                 /*
      72             :                  * This is no longer a handle based call.
      73             :                  */
      74           0 :                 acl = acl_get_file(fsp->fsp_name->base_name, acl_type);
      75             :         }
      76          92 :         if (acl == NULL) {
      77           0 :                 return NULL;
      78             :         }
      79             : 
      80          92 :         result = smb_acl_to_internal(acl, mem_ctx);
      81          92 :         acl_free(acl);
      82          92 :         return result;
      83             : }
      84             : 
      85           0 : 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           0 :         acl_t acl = smb_acl_to_posix(theacl);
      92             :         acl_type_t acl_type;
      93           0 :         int fd = fsp_get_pathref_fd(fsp);
      94             : 
      95           0 :         if (acl == NULL) {
      96           0 :                 return -1;
      97             :         }
      98             : 
      99           0 :         switch(type) {
     100           0 :         case SMB_ACL_TYPE_ACCESS:
     101           0 :                 acl_type = ACL_TYPE_ACCESS;
     102           0 :                 break;
     103           0 :         case SMB_ACL_TYPE_DEFAULT:
     104           0 :                 acl_type = ACL_TYPE_DEFAULT;
     105           0 :                 break;
     106           0 :         default:
     107           0 :                 acl_free(acl);
     108           0 :                 errno = EINVAL;
     109           0 :                 return -1;
     110             :         }
     111             : 
     112           0 :         if (!fsp->fsp_flags.is_pathref && type == SMB_ACL_TYPE_ACCESS) {
     113           0 :                 res = acl_set_fd(fd, acl);
     114           0 :         } else if (fsp->fsp_flags.have_proc_fds) {
     115           0 :                 const char *proc_fd_path = NULL;
     116             :                 char buf[PATH_MAX];
     117             : 
     118           0 :                 proc_fd_path = sys_proc_fd_path(fd, buf, sizeof(buf));
     119           0 :                 if (proc_fd_path == NULL) {
     120           0 :                         acl_free(acl);
     121           0 :                         return -1;
     122             :                 }
     123           0 :                 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           0 :         acl_free(acl);
     134           0 :         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         156 : 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         156 :         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         156 :         switch(tag) {
     172           0 :         case ACL_USER:
     173           0 :                 ace->a_type = SMB_ACL_USER;
     174           0 :                 break;
     175          52 :         case ACL_USER_OBJ:
     176          52 :                 ace->a_type = SMB_ACL_USER_OBJ;
     177          52 :                 break;
     178           0 :         case ACL_GROUP:
     179           0 :                 ace->a_type = SMB_ACL_GROUP;
     180           0 :                 break;
     181          52 :         case ACL_GROUP_OBJ:
     182          52 :                 ace->a_type = SMB_ACL_GROUP_OBJ;
     183          52 :                 break;
     184          52 :         case ACL_OTHER:
     185          52 :                 ace->a_type = SMB_ACL_OTHER;
     186          52 :                 break;
     187           0 :         case ACL_MASK:
     188           0 :                 ace->a_type = SMB_ACL_MASK;
     189           0 :                 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         156 :         switch(ace->a_type) {
     200           0 :         case SMB_ACL_USER: {
     201           0 :                 uid_t *puid = (uid_t *)acl_get_qualifier(posix_ace);
     202           0 :                 if (puid == NULL) {
     203           0 :                         DEBUG(0, ("smb_acl_get_qualifier failed\n"));
     204           0 :                         return False;
     205             :                 }
     206           0 :                 ace->info.user.uid = *puid;
     207           0 :                 acl_free(puid);
     208           0 :                 break;
     209             :         }
     210             : 
     211           0 :         case SMB_ACL_GROUP: {
     212           0 :                 gid_t *pgid = (uid_t *)acl_get_qualifier(posix_ace);
     213           0 :                 if (pgid == NULL) {
     214           0 :                         DEBUG(0, ("smb_acl_get_qualifier failed\n"));
     215           0 :                         return False;
     216             :                 }
     217           0 :                 ace->info.group.gid = *pgid;
     218           0 :                 acl_free(pgid);
     219           0 :                 break;
     220             :         }
     221         156 :         default:
     222         156 :                 break;
     223             :         }
     224         156 :         if (acl_get_permset(posix_ace, &permset) != 0) {
     225           0 :                 DEBUG(0, ("smb_acl_get_mode failed\n"));
     226           0 :                 return False;
     227             :         }
     228         156 :         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         156 :         ace->a_perm |= (acl_get_perm(permset, ACL_READ) ? SMB_ACL_READ : 0);
     235         156 :         ace->a_perm |= (acl_get_perm(permset, ACL_WRITE) ? SMB_ACL_WRITE : 0);
     236         156 :         ace->a_perm |= (acl_get_perm(permset, ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
     237             : #endif
     238         156 :         return True;
     239             : }
     240             : 
     241          92 : static struct smb_acl_t *smb_acl_to_internal(acl_t acl, TALLOC_CTX *mem_ctx)
     242             : {
     243          92 :         struct smb_acl_t *result = sys_acl_init(mem_ctx);
     244          92 :         int entry_id = ACL_FIRST_ENTRY;
     245             :         acl_entry_t e;
     246          92 :         if (result == NULL) {
     247           0 :                 return NULL;
     248             :         }
     249         294 :         while (acl_get_entry(acl, entry_id, &e) == 1) {
     250             : 
     251         156 :                 entry_id = ACL_NEXT_ENTRY;
     252             : 
     253         156 :                 result->acl = talloc_realloc(result, result->acl,
     254             :                                              struct smb_acl_entry, result->count+1);
     255         156 :                 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         156 :                 if (!smb_ace_to_internal(e, &result->acl[result->count])) {
     263           0 :                         TALLOC_FREE(result);
     264           0 :                         return NULL;
     265             :                 }
     266             : 
     267         156 :                 result->count += 1;
     268             :         }
     269          92 :         return result;
     270             : }
     271             : 
     272           0 : 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           0 :         if ((ret = acl_get_permset(entry, &permset)) != 0) {
     278           0 :                 return ret;
     279             :         }
     280           0 :         if ((ret = acl_clear_perms(permset)) != 0) {
     281           0 :                 return ret;
     282             :         }
     283           0 :         if ((perm & SMB_ACL_READ) &&
     284           0 :             ((ret = acl_add_perm(permset, ACL_READ)) != 0)) {
     285           0 :                 return ret;
     286             :         }
     287           0 :         if ((perm & SMB_ACL_WRITE) &&
     288           0 :             ((ret = acl_add_perm(permset, ACL_WRITE)) != 0)) {
     289           0 :                 return ret;
     290             :         }
     291           0 :         if ((perm & SMB_ACL_EXECUTE) &&
     292           0 :             ((ret = acl_add_perm(permset, ACL_EXECUTE)) != 0)) {
     293           0 :                 return ret;
     294             :         }
     295             : 
     296           0 :         return 0;
     297             : }
     298             : 
     299           0 : static acl_t smb_acl_to_posix(const struct smb_acl_t *acl)
     300             : {
     301             :         acl_t result;
     302             :         int i;
     303             : 
     304           0 :         result = acl_init(acl->count);
     305           0 :         if (result == NULL) {
     306           0 :                 DEBUG(10, ("acl_init failed\n"));
     307           0 :                 return NULL;
     308             :         }
     309             : 
     310           0 :         for (i=0; i<acl->count; i++) {
     311           0 :                 const struct smb_acl_entry *entry = &acl->acl[i];
     312             :                 acl_entry_t e;
     313             :                 acl_tag_t tag;
     314             : 
     315           0 :                 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           0 :                 switch (entry->a_type) {
     322           0 :                 case SMB_ACL_USER:
     323           0 :                         tag = ACL_USER;
     324           0 :                         break;
     325           0 :                 case SMB_ACL_USER_OBJ:
     326           0 :                         tag = ACL_USER_OBJ;
     327           0 :                         break;
     328           0 :                 case SMB_ACL_GROUP:
     329           0 :                         tag = ACL_GROUP;
     330           0 :                         break;
     331           0 :                 case SMB_ACL_GROUP_OBJ:
     332           0 :                         tag = ACL_GROUP_OBJ;
     333           0 :                         break;
     334           0 :                 case SMB_ACL_OTHER:
     335           0 :                         tag = ACL_OTHER;
     336           0 :                         break;
     337           0 :                 case SMB_ACL_MASK:
     338           0 :                         tag = ACL_MASK;
     339           0 :                         break;
     340           0 :                 default:
     341           0 :                         DEBUG(1, ("Unknown tag value %d\n", entry->a_type));
     342           0 :                         goto fail;
     343             :                 }
     344             : 
     345           0 :                 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           0 :                 switch (entry->a_type) {
     352           0 :                 case SMB_ACL_USER:
     353           0 :                         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           0 :                         break;
     359           0 :                 case SMB_ACL_GROUP:
     360           0 :                         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           0 :                         break;
     366           0 :                 default:        /* Shut up, compiler! :-) */
     367           0 :                         break;
     368             :                 }
     369             : 
     370           0 :                 if (smb_acl_set_mode(e, entry->a_perm) != 0) {
     371           0 :                         goto fail;
     372             :                 }
     373             :         }
     374             : 
     375           0 :         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           0 :         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        4875 : NTSTATUS vfs_posixacl_init(TALLOC_CTX *ctx)
     403             : {
     404        4875 :         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "posixacl",
     405             :                                 &posixacl_fns);
     406             : }

Generated by: LCOV version 1.13