1 /* 2 * linux/fs/posix_acl.c 3 * 4 * Copyright (C) 2002 by Andreas Gruenbacher <a.gruenbacher@computer.org> 5 * 6 * Fixes from William Schumacher incorporated on 15 March 2001. 7 * (Reported by Charles Bertsch, <CBertsch@microtest.com>). 8 */ 9 10 /* 11 * This file contains generic functions for manipulating 12 * POSIX 1003.1e draft standard 17 ACLs. 13 */ 14 15 #include <linux/kernel.h> 16 #include <linux/slab.h> 17 #include <linux/atomic.h> 18 #include <linux/fs.h> 19 #include <linux/sched.h> 20 #include <linux/posix_acl.h> 21 #include <linux/module.h> 22 23 #include <linux/errno.h> 24 25 EXPORT_SYMBOL(posix_acl_init); 26 EXPORT_SYMBOL(posix_acl_alloc); 27 EXPORT_SYMBOL(posix_acl_valid); 28 EXPORT_SYMBOL(posix_acl_equiv_mode); 29 EXPORT_SYMBOL(posix_acl_from_mode); 30 31 /* 32 * Init a fresh posix_acl 33 */ 34 void 35 posix_acl_init(struct posix_acl *acl, int count) 36 { 37 atomic_set(&acl->a_refcount, 1); 38 acl->a_count = count; 39 } 40 41 /* 42 * Allocate a new ACL with the specified number of entries. 43 */ 44 struct posix_acl * 45 posix_acl_alloc(int count, gfp_t flags) 46 { 47 const size_t size = sizeof(struct posix_acl) + 48 count * sizeof(struct posix_acl_entry); 49 struct posix_acl *acl = kmalloc(size, flags); 50 if (acl) 51 posix_acl_init(acl, count); 52 return acl; 53 } 54 55 /* 56 * Clone an ACL. 57 */ 58 static struct posix_acl * 59 posix_acl_clone(const struct posix_acl *acl, gfp_t flags) 60 { 61 struct posix_acl *clone = NULL; 62 63 if (acl) { 64 int size = sizeof(struct posix_acl) + acl->a_count * 65 sizeof(struct posix_acl_entry); 66 clone = kmemdup(acl, size, flags); 67 if (clone) 68 atomic_set(&clone->a_refcount, 1); 69 } 70 return clone; 71 } 72 73 /* 74 * Check if an acl is valid. Returns 0 if it is, or -E... otherwise. 75 */ 76 int 77 posix_acl_valid(const struct posix_acl *acl) 78 { 79 const struct posix_acl_entry *pa, *pe; 80 int state = ACL_USER_OBJ; 81 unsigned int id = 0; /* keep gcc happy */ 82 int needs_mask = 0; 83 84 FOREACH_ACL_ENTRY(pa, acl, pe) { 85 if (pa->e_perm & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE)) 86 return -EINVAL; 87 switch (pa->e_tag) { 88 case ACL_USER_OBJ: 89 if (state == ACL_USER_OBJ) { 90 id = 0; 91 state = ACL_USER; 92 break; 93 } 94 return -EINVAL; 95 96 case ACL_USER: 97 if (state != ACL_USER) 98 return -EINVAL; 99 if (pa->e_id == ACL_UNDEFINED_ID || 100 pa->e_id < id) 101 return -EINVAL; 102 id = pa->e_id + 1; 103 needs_mask = 1; 104 break; 105 106 case ACL_GROUP_OBJ: 107 if (state == ACL_USER) { 108 id = 0; 109 state = ACL_GROUP; 110 break; 111 } 112 return -EINVAL; 113 114 case ACL_GROUP: 115 if (state != ACL_GROUP) 116 return -EINVAL; 117 if (pa->e_id == ACL_UNDEFINED_ID || 118 pa->e_id < id) 119 return -EINVAL; 120 id = pa->e_id + 1; 121 needs_mask = 1; 122 break; 123 124 case ACL_MASK: 125 if (state != ACL_GROUP) 126 return -EINVAL; 127 state = ACL_OTHER; 128 break; 129 130 case ACL_OTHER: 131 if (state == ACL_OTHER || 132 (state == ACL_GROUP && !needs_mask)) { 133 state = 0; 134 break; 135 } 136 return -EINVAL; 137 138 default: 139 return -EINVAL; 140 } 141 } 142 if (state == 0) 143 return 0; 144 return -EINVAL; 145 } 146 147 /* 148 * Returns 0 if the acl can be exactly represented in the traditional 149 * file mode permission bits, or else 1. Returns -E... on error. 150 */ 151 int 152 posix_acl_equiv_mode(const struct posix_acl *acl, umode_t *mode_p) 153 { 154 const struct posix_acl_entry *pa, *pe; 155 umode_t mode = 0; 156 int not_equiv = 0; 157 158 FOREACH_ACL_ENTRY(pa, acl, pe) { 159 switch (pa->e_tag) { 160 case ACL_USER_OBJ: 161 mode |= (pa->e_perm & S_IRWXO) << 6; 162 break; 163 case ACL_GROUP_OBJ: 164 mode |= (pa->e_perm & S_IRWXO) << 3; 165 break; 166 case ACL_OTHER: 167 mode |= pa->e_perm & S_IRWXO; 168 break; 169 case ACL_MASK: 170 mode = (mode & ~S_IRWXG) | 171 ((pa->e_perm & S_IRWXO) << 3); 172 not_equiv = 1; 173 break; 174 case ACL_USER: 175 case ACL_GROUP: 176 not_equiv = 1; 177 break; 178 default: 179 return -EINVAL; 180 } 181 } 182 if (mode_p) 183 *mode_p = (*mode_p & ~S_IRWXUGO) | mode; 184 return not_equiv; 185 } 186 187 /* 188 * Create an ACL representing the file mode permission bits of an inode. 189 */ 190 struct posix_acl * 191 posix_acl_from_mode(umode_t mode, gfp_t flags) 192 { 193 struct posix_acl *acl = posix_acl_alloc(3, flags); 194 if (!acl) 195 return ERR_PTR(-ENOMEM); 196 197 acl->a_entries[0].e_tag = ACL_USER_OBJ; 198 acl->a_entries[0].e_id = ACL_UNDEFINED_ID; 199 acl->a_entries[0].e_perm = (mode & S_IRWXU) >> 6; 200 201 acl->a_entries[1].e_tag = ACL_GROUP_OBJ; 202 acl->a_entries[1].e_id = ACL_UNDEFINED_ID; 203 acl->a_entries[1].e_perm = (mode & S_IRWXG) >> 3; 204 205 acl->a_entries[2].e_tag = ACL_OTHER; 206 acl->a_entries[2].e_id = ACL_UNDEFINED_ID; 207 acl->a_entries[2].e_perm = (mode & S_IRWXO); 208 return acl; 209 } 210 211 /* 212 * Return 0 if current is granted want access to the inode 213 * by the acl. Returns -E... otherwise. 214 */ 215 int 216 posix_acl_permission(struct inode *inode, const struct posix_acl *acl, int want) 217 { 218 const struct posix_acl_entry *pa, *pe, *mask_obj; 219 int found = 0; 220 221 FOREACH_ACL_ENTRY(pa, acl, pe) { 222 switch(pa->e_tag) { 223 case ACL_USER_OBJ: 224 /* (May have been checked already) */ 225 if (inode->i_uid == current_fsuid()) 226 goto check_perm; 227 break; 228 case ACL_USER: 229 if (pa->e_id == current_fsuid()) 230 goto mask; 231 break; 232 case ACL_GROUP_OBJ: 233 if (in_group_p(inode->i_gid)) { 234 found = 1; 235 if ((pa->e_perm & want) == want) 236 goto mask; 237 } 238 break; 239 case ACL_GROUP: 240 if (in_group_p(pa->e_id)) { 241 found = 1; 242 if ((pa->e_perm & want) == want) 243 goto mask; 244 } 245 break; 246 case ACL_MASK: 247 break; 248 case ACL_OTHER: 249 if (found) 250 return -EACCES; 251 else 252 goto check_perm; 253 default: 254 return -EIO; 255 } 256 } 257 return -EIO; 258 259 mask: 260 for (mask_obj = pa+1; mask_obj != pe; mask_obj++) { 261 if (mask_obj->e_tag == ACL_MASK) { 262 if ((pa->e_perm & mask_obj->e_perm & want) == want) 263 return 0; 264 return -EACCES; 265 } 266 } 267 268 check_perm: 269 if ((pa->e_perm & want) == want) 270 return 0; 271 return -EACCES; 272 } 273 274 /* 275 * Modify acl when creating a new inode. The caller must ensure the acl is 276 * only referenced once. 277 * 278 * mode_p initially must contain the mode parameter to the open() / creat() 279 * system calls. All permissions that are not granted by the acl are removed. 280 * The permissions in the acl are changed to reflect the mode_p parameter. 281 */ 282 static int posix_acl_create_masq(struct posix_acl *acl, umode_t *mode_p) 283 { 284 struct posix_acl_entry *pa, *pe; 285 struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL; 286 umode_t mode = *mode_p; 287 int not_equiv = 0; 288 289 /* assert(atomic_read(acl->a_refcount) == 1); */ 290 291 FOREACH_ACL_ENTRY(pa, acl, pe) { 292 switch(pa->e_tag) { 293 case ACL_USER_OBJ: 294 pa->e_perm &= (mode >> 6) | ~S_IRWXO; 295 mode &= (pa->e_perm << 6) | ~S_IRWXU; 296 break; 297 298 case ACL_USER: 299 case ACL_GROUP: 300 not_equiv = 1; 301 break; 302 303 case ACL_GROUP_OBJ: 304 group_obj = pa; 305 break; 306 307 case ACL_OTHER: 308 pa->e_perm &= mode | ~S_IRWXO; 309 mode &= pa->e_perm | ~S_IRWXO; 310 break; 311 312 case ACL_MASK: 313 mask_obj = pa; 314 not_equiv = 1; 315 break; 316 317 default: 318 return -EIO; 319 } 320 } 321 322 if (mask_obj) { 323 mask_obj->e_perm &= (mode >> 3) | ~S_IRWXO; 324 mode &= (mask_obj->e_perm << 3) | ~S_IRWXG; 325 } else { 326 if (!group_obj) 327 return -EIO; 328 group_obj->e_perm &= (mode >> 3) | ~S_IRWXO; 329 mode &= (group_obj->e_perm << 3) | ~S_IRWXG; 330 } 331 332 *mode_p = (*mode_p & ~S_IRWXUGO) | mode; 333 return not_equiv; 334 } 335 336 /* 337 * Modify the ACL for the chmod syscall. 338 */ 339 static int posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode) 340 { 341 struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL; 342 struct posix_acl_entry *pa, *pe; 343 344 /* assert(atomic_read(acl->a_refcount) == 1); */ 345 346 FOREACH_ACL_ENTRY(pa, acl, pe) { 347 switch(pa->e_tag) { 348 case ACL_USER_OBJ: 349 pa->e_perm = (mode & S_IRWXU) >> 6; 350 break; 351 352 case ACL_USER: 353 case ACL_GROUP: 354 break; 355 356 case ACL_GROUP_OBJ: 357 group_obj = pa; 358 break; 359 360 case ACL_MASK: 361 mask_obj = pa; 362 break; 363 364 case ACL_OTHER: 365 pa->e_perm = (mode & S_IRWXO); 366 break; 367 368 default: 369 return -EIO; 370 } 371 } 372 373 if (mask_obj) { 374 mask_obj->e_perm = (mode & S_IRWXG) >> 3; 375 } else { 376 if (!group_obj) 377 return -EIO; 378 group_obj->e_perm = (mode & S_IRWXG) >> 3; 379 } 380 381 return 0; 382 } 383 384 int 385 posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p) 386 { 387 struct posix_acl *clone = posix_acl_clone(*acl, gfp); 388 int err = -ENOMEM; 389 if (clone) { 390 err = posix_acl_create_masq(clone, mode_p); 391 if (err < 0) { 392 posix_acl_release(clone); 393 clone = NULL; 394 } 395 } 396 posix_acl_release(*acl); 397 *acl = clone; 398 return err; 399 } 400 EXPORT_SYMBOL(posix_acl_create); 401 402 int 403 posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode) 404 { 405 struct posix_acl *clone = posix_acl_clone(*acl, gfp); 406 int err = -ENOMEM; 407 if (clone) { 408 err = posix_acl_chmod_masq(clone, mode); 409 if (err) { 410 posix_acl_release(clone); 411 clone = NULL; 412 } 413 } 414 posix_acl_release(*acl); 415 *acl = clone; 416 return err; 417 } 418 EXPORT_SYMBOL(posix_acl_chmod); 419