nfs_commonacl.c revision 361070
1/*- 2 * Copyright (c) 2009 Rick Macklem, University of Guelph 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: stable/11/sys/fs/nfs/nfs_commonacl.c 361070 2020-05-15 01:01:02Z freqlabs $"); 30 31#include <fs/nfs/nfsport.h> 32 33extern int nfsrv_useacl; 34 35static int nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner, 36 enum vtype type, acl_perm_t *permp); 37 38/* 39 * Handle xdr for an ace. 40 */ 41APPLESTATIC int 42nfsrv_dissectace(struct nfsrv_descript *nd, struct acl_entry *acep, 43 int *aceerrp, int *acesizep, NFSPROC_T *p) 44{ 45 u_int32_t *tl; 46 int len, gotid = 0, owner = 0, error = 0, aceerr = 0; 47 u_char *name, namestr[NFSV4_SMALLSTR + 1]; 48 u_int32_t flag, mask, acetype; 49 gid_t gid; 50 uid_t uid; 51 52 *aceerrp = 0; 53 acep->ae_flags = 0; 54 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 55 acetype = fxdr_unsigned(u_int32_t, *tl++); 56 flag = fxdr_unsigned(u_int32_t, *tl++); 57 mask = fxdr_unsigned(u_int32_t, *tl++); 58 len = fxdr_unsigned(int, *tl); 59 if (len < 0) { 60 error = NFSERR_BADXDR; 61 goto nfsmout; 62 } else if (len == 0) { 63 /* Netapp filers return a 0 length who for nil users */ 64 acep->ae_tag = ACL_UNDEFINED_TAG; 65 acep->ae_id = ACL_UNDEFINED_ID; 66 acep->ae_perm = (acl_perm_t)0; 67 acep->ae_entry_type = ACL_ENTRY_TYPE_DENY; 68 if (acesizep) 69 *acesizep = 4 * NFSX_UNSIGNED; 70 error = 0; 71 goto nfsmout; 72 } 73 if (len > NFSV4_SMALLSTR) 74 name = malloc(len + 1, M_NFSSTRING, M_WAITOK); 75 else 76 name = namestr; 77 error = nfsrv_mtostr(nd, name, len); 78 if (error) { 79 if (len > NFSV4_SMALLSTR) 80 free(name, M_NFSSTRING); 81 goto nfsmout; 82 } 83 if (len == 6) { 84 if (!NFSBCMP(name, "OWNER@", 6)) { 85 acep->ae_tag = ACL_USER_OBJ; 86 acep->ae_id = ACL_UNDEFINED_ID; 87 owner = 1; 88 gotid = 1; 89 } else if (!NFSBCMP(name, "GROUP@", 6)) { 90 acep->ae_tag = ACL_GROUP_OBJ; 91 acep->ae_id = ACL_UNDEFINED_ID; 92 gotid = 1; 93 } 94 } else if (len == 9 && !NFSBCMP(name, "EVERYONE@", 9)) { 95 acep->ae_tag = ACL_EVERYONE; 96 acep->ae_id = ACL_UNDEFINED_ID; 97 gotid = 1; 98 } 99 if (gotid == 0) { 100 if (flag & NFSV4ACE_IDENTIFIERGROUP) { 101 acep->ae_tag = ACL_GROUP; 102 aceerr = nfsv4_strtogid(nd, name, len, &gid, p); 103 if (aceerr == 0) 104 acep->ae_id = (uid_t)gid; 105 } else { 106 acep->ae_tag = ACL_USER; 107 aceerr = nfsv4_strtouid(nd, name, len, &uid, p); 108 if (aceerr == 0) 109 acep->ae_id = uid; 110 } 111 } 112 if (len > NFSV4_SMALLSTR) 113 free(name, M_NFSSTRING); 114 115 if (aceerr == 0) { 116 /* 117 * Handle the flags. 118 */ 119 flag &= ~NFSV4ACE_IDENTIFIERGROUP; 120 if (flag & NFSV4ACE_FILEINHERIT) { 121 flag &= ~NFSV4ACE_FILEINHERIT; 122 acep->ae_flags |= ACL_ENTRY_FILE_INHERIT; 123 } 124 if (flag & NFSV4ACE_DIRECTORYINHERIT) { 125 flag &= ~NFSV4ACE_DIRECTORYINHERIT; 126 acep->ae_flags |= ACL_ENTRY_DIRECTORY_INHERIT; 127 } 128 if (flag & NFSV4ACE_NOPROPAGATEINHERIT) { 129 flag &= ~NFSV4ACE_NOPROPAGATEINHERIT; 130 acep->ae_flags |= ACL_ENTRY_NO_PROPAGATE_INHERIT; 131 } 132 if (flag & NFSV4ACE_INHERITONLY) { 133 flag &= ~NFSV4ACE_INHERITONLY; 134 acep->ae_flags |= ACL_ENTRY_INHERIT_ONLY; 135 } 136 if (flag & NFSV4ACE_SUCCESSFULACCESS) { 137 flag &= ~NFSV4ACE_SUCCESSFULACCESS; 138 acep->ae_flags |= ACL_ENTRY_SUCCESSFUL_ACCESS; 139 } 140 if (flag & NFSV4ACE_FAILEDACCESS) { 141 flag &= ~NFSV4ACE_FAILEDACCESS; 142 acep->ae_flags |= ACL_ENTRY_FAILED_ACCESS; 143 } 144 /* 145 * Set ae_entry_type. 146 */ 147 if (acetype == NFSV4ACE_ALLOWEDTYPE) 148 acep->ae_entry_type = ACL_ENTRY_TYPE_ALLOW; 149 else if (acetype == NFSV4ACE_DENIEDTYPE) 150 acep->ae_entry_type = ACL_ENTRY_TYPE_DENY; 151 else if (acetype == NFSV4ACE_AUDITTYPE) 152 acep->ae_entry_type = ACL_ENTRY_TYPE_AUDIT; 153 else if (acetype == NFSV4ACE_ALARMTYPE) 154 acep->ae_entry_type = ACL_ENTRY_TYPE_ALARM; 155 else 156 aceerr = NFSERR_ATTRNOTSUPP; 157 } 158 159 /* 160 * Now, check for unsupported flag bits. 161 */ 162 if (aceerr == 0 && flag != 0) 163 aceerr = NFSERR_ATTRNOTSUPP; 164 165 /* 166 * And turn the mask into perm bits. 167 */ 168 if (aceerr == 0) 169 aceerr = nfsrv_acemasktoperm(acetype, mask, owner, VREG, 170 &acep->ae_perm); 171 *aceerrp = aceerr; 172 if (acesizep) 173 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED); 174 error = 0; 175nfsmout: 176 NFSEXITCODE(error); 177 return (error); 178} 179 180/* 181 * Turn an NFSv4 ace mask into R/W/X flag bits. 182 */ 183static int 184nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner, 185 enum vtype type, acl_perm_t *permp) 186{ 187 acl_perm_t perm = 0x0; 188 int error = 0; 189 190 if (mask & NFSV4ACE_READDATA) { 191 mask &= ~NFSV4ACE_READDATA; 192 perm |= ACL_READ_DATA; 193 } 194 if (mask & NFSV4ACE_LISTDIRECTORY) { 195 mask &= ~NFSV4ACE_LISTDIRECTORY; 196 perm |= ACL_LIST_DIRECTORY; 197 } 198 if (mask & NFSV4ACE_WRITEDATA) { 199 mask &= ~NFSV4ACE_WRITEDATA; 200 perm |= ACL_WRITE_DATA; 201 } 202 if (mask & NFSV4ACE_ADDFILE) { 203 mask &= ~NFSV4ACE_ADDFILE; 204 perm |= ACL_ADD_FILE; 205 } 206 if (mask & NFSV4ACE_APPENDDATA) { 207 mask &= ~NFSV4ACE_APPENDDATA; 208 perm |= ACL_APPEND_DATA; 209 } 210 if (mask & NFSV4ACE_ADDSUBDIRECTORY) { 211 mask &= ~NFSV4ACE_ADDSUBDIRECTORY; 212 perm |= ACL_ADD_SUBDIRECTORY; 213 } 214 if (mask & NFSV4ACE_READNAMEDATTR) { 215 mask &= ~NFSV4ACE_READNAMEDATTR; 216 perm |= ACL_READ_NAMED_ATTRS; 217 } 218 if (mask & NFSV4ACE_WRITENAMEDATTR) { 219 mask &= ~NFSV4ACE_WRITENAMEDATTR; 220 perm |= ACL_WRITE_NAMED_ATTRS; 221 } 222 if (mask & NFSV4ACE_EXECUTE) { 223 mask &= ~NFSV4ACE_EXECUTE; 224 perm |= ACL_EXECUTE; 225 } 226 if (mask & NFSV4ACE_SEARCH) { 227 mask &= ~NFSV4ACE_SEARCH; 228 perm |= ACL_EXECUTE; 229 } 230 if (mask & NFSV4ACE_DELETECHILD) { 231 mask &= ~NFSV4ACE_DELETECHILD; 232 perm |= ACL_DELETE_CHILD; 233 } 234 if (mask & NFSV4ACE_READATTRIBUTES) { 235 mask &= ~NFSV4ACE_READATTRIBUTES; 236 perm |= ACL_READ_ATTRIBUTES; 237 } 238 if (mask & NFSV4ACE_WRITEATTRIBUTES) { 239 mask &= ~NFSV4ACE_WRITEATTRIBUTES; 240 perm |= ACL_WRITE_ATTRIBUTES; 241 } 242 if (mask & NFSV4ACE_DELETE) { 243 mask &= ~NFSV4ACE_DELETE; 244 perm |= ACL_DELETE; 245 } 246 if (mask & NFSV4ACE_READACL) { 247 mask &= ~NFSV4ACE_READACL; 248 perm |= ACL_READ_ACL; 249 } 250 if (mask & NFSV4ACE_WRITEACL) { 251 mask &= ~NFSV4ACE_WRITEACL; 252 perm |= ACL_WRITE_ACL; 253 } 254 if (mask & NFSV4ACE_WRITEOWNER) { 255 mask &= ~NFSV4ACE_WRITEOWNER; 256 perm |= ACL_WRITE_OWNER; 257 } 258 if (mask & NFSV4ACE_SYNCHRONIZE) { 259 mask &= ~NFSV4ACE_SYNCHRONIZE; 260 perm |= ACL_SYNCHRONIZE; 261 } 262 if (mask != 0) { 263 error = NFSERR_ATTRNOTSUPP; 264 goto out; 265 } 266 *permp = perm; 267 268out: 269 NFSEXITCODE(error); 270 return (error); 271} 272 273/* local functions */ 274static int nfsrv_buildace(struct nfsrv_descript *, u_char *, int, 275 enum vtype, int, int, struct acl_entry *); 276 277/* 278 * This function builds an NFS ace. 279 */ 280static int 281nfsrv_buildace(struct nfsrv_descript *nd, u_char *name, int namelen, 282 enum vtype type, int group, int owner, struct acl_entry *ace) 283{ 284 u_int32_t *tl, aceflag = 0x0, acemask = 0x0, acetype; 285 int full_len; 286 287 full_len = NFSM_RNDUP(namelen); 288 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED + full_len); 289 290 /* 291 * Fill in the ace type. 292 */ 293 if (ace->ae_entry_type & ACL_ENTRY_TYPE_ALLOW) 294 acetype = NFSV4ACE_ALLOWEDTYPE; 295 else if (ace->ae_entry_type & ACL_ENTRY_TYPE_DENY) 296 acetype = NFSV4ACE_DENIEDTYPE; 297 else if (ace->ae_entry_type & ACL_ENTRY_TYPE_AUDIT) 298 acetype = NFSV4ACE_AUDITTYPE; 299 else 300 acetype = NFSV4ACE_ALARMTYPE; 301 *tl++ = txdr_unsigned(acetype); 302 303 /* 304 * Set the flag bits from the ACL. 305 */ 306 if (ace->ae_flags & ACL_ENTRY_FILE_INHERIT) 307 aceflag |= NFSV4ACE_FILEINHERIT; 308 if (ace->ae_flags & ACL_ENTRY_DIRECTORY_INHERIT) 309 aceflag |= NFSV4ACE_DIRECTORYINHERIT; 310 if (ace->ae_flags & ACL_ENTRY_NO_PROPAGATE_INHERIT) 311 aceflag |= NFSV4ACE_NOPROPAGATEINHERIT; 312 if (ace->ae_flags & ACL_ENTRY_INHERIT_ONLY) 313 aceflag |= NFSV4ACE_INHERITONLY; 314 if (ace->ae_flags & ACL_ENTRY_SUCCESSFUL_ACCESS) 315 aceflag |= NFSV4ACE_SUCCESSFULACCESS; 316 if (ace->ae_flags & ACL_ENTRY_FAILED_ACCESS) 317 aceflag |= NFSV4ACE_FAILEDACCESS; 318 if (group) 319 aceflag |= NFSV4ACE_IDENTIFIERGROUP; 320 *tl++ = txdr_unsigned(aceflag); 321 if (type == VDIR) { 322 if (ace->ae_perm & ACL_LIST_DIRECTORY) 323 acemask |= NFSV4ACE_LISTDIRECTORY; 324 if (ace->ae_perm & ACL_ADD_FILE) 325 acemask |= NFSV4ACE_ADDFILE; 326 if (ace->ae_perm & ACL_ADD_SUBDIRECTORY) 327 acemask |= NFSV4ACE_ADDSUBDIRECTORY; 328 if (ace->ae_perm & ACL_READ_NAMED_ATTRS) 329 acemask |= NFSV4ACE_READNAMEDATTR; 330 if (ace->ae_perm & ACL_WRITE_NAMED_ATTRS) 331 acemask |= NFSV4ACE_WRITENAMEDATTR; 332 if (ace->ae_perm & ACL_EXECUTE) 333 acemask |= NFSV4ACE_SEARCH; 334 if (ace->ae_perm & ACL_DELETE_CHILD) 335 acemask |= NFSV4ACE_DELETECHILD; 336 if (ace->ae_perm & ACL_READ_ATTRIBUTES) 337 acemask |= NFSV4ACE_READATTRIBUTES; 338 if (ace->ae_perm & ACL_WRITE_ATTRIBUTES) 339 acemask |= NFSV4ACE_WRITEATTRIBUTES; 340 if (ace->ae_perm & ACL_DELETE) 341 acemask |= NFSV4ACE_DELETE; 342 if (ace->ae_perm & ACL_READ_ACL) 343 acemask |= NFSV4ACE_READACL; 344 if (ace->ae_perm & ACL_WRITE_ACL) 345 acemask |= NFSV4ACE_WRITEACL; 346 if (ace->ae_perm & ACL_WRITE_OWNER) 347 acemask |= NFSV4ACE_WRITEOWNER; 348 if (ace->ae_perm & ACL_SYNCHRONIZE) 349 acemask |= NFSV4ACE_SYNCHRONIZE; 350 } else { 351 if (ace->ae_perm & ACL_READ_DATA) 352 acemask |= NFSV4ACE_READDATA; 353 if (ace->ae_perm & ACL_WRITE_DATA) 354 acemask |= NFSV4ACE_WRITEDATA; 355 if (ace->ae_perm & ACL_APPEND_DATA) 356 acemask |= NFSV4ACE_APPENDDATA; 357 if (ace->ae_perm & ACL_READ_NAMED_ATTRS) 358 acemask |= NFSV4ACE_READNAMEDATTR; 359 if (ace->ae_perm & ACL_WRITE_NAMED_ATTRS) 360 acemask |= NFSV4ACE_WRITENAMEDATTR; 361 if (ace->ae_perm & ACL_EXECUTE) 362 acemask |= NFSV4ACE_EXECUTE; 363 if (ace->ae_perm & ACL_READ_ATTRIBUTES) 364 acemask |= NFSV4ACE_READATTRIBUTES; 365 if (ace->ae_perm & ACL_WRITE_ATTRIBUTES) 366 acemask |= NFSV4ACE_WRITEATTRIBUTES; 367 if (ace->ae_perm & ACL_DELETE) 368 acemask |= NFSV4ACE_DELETE; 369 if (ace->ae_perm & ACL_READ_ACL) 370 acemask |= NFSV4ACE_READACL; 371 if (ace->ae_perm & ACL_WRITE_ACL) 372 acemask |= NFSV4ACE_WRITEACL; 373 if (ace->ae_perm & ACL_WRITE_OWNER) 374 acemask |= NFSV4ACE_WRITEOWNER; 375 if (ace->ae_perm & ACL_SYNCHRONIZE) 376 acemask |= NFSV4ACE_SYNCHRONIZE; 377 } 378 *tl++ = txdr_unsigned(acemask); 379 *tl++ = txdr_unsigned(namelen); 380 if (full_len - namelen) 381 *(tl + (namelen / NFSX_UNSIGNED)) = 0x0; 382 NFSBCOPY(name, (caddr_t)tl, namelen); 383 return (full_len + 4 * NFSX_UNSIGNED); 384} 385 386/* 387 * Build an NFSv4 ACL. 388 */ 389APPLESTATIC int 390nfsrv_buildacl(struct nfsrv_descript *nd, NFSACL_T *aclp, enum vtype type, 391 NFSPROC_T *p) 392{ 393 int i, entrycnt = 0, retlen; 394 u_int32_t *entrycntp; 395 int isowner, isgroup, namelen, malloced; 396 u_char *name, namestr[NFSV4_SMALLSTR]; 397 398 NFSM_BUILD(entrycntp, u_int32_t *, NFSX_UNSIGNED); 399 retlen = NFSX_UNSIGNED; 400 /* 401 * Loop through the acl entries, building each one. 402 */ 403 for (i = 0; i < aclp->acl_cnt; i++) { 404 isowner = isgroup = malloced = 0; 405 switch (aclp->acl_entry[i].ae_tag) { 406 case ACL_USER_OBJ: 407 isowner = 1; 408 name = "OWNER@"; 409 namelen = 6; 410 break; 411 case ACL_GROUP_OBJ: 412 isgroup = 1; 413 name = "GROUP@"; 414 namelen = 6; 415 break; 416 case ACL_EVERYONE: 417 name = "EVERYONE@"; 418 namelen = 9; 419 break; 420 case ACL_USER: 421 name = namestr; 422 nfsv4_uidtostr(aclp->acl_entry[i].ae_id, &name, 423 &namelen, p); 424 if (name != namestr) 425 malloced = 1; 426 break; 427 case ACL_GROUP: 428 isgroup = 1; 429 name = namestr; 430 nfsv4_gidtostr((gid_t)aclp->acl_entry[i].ae_id, &name, 431 &namelen, p); 432 if (name != namestr) 433 malloced = 1; 434 break; 435 default: 436 continue; 437 } 438 retlen += nfsrv_buildace(nd, name, namelen, type, isgroup, 439 isowner, &aclp->acl_entry[i]); 440 entrycnt++; 441 if (malloced) 442 free(name, M_NFSSTRING); 443 } 444 *entrycntp = txdr_unsigned(entrycnt); 445 return (retlen); 446} 447 448/* 449 * Set an NFSv4 acl. 450 */ 451APPLESTATIC int 452nfsrv_setacl(vnode_t vp, NFSACL_T *aclp, struct ucred *cred, 453 NFSPROC_T *p) 454{ 455 int error; 456 457 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) { 458 error = NFSERR_ATTRNOTSUPP; 459 goto out; 460 } 461 /* 462 * With NFSv4 ACLs, chmod(2) may need to add additional entries. 463 * Make sure it has enough room for that - splitting every entry 464 * into two and appending "canonical six" entries at the end. 465 * Cribbed out of kern/vfs_acl.c - Rick M. 466 */ 467 if (aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) { 468 error = NFSERR_ATTRNOTSUPP; 469 goto out; 470 } 471 error = VOP_SETACL(vp, ACL_TYPE_NFS4, aclp, cred, p); 472 473out: 474 NFSEXITCODE(error); 475 return (error); 476} 477 478/* 479 * Compare two NFSv4 acls. 480 * Return 0 if they are the same, 1 if not the same. 481 */ 482APPLESTATIC int 483nfsrv_compareacl(NFSACL_T *aclp1, NFSACL_T *aclp2) 484{ 485 int i; 486 struct acl_entry *acep1, *acep2; 487 488 if (aclp1->acl_cnt != aclp2->acl_cnt) 489 return (1); 490 acep1 = aclp1->acl_entry; 491 acep2 = aclp2->acl_entry; 492 for (i = 0; i < aclp1->acl_cnt; i++) { 493 if (acep1->ae_tag != acep2->ae_tag) 494 return (1); 495 switch (acep1->ae_tag) { 496 case ACL_GROUP: 497 case ACL_USER: 498 if (acep1->ae_id != acep2->ae_id) 499 return (1); 500 /* fall through */ 501 case ACL_USER_OBJ: 502 case ACL_GROUP_OBJ: 503 case ACL_OTHER: 504 if (acep1->ae_perm != acep2->ae_perm) 505 return (1); 506 } 507 acep1++; 508 acep2++; 509 } 510 return (0); 511} 512