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