Changeset 105 for branches/samba-3.0/source/smbd/posix_acls.c
- Timestamp:
- Nov 26, 2007, 9:24:27 AM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/samba-3.0/source/smbd/posix_acls.c
r71 r105 4146 4146 4147 4147 /**************************************************************************** 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 ****************************************************************************/ 4154 static 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; 4275 4200 goto done; 4276 4201 } 4277 4202 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 4206 done: 4207 close_file(fsp, NORMAL_CLOSE); 4208 return status; 4209 } 4210 4211 static 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; 4433 4230 } 4434 4231 … … 4442 4239 SMB_STRUCT_STAT sbuf; 4443 4240 pstring dname; 4444 int ret;4445 4241 4446 4242 if (!CAN_WRITE(conn)) { … … 4453 4249 return False; 4454 4250 } 4251 4252 /* fast paths first */ 4253 4455 4254 if (!S_ISDIR(sbuf.st_mode)) { 4456 4255 return False; … … 4489 4288 #endif 4490 4289 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); 4499 4293 } 4500 4294 … … 4507 4301 BOOL can_access_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask) 4508 4302 { 4509 int ret;4510 4511 4303 if (!(access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))) { 4512 4304 return False; 4513 4305 } 4514 4306 access_mask &= (FILE_READ_DATA|FILE_WRITE_DATA); 4307 4308 /* some fast paths first */ 4515 4309 4516 4310 DEBUG(10,("can_access_file: requesting 0x%x on file %s\n", … … 4550 4344 } 4551 4345 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); 4573 4349 } 4574 4350
Note:
See TracChangeset
for help on using the changeset viewer.