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