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