1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2017, Fedor Uporov 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <sys/kernel.h> 36 #include <sys/malloc.h> 37 #include <sys/vnode.h> 38 #include <sys/bio.h> 39 #include <sys/buf.h> 40 #include <sys/endian.h> 41 #include <sys/conf.h> 42 #include <sys/mount.h> 43 #include <sys/extattr.h> 44 45 #include <fs/ext2fs/fs.h> 46 #include <fs/ext2fs/ext2fs.h> 47 #include <fs/ext2fs/inode.h> 48 #include <fs/ext2fs/ext2_acl.h> 49 #include <fs/ext2fs/ext2_extattr.h> 50 #include <fs/ext2fs/ext2_extern.h> 51 #include <fs/ext2fs/ext2_dinode.h> 52 #include <fs/ext2fs/ext2_mount.h> 53 54 #ifdef UFS_ACL 55 56 void 57 ext2_sync_acl_from_inode(struct inode *ip, struct acl *acl) 58 { 59 struct acl_entry *acl_mask, *acl_group_obj; 60 int i; 61 62 /* 63 * Update ACL_USER_OBJ, ACL_OTHER, but simply identify ACL_MASK 64 * and ACL_GROUP_OBJ for use after we know whether ACL_MASK is 65 * present. 66 */ 67 acl_mask = NULL; 68 acl_group_obj = NULL; 69 for (i = 0; i < acl->acl_cnt; i++) { 70 switch (acl->acl_entry[i].ae_tag) { 71 case ACL_USER_OBJ: 72 acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm( 73 ACL_USER_OBJ, ip->i_mode); 74 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; 75 break; 76 77 case ACL_GROUP_OBJ: 78 acl_group_obj = &acl->acl_entry[i]; 79 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; 80 break; 81 82 case ACL_OTHER: 83 acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm( 84 ACL_OTHER, ip->i_mode); 85 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; 86 break; 87 88 case ACL_MASK: 89 acl_mask = &acl->acl_entry[i]; 90 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; 91 break; 92 93 case ACL_USER: 94 case ACL_GROUP: 95 break; 96 97 default: 98 panic("ext2_sync_acl_from_inode(): bad ae_tag"); 99 } 100 } 101 102 if (acl_group_obj == NULL) 103 panic("ext2_sync_acl_from_inode(): no ACL_GROUP_OBJ"); 104 105 if (acl_mask == NULL) { 106 /* 107 * There is no ACL_MASK, so update ACL_GROUP_OBJ. 108 */ 109 acl_group_obj->ae_perm = acl_posix1e_mode_to_perm( 110 ACL_GROUP_OBJ, ip->i_mode); 111 } else { 112 /* 113 * Update the ACL_MASK entry instead of ACL_GROUP_OBJ. 114 */ 115 acl_mask->ae_perm = acl_posix1e_mode_to_perm(ACL_GROUP_OBJ, 116 ip->i_mode); 117 } 118 } 119 120 static void 121 ext2_sync_inode_from_acl(struct acl *acl, struct inode *ip) 122 { 123 124 ip->i_mode &= ACL_PRESERVE_MASK; 125 ip->i_mode |= acl_posix1e_acl_to_mode(acl); 126 } 127 128 /* 129 * Convert from filesystem to in-memory representation. 130 */ 131 static int 132 ext4_acl_from_disk(char *value, size_t size, struct acl *acl) 133 { 134 const char *end; 135 int n, count, s; 136 137 if (value == NULL) 138 return (EINVAL); 139 140 end = value + size; 141 142 if (((struct ext2_acl_header *)value)->a_version != EXT4_ACL_VERSION) 143 return (EINVAL); 144 145 if (size < sizeof(struct ext2_acl_header)) 146 return (EINVAL); 147 148 s = size - sizeof(struct ext2_acl_header); 149 s -= 4 * sizeof(struct ext2_acl_entry_short); 150 if (s < 0) 151 if ((size - sizeof(struct ext2_acl_header)) % 152 sizeof(struct ext2_acl_entry_short)) 153 count = -1; 154 else 155 count = (size - sizeof(struct ext2_acl_header)) / 156 sizeof(struct ext2_acl_entry_short); 157 else 158 if (s % sizeof(struct ext2_acl_entry)) 159 count = -1; 160 else 161 count = s / sizeof(struct ext2_acl_entry) + 4; 162 163 if (count <= 0 || count > acl->acl_maxcnt) 164 return (EINVAL); 165 166 value = value + sizeof(struct ext2_acl_header); 167 168 for (n = 0; n < count; n++) { 169 struct ext2_acl_entry *entry = (struct ext2_acl_entry *)value; 170 if ((char *)value + sizeof(struct ext2_acl_entry_short) > end) 171 return (EINVAL); 172 173 acl->acl_entry[n].ae_tag = entry->ae_tag; 174 acl->acl_entry[n].ae_perm = entry->ae_perm; 175 176 switch (acl->acl_entry[n].ae_tag) { 177 case ACL_USER_OBJ: 178 case ACL_GROUP_OBJ: 179 case ACL_MASK: 180 case ACL_OTHER: 181 value = (char *)value + sizeof(struct ext2_acl_entry_short); 182 break; 183 184 case ACL_USER: 185 value = (char *)value + sizeof(struct ext2_acl_entry); 186 if ((char *)value > end) 187 return (EINVAL); 188 189 acl->acl_entry[n].ae_id = entry->ae_id; 190 break; 191 192 case ACL_GROUP: 193 value = (char *)value + sizeof(struct ext2_acl_entry); 194 if ((char *)value > end) 195 return (EINVAL); 196 197 acl->acl_entry[n].ae_id = entry->ae_id; 198 break; 199 200 default: 201 return (EINVAL); 202 } 203 } 204 205 if (value != end) 206 return (EINVAL); 207 208 acl->acl_cnt = count; 209 210 return (0); 211 } 212 213 static int 214 ext2_getacl_posix1e(struct vop_getacl_args *ap) 215 { 216 int attrnamespace; 217 const char *attrname; 218 char *value; 219 int len; 220 int error; 221 222 switch (ap->a_type) { 223 case ACL_TYPE_DEFAULT: 224 attrnamespace = POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE; 225 attrname = POSIX1E_ACL_DEFAULT_EXTATTR_NAME; 226 break; 227 case ACL_TYPE_ACCESS: 228 attrnamespace = POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE; 229 attrname = POSIX1E_ACL_ACCESS_EXTATTR_NAME; 230 break; 231 default: 232 return (EINVAL); 233 } 234 235 len = sizeof(*ap->a_aclp) + sizeof(struct ext2_acl_header); 236 value = malloc(len, M_ACL, M_WAITOK); 237 if (!value) 238 return (ENOMEM); 239 240 error = vn_extattr_get(ap->a_vp, IO_NODELOCKED, attrnamespace, attrname, 241 &len, value, ap->a_td); 242 if (error == ENOATTR) { 243 switch (ap->a_type) { 244 case ACL_TYPE_ACCESS: 245 ap->a_aclp->acl_cnt = 3; 246 ap->a_aclp->acl_entry[0].ae_tag = ACL_USER_OBJ; 247 ap->a_aclp->acl_entry[0].ae_id = ACL_UNDEFINED_ID; 248 ap->a_aclp->acl_entry[0].ae_perm = ACL_PERM_NONE; 249 ap->a_aclp->acl_entry[1].ae_tag = ACL_GROUP_OBJ; 250 ap->a_aclp->acl_entry[1].ae_id = ACL_UNDEFINED_ID; 251 ap->a_aclp->acl_entry[1].ae_perm = ACL_PERM_NONE; 252 ap->a_aclp->acl_entry[2].ae_tag = ACL_OTHER; 253 ap->a_aclp->acl_entry[2].ae_id = ACL_UNDEFINED_ID; 254 ap->a_aclp->acl_entry[2].ae_perm = ACL_PERM_NONE; 255 break; 256 257 case ACL_TYPE_DEFAULT: 258 ap->a_aclp->acl_cnt = 0; 259 break; 260 } 261 } else if (error != 0) 262 goto out; 263 264 if (!error) { 265 error = ext4_acl_from_disk(value, len, ap->a_aclp); 266 if (error) 267 goto out; 268 } 269 270 if (error == ENOATTR) 271 error = 0; 272 273 if (ap->a_type == ACL_TYPE_ACCESS) 274 ext2_sync_acl_from_inode(VTOI(ap->a_vp), ap->a_aclp); 275 276 out: 277 free(value, M_TEMP); 278 return (error); 279 } 280 281 int 282 ext2_getacl(struct vop_getacl_args *ap) 283 { 284 285 if (((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) || 286 ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) != 0)) 287 return (EOPNOTSUPP); 288 289 if (ap->a_type == ACL_TYPE_NFS4) 290 return (ENOTSUP); 291 292 return (ext2_getacl_posix1e(ap)); 293 } 294 295 /* 296 * Convert from in-memory to filesystem representation. 297 */ 298 static int 299 ext4_acl_to_disk(const struct acl *acl, size_t *size, char *value) 300 { 301 struct ext2_acl_header *ext_acl; 302 int disk_size; 303 char *e; 304 size_t n; 305 306 if (acl->acl_cnt <= 4) 307 disk_size = sizeof(struct ext2_acl_header) + 308 acl->acl_cnt * sizeof(struct ext2_acl_entry_short); 309 else 310 disk_size = sizeof(struct ext2_acl_header) + 311 4 * sizeof(struct ext2_acl_entry_short) + 312 (acl->acl_cnt - 4) * sizeof(struct ext2_acl_entry); 313 314 if (disk_size > *size) 315 return (EINVAL); 316 317 *size = disk_size; 318 ext_acl = (struct ext2_acl_header *)value; 319 320 ext_acl->a_version = EXT4_ACL_VERSION; 321 e = (char *)ext_acl + sizeof(struct ext2_acl_header); 322 for (n = 0; n < acl->acl_cnt; n++) { 323 const struct acl_entry *acl_e = &acl->acl_entry[n]; 324 struct ext2_acl_entry *entry = (struct ext2_acl_entry *)e; 325 entry->ae_tag = acl_e->ae_tag; 326 entry->ae_perm = acl_e->ae_perm; 327 switch (acl_e->ae_tag) { 328 case ACL_USER: 329 entry->ae_id = acl_e->ae_id; 330 e += sizeof(struct ext2_acl_entry); 331 break; 332 333 case ACL_GROUP: 334 entry->ae_id = acl_e->ae_id; 335 e += sizeof(struct ext2_acl_entry); 336 break; 337 338 case ACL_USER_OBJ: 339 case ACL_GROUP_OBJ: 340 case ACL_MASK: 341 case ACL_OTHER: 342 e += sizeof(struct ext2_acl_entry_short); 343 break; 344 345 default: 346 return (EINVAL); 347 } 348 } 349 350 return (0); 351 } 352 353 static int 354 ext2_setacl_posix1e(struct vop_setacl_args *ap) 355 { 356 struct inode *ip = VTOI(ap->a_vp); 357 char *value; 358 size_t len; 359 int error; 360 361 if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) 362 return (EINVAL); 363 364 /* 365 * If this is a set operation rather than a delete operation, 366 * invoke VOP_ACLCHECK() on the passed ACL to determine if it is 367 * valid for the target. This will include a check on ap->a_type. 368 */ 369 if (ap->a_aclp != NULL) { 370 /* 371 * Set operation. 372 */ 373 error = VOP_ACLCHECK(ap->a_vp, ap->a_type, ap->a_aclp, 374 ap->a_cred, ap->a_td); 375 if (error) 376 return (error); 377 } else { 378 /* 379 * Delete operation. 380 * POSIX.1e allows only deletion of the default ACL on a 381 * directory (ACL_TYPE_DEFAULT). 382 */ 383 if (ap->a_type != ACL_TYPE_DEFAULT) 384 return (EINVAL); 385 if (ap->a_vp->v_type != VDIR) 386 return (ENOTDIR); 387 } 388 389 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 390 return (EROFS); 391 392 /* 393 * Authorize the ACL operation. 394 */ 395 if (ip->i_flags & (IMMUTABLE | APPEND)) 396 return (EPERM); 397 398 /* 399 * Must hold VADMIN (be file owner) or have appropriate privilege. 400 */ 401 if ((error = VOP_ACCESS(ap->a_vp, VADMIN, ap->a_cred, ap->a_td))) 402 return (error); 403 404 switch (ap->a_type) { 405 case ACL_TYPE_ACCESS: 406 len = sizeof(*ap->a_aclp) + sizeof(struct ext2_acl_header); 407 value = malloc(len, M_ACL, M_WAITOK | M_ZERO); 408 error = ext4_acl_to_disk(ap->a_aclp, &len, value); 409 if (error == 0) 410 error = vn_extattr_set(ap->a_vp, IO_NODELOCKED, 411 POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE, 412 POSIX1E_ACL_ACCESS_EXTATTR_NAME, len, 413 value, ap->a_td); 414 415 free(value, M_ACL); 416 break; 417 418 case ACL_TYPE_DEFAULT: 419 if (ap->a_aclp == NULL) { 420 error = vn_extattr_rm(ap->a_vp, IO_NODELOCKED, 421 POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE, 422 POSIX1E_ACL_DEFAULT_EXTATTR_NAME, ap->a_td); 423 424 /* 425 * Attempting to delete a non-present default ACL 426 * will return success for portability purposes. 427 * (TRIX) 428 * 429 * XXX: Note that since we can't distinguish 430 * "that EA is not supported" from "that EA is not 431 * defined", the success case here overlaps the 432 * the ENOATTR->EOPNOTSUPP case below. 433 */ 434 if (error == ENOATTR) 435 error = 0; 436 } else { 437 len = sizeof(*ap->a_aclp) + sizeof(struct ext2_acl_header); 438 value = malloc(len, M_ACL, M_WAITOK | M_ZERO); 439 error = ext4_acl_to_disk(ap->a_aclp, &len, value); 440 if (error == 0) 441 error = vn_extattr_set(ap->a_vp, IO_NODELOCKED, 442 POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE, 443 POSIX1E_ACL_DEFAULT_EXTATTR_NAME, len, 444 value, ap->a_td); 445 446 free(value, M_ACL); 447 } 448 break; 449 450 default: 451 error = EINVAL; 452 } 453 454 /* 455 * Map lack of attribute definition in UFS_EXTATTR into lack of 456 * support for ACLs on the filesystem. 457 */ 458 if (error == ENOATTR) 459 return (EOPNOTSUPP); 460 461 if (error != 0) 462 return (error); 463 464 if (ap->a_type == ACL_TYPE_ACCESS) { 465 /* 466 * Now that the EA is successfully updated, update the 467 * inode and mark it as changed. 468 */ 469 ext2_sync_inode_from_acl(ap->a_aclp, ip); 470 ip->i_flag |= IN_CHANGE; 471 error = ext2_update(ip->i_vnode, 1); 472 } 473 474 VN_KNOTE_UNLOCKED(ap->a_vp, NOTE_ATTRIB); 475 476 return (error); 477 } 478 479 int 480 ext2_setacl(struct vop_setacl_args *ap) 481 { 482 if (((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) || 483 ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) != 0)) 484 return (EOPNOTSUPP); 485 486 if (ap->a_type == ACL_TYPE_NFS4) 487 return (ENOTSUP); 488 489 return (ext2_setacl_posix1e(ap)); 490 } 491 492 /* 493 * Check the validity of an ACL for a file. 494 */ 495 int 496 ext2_aclcheck(struct vop_aclcheck_args *ap) 497 { 498 499 if (((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) || 500 ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) != 0)) 501 return (EOPNOTSUPP); 502 503 if (ap->a_type == ACL_TYPE_NFS4) 504 return (ENOTSUP); 505 506 if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) 507 return (EINVAL); 508 509 /* 510 * Verify we understand this type of ACL, and that it applies 511 * to this kind of object. 512 * Rely on the acl_posix1e_check() routine to verify the contents. 513 */ 514 switch (ap->a_type) { 515 case ACL_TYPE_ACCESS: 516 break; 517 518 case ACL_TYPE_DEFAULT: 519 if (ap->a_vp->v_type != VDIR) 520 return (EINVAL); 521 break; 522 523 default: 524 return (EINVAL); 525 } 526 527 return (acl_posix1e_check(ap->a_aclp)); 528 } 529 530 #endif /* UFS_ACL */ 531