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 return (NFSERR_BADXDR); 63 } else if (len == 0) { 64 /* Netapp filers return a 0 length who for nil users */ 65 acep->ae_tag = ACL_UNDEFINED_TAG; 66 acep->ae_id = ACL_UNDEFINED_ID; 67 acep->ae_perm = (acl_perm_t)0; 68 acep->ae_entry_type = ACL_ENTRY_TYPE_DENY; 69 if (acesizep) 70 *acesizep = 4 * NFSX_UNSIGNED; 71 return (0); 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 return (error); 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(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(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 return (0); 175 nfsmout: 176 return (error); 177 } 178 179 /* 180 * Turn an NFSv4 ace mask into R/W/X flag bits. 181 */ 182 static int 183 nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner, 184 enum vtype type, acl_perm_t *permp) 185 { 186 acl_perm_t perm = 0x0; 187 188 if (mask & NFSV4ACE_READDATA) { 189 mask &= ~NFSV4ACE_READDATA; 190 perm |= ACL_READ_DATA; 191 } 192 if (mask & NFSV4ACE_LISTDIRECTORY) { 193 mask &= ~NFSV4ACE_LISTDIRECTORY; 194 perm |= ACL_LIST_DIRECTORY; 195 } 196 if (mask & NFSV4ACE_WRITEDATA) { 197 mask &= ~NFSV4ACE_WRITEDATA; 198 perm |= ACL_WRITE_DATA; 199 } 200 if (mask & NFSV4ACE_ADDFILE) { 201 mask &= ~NFSV4ACE_ADDFILE; 202 perm |= ACL_ADD_FILE; 203 } 204 if (mask & NFSV4ACE_APPENDDATA) { 205 mask &= ~NFSV4ACE_APPENDDATA; 206 perm |= ACL_APPEND_DATA; 207 } 208 if (mask & NFSV4ACE_ADDSUBDIRECTORY) { 209 mask &= ~NFSV4ACE_ADDSUBDIRECTORY; 210 perm |= ACL_ADD_SUBDIRECTORY; 211 } 212 if (mask & NFSV4ACE_READNAMEDATTR) { 213 mask &= ~NFSV4ACE_READNAMEDATTR; 214 perm |= ACL_READ_NAMED_ATTRS; 215 } 216 if (mask & NFSV4ACE_WRITENAMEDATTR) { 217 mask &= ~NFSV4ACE_WRITENAMEDATTR; 218 perm |= ACL_WRITE_NAMED_ATTRS; 219 } 220 if (mask & NFSV4ACE_EXECUTE) { 221 mask &= ~NFSV4ACE_EXECUTE; 222 perm |= ACL_EXECUTE; 223 } 224 if (mask & NFSV4ACE_SEARCH) { 225 mask &= ~NFSV4ACE_SEARCH; 226 perm |= ACL_EXECUTE; 227 } 228 if (mask & NFSV4ACE_DELETECHILD) { 229 mask &= ~NFSV4ACE_DELETECHILD; 230 perm |= ACL_DELETE_CHILD; 231 } 232 if (mask & NFSV4ACE_READATTRIBUTES) { 233 mask &= ~NFSV4ACE_READATTRIBUTES; 234 perm |= ACL_READ_ATTRIBUTES; 235 } 236 if (mask & NFSV4ACE_WRITEATTRIBUTES) { 237 mask &= ~NFSV4ACE_WRITEATTRIBUTES; 238 perm |= ACL_WRITE_ATTRIBUTES; 239 } 240 if (mask & NFSV4ACE_DELETE) { 241 mask &= ~NFSV4ACE_DELETE; 242 perm |= ACL_DELETE; 243 } 244 if (mask & NFSV4ACE_READACL) { 245 mask &= ~NFSV4ACE_READACL; 246 perm |= ACL_READ_ACL; 247 } 248 if (mask & NFSV4ACE_WRITEACL) { 249 mask &= ~NFSV4ACE_WRITEACL; 250 perm |= ACL_WRITE_ACL; 251 } 252 if (mask & NFSV4ACE_WRITEOWNER) { 253 mask &= ~NFSV4ACE_WRITEOWNER; 254 perm |= ACL_WRITE_OWNER; 255 } 256 if (mask & NFSV4ACE_SYNCHRONIZE) { 257 mask &= ~NFSV4ACE_SYNCHRONIZE; 258 perm |= ACL_SYNCHRONIZE; 259 } 260 if (mask != 0) 261 return (NFSERR_ATTRNOTSUPP); 262 *permp = perm; 263 return (0); 264 } 265 266 /* local functions */ 267 static int nfsrv_buildace(struct nfsrv_descript *, u_char *, int, 268 enum vtype, int, int, struct acl_entry *); 269 270 /* 271 * This function builds an NFS ace. 272 */ 273 static int 274 nfsrv_buildace(struct nfsrv_descript *nd, u_char *name, int namelen, 275 enum vtype type, int group, int owner, struct acl_entry *ace) 276 { 277 u_int32_t *tl, aceflag = 0x0, acemask = 0x0, acetype; 278 int full_len; 279 280 full_len = NFSM_RNDUP(namelen); 281 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED + full_len); 282 283 /* 284 * Fill in the ace type. 285 */ 286 if (ace->ae_entry_type & ACL_ENTRY_TYPE_ALLOW) 287 acetype = NFSV4ACE_ALLOWEDTYPE; 288 else if (ace->ae_entry_type & ACL_ENTRY_TYPE_DENY) 289 acetype = NFSV4ACE_DENIEDTYPE; 290 else if (ace->ae_entry_type & ACL_ENTRY_TYPE_AUDIT) 291 acetype = NFSV4ACE_AUDITTYPE; 292 else 293 acetype = NFSV4ACE_ALARMTYPE; 294 *tl++ = txdr_unsigned(acetype); 295 296 /* 297 * Set the flag bits from the ACL. 298 */ 299 if (ace->ae_flags & ACL_ENTRY_FILE_INHERIT) 300 aceflag |= NFSV4ACE_FILEINHERIT; 301 if (ace->ae_flags & ACL_ENTRY_DIRECTORY_INHERIT) 302 aceflag |= NFSV4ACE_DIRECTORYINHERIT; 303 if (ace->ae_flags & ACL_ENTRY_NO_PROPAGATE_INHERIT) 304 aceflag |= NFSV4ACE_NOPROPAGATEINHERIT; 305 if (ace->ae_flags & ACL_ENTRY_INHERIT_ONLY) 306 aceflag |= NFSV4ACE_INHERITONLY; 307 if (ace->ae_flags & ACL_ENTRY_SUCCESSFUL_ACCESS) 308 aceflag |= NFSV4ACE_SUCCESSFULACCESS; 309 if (ace->ae_flags & ACL_ENTRY_FAILED_ACCESS) 310 aceflag |= NFSV4ACE_FAILEDACCESS; 311 if (group) 312 aceflag |= NFSV4ACE_IDENTIFIERGROUP; 313 *tl++ = txdr_unsigned(aceflag); 314 if (type == VDIR) { 315 if (ace->ae_perm & ACL_LIST_DIRECTORY) 316 acemask |= NFSV4ACE_LISTDIRECTORY; 317 if (ace->ae_perm & ACL_ADD_FILE) 318 acemask |= NFSV4ACE_ADDFILE; 319 if (ace->ae_perm & ACL_ADD_SUBDIRECTORY) 320 acemask |= NFSV4ACE_ADDSUBDIRECTORY; 321 if (ace->ae_perm & ACL_READ_NAMED_ATTRS) 322 acemask |= NFSV4ACE_READNAMEDATTR; 323 if (ace->ae_perm & ACL_WRITE_NAMED_ATTRS) 324 acemask |= NFSV4ACE_WRITENAMEDATTR; 325 if (ace->ae_perm & ACL_EXECUTE) 326 acemask |= NFSV4ACE_SEARCH; 327 if (ace->ae_perm & ACL_DELETE_CHILD) 328 acemask |= NFSV4ACE_DELETECHILD; 329 if (ace->ae_perm & ACL_READ_ATTRIBUTES) 330 acemask |= NFSV4ACE_READATTRIBUTES; 331 if (ace->ae_perm & ACL_WRITE_ATTRIBUTES) 332 acemask |= NFSV4ACE_WRITEATTRIBUTES; 333 if (ace->ae_perm & ACL_DELETE) 334 acemask |= NFSV4ACE_DELETE; 335 if (ace->ae_perm & ACL_READ_ACL) 336 acemask |= NFSV4ACE_READACL; 337 if (ace->ae_perm & ACL_WRITE_ACL) 338 acemask |= NFSV4ACE_WRITEACL; 339 if (ace->ae_perm & ACL_WRITE_OWNER) 340 acemask |= NFSV4ACE_WRITEOWNER; 341 } else { 342 if (ace->ae_perm & ACL_READ_DATA) 343 acemask |= NFSV4ACE_READDATA; 344 if (ace->ae_perm & ACL_WRITE_DATA) 345 acemask |= NFSV4ACE_WRITEDATA; 346 if (ace->ae_perm & ACL_APPEND_DATA) 347 acemask |= NFSV4ACE_APPENDDATA; 348 if (ace->ae_perm & ACL_READ_NAMED_ATTRS) 349 acemask |= NFSV4ACE_READNAMEDATTR; 350 if (ace->ae_perm & ACL_WRITE_NAMED_ATTRS) 351 acemask |= NFSV4ACE_WRITENAMEDATTR; 352 if (ace->ae_perm & ACL_EXECUTE) 353 acemask |= NFSV4ACE_EXECUTE; 354 if (ace->ae_perm & ACL_READ_ATTRIBUTES) 355 acemask |= NFSV4ACE_READATTRIBUTES; 356 if (ace->ae_perm & ACL_WRITE_ATTRIBUTES) 357 acemask |= NFSV4ACE_WRITEATTRIBUTES; 358 if (ace->ae_perm & ACL_DELETE) 359 acemask |= NFSV4ACE_DELETE; 360 if (ace->ae_perm & ACL_READ_ACL) 361 acemask |= NFSV4ACE_READACL; 362 if (ace->ae_perm & ACL_WRITE_ACL) 363 acemask |= NFSV4ACE_WRITEACL; 364 if (ace->ae_perm & ACL_WRITE_OWNER) 365 acemask |= NFSV4ACE_WRITEOWNER; 366 if (ace->ae_perm & ACL_SYNCHRONIZE) 367 acemask |= NFSV4ACE_SYNCHRONIZE; 368 } 369 *tl++ = txdr_unsigned(acemask); 370 *tl++ = txdr_unsigned(namelen); 371 if (full_len - namelen) 372 *(tl + (namelen / NFSX_UNSIGNED)) = 0x0; 373 NFSBCOPY(name, (caddr_t)tl, namelen); 374 return (full_len + 4 * NFSX_UNSIGNED); 375 } 376 377 /* 378 * Build an NFSv4 ACL. 379 */ 380 APPLESTATIC int 381 nfsrv_buildacl(struct nfsrv_descript *nd, NFSACL_T *aclp, enum vtype type, 382 NFSPROC_T *p) 383 { 384 int i, entrycnt = 0, retlen; 385 u_int32_t *entrycntp; 386 int isowner, isgroup, namelen, malloced; 387 u_char *name, namestr[NFSV4_SMALLSTR]; 388 389 NFSM_BUILD(entrycntp, u_int32_t *, NFSX_UNSIGNED); 390 retlen = NFSX_UNSIGNED; 391 /* 392 * Loop through the acl entries, building each one. 393 */ 394 for (i = 0; i < aclp->acl_cnt; i++) { 395 isowner = isgroup = malloced = 0; 396 switch (aclp->acl_entry[i].ae_tag) { 397 case ACL_USER_OBJ: 398 isowner = 1; 399 name = "OWNER@"; 400 namelen = 6; 401 break; 402 case ACL_GROUP_OBJ: 403 isgroup = 1; 404 name = "GROUP@"; 405 namelen = 6; 406 break; 407 case ACL_EVERYONE: 408 name = "EVERYONE@"; 409 namelen = 9; 410 break; 411 case ACL_USER: 412 name = namestr; 413 nfsv4_uidtostr(aclp->acl_entry[i].ae_id, &name, 414 &namelen, p); 415 if (name != namestr) 416 malloced = 1; 417 break; 418 case ACL_GROUP: 419 isgroup = 1; 420 name = namestr; 421 nfsv4_gidtostr((gid_t)aclp->acl_entry[i].ae_id, &name, 422 &namelen, p); 423 if (name != namestr) 424 malloced = 1; 425 break; 426 default: 427 continue; 428 }; 429 retlen += nfsrv_buildace(nd, name, namelen, type, isgroup, 430 isowner, &aclp->acl_entry[i]); 431 entrycnt++; 432 if (malloced) 433 free(name, M_NFSSTRING); 434 } 435 *entrycntp = txdr_unsigned(entrycnt); 436 return (retlen); 437 } 438 439 /* 440 * Set an NFSv4 acl. 441 */ 442 APPLESTATIC int 443 nfsrv_setacl(vnode_t vp, NFSACL_T *aclp, struct ucred *cred, 444 NFSPROC_T *p) 445 { 446 int error; 447 448 if (nfsrv_useacl == 0 || !NFSHASNFS4ACL(vnode_mount(vp))) 449 return (NFSERR_ATTRNOTSUPP); 450 /* 451 * With NFSv4 ACLs, chmod(2) may need to add additional entries. 452 * Make sure it has enough room for that - splitting every entry 453 * into two and appending "canonical six" entries at the end. 454 * Cribbed out of kern/vfs_acl.c - Rick M. 455 */ 456 if (aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) 457 return (NFSERR_ATTRNOTSUPP); 458 error = VOP_ACLCHECK(vp, ACL_TYPE_NFS4, aclp, cred, p); 459 if (!error) 460 error = VOP_SETACL(vp, ACL_TYPE_NFS4, aclp, cred, p); 461 return (error); 462 } 463 464 /* 465 * Compare two NFSv4 acls. 466 * Return 0 if they are the same, 1 if not the same. 467 */ 468 APPLESTATIC int 469 nfsrv_compareacl(NFSACL_T *aclp1, NFSACL_T *aclp2) 470 { 471 int i; 472 struct acl_entry *acep1, *acep2; 473 474 if (aclp1->acl_cnt != aclp2->acl_cnt) 475 return (1); 476 acep1 = aclp1->acl_entry; 477 acep2 = aclp2->acl_entry; 478 for (i = 0; i < aclp1->acl_cnt; i++) { 479 if (acep1->ae_tag != acep2->ae_tag) 480 return (1); 481 switch (acep1->ae_tag) { 482 case ACL_GROUP: 483 case ACL_USER: 484 if (acep1->ae_id != acep2->ae_id) 485 return (1); 486 /* fall through */ 487 case ACL_USER_OBJ: 488 case ACL_GROUP_OBJ: 489 case ACL_OTHER: 490 if (acep1->ae_perm != acep2->ae_perm) 491 return (1); 492 }; 493 acep1++; 494 acep2++; 495 } 496 return (0); 497 } 498