Ignore:
Timestamp:
Nov 26, 2007, 9:24:27 AM (18 years ago)
Author:
Paul Smedley
Message:

Update source to 3.0.27a

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/samba-3.0/source/smbd/posix_acls.c

    r71 r105  
    41464146
    41474147/****************************************************************************
    4148  Check for POSIX group ACLs. If none use stat entry.
    4149  Return -1 if no match, 0 if match and denied, 1 if match and allowed.
    4150 ****************************************************************************/
    4151 
    4152 static int check_posix_acl_group_access(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask)
    4153 {
    4154         SMB_ACL_T posix_acl = NULL;
    4155         int entry_id = SMB_ACL_FIRST_ENTRY;
    4156         SMB_ACL_ENTRY_T entry;
    4157         int i;
    4158         BOOL seen_mask = False;
    4159         BOOL seen_owning_group = False;
    4160         int ret = -1;
    4161         gid_t cu_gid;
    4162 
    4163         DEBUG(10,("check_posix_acl_group_access: requesting 0x%x on file %s\n",
    4164                 (unsigned int)access_mask, fname ));
    4165 
    4166         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS)) == NULL) {
    4167                 goto check_stat;
    4168         }
    4169 
    4170         /* First ensure the group mask allows group access. */
    4171         /* Also check any user entries (these take preference over group). */
    4172 
    4173         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
    4174                 SMB_ACL_TAG_T tagtype;
    4175                 SMB_ACL_PERMSET_T permset;
    4176                 int have_write = -1;
    4177                 int have_read = -1;
    4178 
    4179                 /* get_next... */
    4180                 if (entry_id == SMB_ACL_FIRST_ENTRY)
    4181                         entry_id = SMB_ACL_NEXT_ENTRY;
    4182 
    4183                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
    4184                         goto check_stat;
    4185                 }
    4186 
    4187                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
    4188                         goto check_stat;
    4189                 }
    4190 
    4191                 have_read = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ);
    4192                 if (have_read == -1) {
    4193                         goto check_stat;
    4194                 }
    4195 
    4196                 have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE);
    4197                 if (have_write == -1) {
    4198                         goto check_stat;
    4199                 }
    4200 
    4201                 /*
    4202                  * Solaris returns 2 for this if write is available.
    4203                  * canonicalize to 0 or 1.
    4204                  */     
    4205                 have_write = (have_write ? 1 : 0);
    4206                 have_read = (have_read ? 1 : 0);
    4207 
    4208                 switch(tagtype) {
    4209                         case SMB_ACL_MASK:
    4210                                 seen_mask = True;
    4211                                 switch (access_mask) {
    4212                                         case FILE_READ_DATA:
    4213                                                 if (!have_read) {
    4214                                                         ret = -1;
    4215                                                         DEBUG(10,("check_posix_acl_group_access: file %s "
    4216                                                                 "refusing read due to mask.\n", fname));
    4217                                                         goto done;
    4218                                                 }
    4219                                                 break;
    4220                                         case FILE_WRITE_DATA:
    4221                                                 if (!have_write) {
    4222                                                         ret = -1;
    4223                                                         DEBUG(10,("check_posix_acl_group_access: file %s "
    4224                                                                 "refusing write due to mask.\n", fname));
    4225                                                         goto done;
    4226                                                 }
    4227                                                 break;
    4228                                         default: /* FILE_READ_DATA|FILE_WRITE_DATA */
    4229                                                 if (!have_write || !have_read) {
    4230                                                         ret = -1;
    4231                                                         DEBUG(10,("check_posix_acl_group_access: file %s "
    4232                                                                 "refusing read/write due to mask.\n", fname));
    4233                                                         goto done;
    4234                                                 }
    4235                                                 break;
    4236                                 }
    4237                                 break;
    4238                         case SMB_ACL_USER:
    4239                         {
    4240                                 /* Check against current_user.ut.uid. */
    4241                                 uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
    4242                                 if (puid == NULL) {
    4243                                         goto check_stat;
    4244                                 }
    4245                                 if (current_user.ut.uid == *puid) {
    4246                                         /* We have a uid match but we must ensure we have seen the acl mask. */
    4247                                         switch (access_mask) {
    4248                                                 case FILE_READ_DATA:
    4249                                                         ret = have_read;
    4250                                                         break;
    4251                                                 case FILE_WRITE_DATA:
    4252                                                         ret = have_write;
    4253                                                         break;
    4254                                                 default: /* FILE_READ_DATA|FILE_WRITE_DATA */
    4255                                                         ret = (have_write & have_read);
    4256                                                         break;
    4257                                         }
    4258                                         DEBUG(10,("check_posix_acl_group_access: file %s "
    4259                                                 "match on user %u -> %s.\n",
    4260                                                 fname, (unsigned int)*puid,
    4261                                                 ret ? "can access" : "cannot access"));
    4262                                         if (seen_mask) {
    4263                                                 goto done;
    4264                                         }
    4265                                 }
    4266                                 break;
    4267                         }
    4268                         default:
    4269                                 continue;
    4270                 }
    4271         }
    4272 
    4273         /* If ret is anything other than -1 we matched on a user entry. */
    4274         if (ret != -1) {
     4148 Helper function that gets a security descriptor by connection and
     4149 file name.
     4150 NOTE: This is transitional, in the sense that SMB_VFS_GET_NT_ACL really
     4151 should *not* get a files_struct pointer but a connection_struct ptr
     4152 (automatic by the vfs handle) and the file name and _use_ that!
     4153****************************************************************************/
     4154static NTSTATUS conn_get_nt_acl(TALLOC_CTX *mem_ctx,
     4155                                struct connection_struct *conn,
     4156                                const char *fname,
     4157                                SMB_STRUCT_STAT *psbuf,
     4158                                struct security_descriptor_info **psd)
     4159{
     4160        NTSTATUS status;
     4161        struct files_struct *fsp = NULL;
     4162        struct security_descriptor_info *secdesc = NULL;
     4163        size_t secdesc_size;
     4164
     4165        if (!VALID_STAT(*psbuf)) {
     4166                if (SMB_VFS_STAT(conn, fname, psbuf) != 0) {
     4167                        return map_nt_error_from_unix(errno);
     4168                }
     4169        }
     4170
     4171        /* fake a files_struct ptr: */
     4172
     4173        if (S_ISDIR(psbuf->st_mode)) {
     4174                status = open_directory(conn, fname, psbuf,
     4175                                        READ_CONTROL_ACCESS,
     4176                                        FILE_SHARE_READ|FILE_SHARE_WRITE,
     4177                                        FILE_OPEN,
     4178                                        0,
     4179                                        FILE_ATTRIBUTE_DIRECTORY,
     4180                                        NULL, &fsp);
     4181        }
     4182        else {
     4183                status = open_file_stat(conn, fname, psbuf, &fsp);
     4184        }
     4185
     4186        if (!NT_STATUS_IS_OK(status)) {
     4187                DEBUG(3, ("Unable to open file %s: %s\n", fname,
     4188                          nt_errstr(status)));
     4189                return status;
     4190        }
     4191
     4192        secdesc_size = SMB_VFS_GET_NT_ACL(fsp, fname,
     4193                                          (OWNER_SECURITY_INFORMATION |
     4194                                           GROUP_SECURITY_INFORMATION |
     4195                                           DACL_SECURITY_INFORMATION),
     4196                                          &secdesc);
     4197        if (secdesc_size == 0) {
     4198                DEBUG(5, ("Unable to get NT ACL for file %s\n", fname));
     4199                status = NT_STATUS_ACCESS_DENIED;
    42754200                goto done;
    42764201        }
    42774202
    4278         /* Next check all group entries. */
    4279         entry_id = SMB_ACL_FIRST_ENTRY;
    4280         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
    4281                 SMB_ACL_TAG_T tagtype;
    4282                 SMB_ACL_PERMSET_T permset;
    4283                 int have_write = -1;
    4284                 int have_read = -1;
    4285 
    4286                 /* get_next... */
    4287                 if (entry_id == SMB_ACL_FIRST_ENTRY)
    4288                         entry_id = SMB_ACL_NEXT_ENTRY;
    4289 
    4290                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
    4291                         goto check_stat;
    4292                 }
    4293 
    4294                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
    4295                         goto check_stat;
    4296                 }
    4297 
    4298                 have_read = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ);
    4299                 if (have_read == -1) {
    4300                         goto check_stat;
    4301                 }
    4302 
    4303                 have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE);
    4304                 if (have_write == -1) {
    4305                         goto check_stat;
    4306                 }
    4307 
    4308                 /*
    4309                  * Solaris returns 2 for this if write is available.
    4310                  * canonicalize to 0 or 1.
    4311                  */     
    4312                 have_write = (have_write ? 1 : 0);
    4313                 have_read = (have_read ? 1 : 0);
    4314 
    4315                 switch(tagtype) {
    4316                         case SMB_ACL_GROUP:
    4317                         case SMB_ACL_GROUP_OBJ:
    4318                         {
    4319                                 gid_t *pgid = NULL;
    4320 
    4321                                 if (tagtype == SMB_ACL_GROUP) {
    4322                                         pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
    4323                                 } else {
    4324                                         seen_owning_group = True;
    4325                                         pgid = &psbuf->st_gid;
    4326                                 }
    4327                                 if (pgid == NULL) {
    4328                                         goto check_stat;
    4329                                 }
    4330 
    4331                                 /*
    4332                                  * Does it match the current effective group
    4333                                  * or supplementary groups ?
    4334                                  */
    4335                                 for (cu_gid = get_current_user_gid_first(&i); cu_gid != (gid_t)-1;
    4336                                                         cu_gid = get_current_user_gid_next(&i)) {
    4337                                         if (cu_gid == *pgid) {
    4338                                                 switch (access_mask) {
    4339                                                         case FILE_READ_DATA:
    4340                                                                 ret = have_read;
    4341                                                                 break;
    4342                                                         case FILE_WRITE_DATA:
    4343                                                                 ret = have_write;
    4344                                                                 break;
    4345                                                         default: /* FILE_READ_DATA|FILE_WRITE_DATA */
    4346                                                                 ret = (have_write & have_read);
    4347                                                                 break;
    4348                                                 }
    4349 
    4350                                                 DEBUG(10,("check_posix_acl_group_access: file %s "
    4351                                                         "match on group %u -> can access.\n",
    4352                                                         fname, (unsigned int)cu_gid ));
    4353 
    4354                                                 /* If we don't have access permission this entry doesn't
    4355                                                         terminate the enumeration of the entries. */
    4356                                                 if (ret) {
    4357                                                         goto done;
    4358                                                 }
    4359                                                 /* But does terminate the group iteration. */
    4360                                                 break;
    4361                                         }
    4362                                 }
    4363                                 break;
    4364                         }
    4365                         default:
    4366                                 continue;
    4367                 }
    4368         }
    4369 
    4370         /* If ret is -1 here we didn't match on the user entry or
    4371            supplemental group entries. */
    4372        
    4373         DEBUG(10,("check_posix_acl_group_access: ret = %d before check_stat:\n", ret));
    4374 
    4375   check_stat:
    4376 
    4377         /*
    4378          * We only check the S_I[RW]GRP permissions if we haven't already
    4379          * seen an owning group SMB_ACL_GROUP_OBJ ace entry. If there is an
    4380          * SMB_ACL_GROUP_OBJ ace entry then the group bits in st_gid are
    4381          * the same as the SMB_ACL_MASK bits, not the SMB_ACL_GROUP_OBJ
    4382          * bits. Thanks to Marc Cousin <mcousin@sigma.fr> for pointing
    4383          * this out. JRA.
    4384          */
    4385 
    4386         if (!seen_owning_group) {
    4387                 /* Do we match on the owning group entry ? */
    4388                 /*
    4389                  * Does it match the current effective group
    4390                  * or supplementary groups ?
    4391                  */
    4392                 for (cu_gid = get_current_user_gid_first(&i); cu_gid != (gid_t)-1;
    4393                                                 cu_gid = get_current_user_gid_next(&i)) {
    4394                         if (cu_gid == psbuf->st_gid) {
    4395                                 switch (access_mask) {
    4396                                         case FILE_READ_DATA:
    4397                                                 ret = (psbuf->st_mode & S_IRGRP) ? 1 : 0;
    4398                                                 break;
    4399                                         case FILE_WRITE_DATA:
    4400                                                 ret = (psbuf->st_mode & S_IWGRP) ? 1 : 0;
    4401                                                 break;
    4402                                         default: /* FILE_READ_DATA|FILE_WRITE_DATA */
    4403                                                 if ((psbuf->st_mode & (S_IWGRP|S_IRGRP)) == (S_IWGRP|S_IRGRP)) {
    4404                                                         ret = 1;
    4405                                                 } else {
    4406                                                         ret = 0;
    4407                                                 }
    4408                                                 break;
    4409                                 }
    4410                                 DEBUG(10,("check_posix_acl_group_access: file %s "
    4411                                         "match on owning group %u -> %s.\n",
    4412                                         fname, (unsigned int)psbuf->st_gid,
    4413                                         ret ? "can access" : "cannot access"));
    4414                                 break;
    4415                         }
    4416                 }
    4417 
    4418                 if (cu_gid == (gid_t)-1) {
    4419                         DEBUG(10,("check_posix_acl_group_access: file %s "
    4420                                 "failed to match on user or group in token (ret = %d).\n",
    4421                                 fname, ret ));
    4422                 }
    4423         }
    4424 
    4425   done:
    4426 
    4427         if (posix_acl) {
    4428                 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
    4429         }
    4430 
    4431         DEBUG(10,("check_posix_acl_group_access: file %s returning (ret = %d).\n", fname, ret ));
    4432         return ret;
     4203        *psd = talloc_move(mem_ctx, &secdesc);
     4204        status = NT_STATUS_OK;
     4205
     4206done:
     4207        close_file(fsp, NORMAL_CLOSE);
     4208        return status;
     4209}
     4210
     4211static BOOL can_access_file_acl(struct connection_struct *conn,
     4212                                const char * fname, SMB_STRUCT_STAT *psbuf,
     4213                                uint32_t access_mask)
     4214{
     4215        BOOL result;
     4216        NTSTATUS status;
     4217        uint32_t access_granted;
     4218        struct security_descriptor_info *secdesc = NULL;
     4219
     4220        status = conn_get_nt_acl(tmp_talloc_ctx(), conn, fname, psbuf, &secdesc);
     4221        if (!NT_STATUS_IS_OK(status)) {
     4222                DEBUG(5, ("Could not get acl: %s\n", nt_errstr(status)));
     4223                return False;
     4224        }
     4225
     4226        result = se_access_check(secdesc, current_user.nt_user_token,
     4227                                 access_mask, &access_granted, &status);
     4228        TALLOC_FREE(secdesc);
     4229        return result;
    44334230}
    44344231
     
    44424239        SMB_STRUCT_STAT sbuf; 
    44434240        pstring dname;
    4444         int ret;
    44454241
    44464242        if (!CAN_WRITE(conn)) {
     
    44534249                return False;
    44544250        }
     4251
     4252        /* fast paths first */
     4253
    44554254        if (!S_ISDIR(sbuf.st_mode)) {
    44564255                return False;
     
    44894288#endif
    44904289
    4491         /* Check group or explicit user acl entry write access. */
    4492         ret = check_posix_acl_group_access(conn, dname, &sbuf, FILE_WRITE_DATA);
    4493         if (ret == 0 || ret == 1) {
    4494                 return ret ? True : False;
    4495         }
    4496 
    4497         /* Finally check other write access. */
    4498         return (sbuf.st_mode & S_IWOTH) ? True : False;
     4290        /* now for ACL checks */
     4291
     4292        return can_access_file_acl(conn, dname, &sbuf, FILE_WRITE_DATA);
    44994293}
    45004294
     
    45074301BOOL can_access_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask)
    45084302{
    4509         int ret;
    4510 
    45114303        if (!(access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))) {
    45124304                return False;
    45134305        }
    45144306        access_mask &= (FILE_READ_DATA|FILE_WRITE_DATA);
     4307
     4308        /* some fast paths first */
    45154309
    45164310        DEBUG(10,("can_access_file: requesting 0x%x on file %s\n",
     
    45504344        }
    45514345
    4552         /* Check group or explicit user acl entry access. */
    4553         ret = check_posix_acl_group_access(conn, fname, psbuf, access_mask);
    4554         if (ret == 0 || ret == 1) {
    4555                 return ret ? True : False;
    4556         }
    4557 
    4558         /* Finally check other access. */
    4559         switch (access_mask) {
    4560                 case FILE_READ_DATA:
    4561                         return (psbuf->st_mode & S_IROTH) ? True : False;
    4562 
    4563                 case FILE_WRITE_DATA:
    4564                         return (psbuf->st_mode & S_IWOTH) ? True : False;
    4565 
    4566                 default: /* FILE_READ_DATA|FILE_WRITE_DATA */
    4567 
    4568                         if ((psbuf->st_mode & (S_IWOTH|S_IROTH)) == (S_IWOTH|S_IROTH)) {
    4569                                 return True;
    4570                         }
    4571         }
    4572         return False;
     4346        /* now for ACL checks */
     4347
     4348        return can_access_file_acl(conn, fname, psbuf, access_mask);
    45734349}
    45744350
Note: See TracChangeset for help on using the changeset viewer.