1 /* NFSv4.1 client for Windows 2 * Copyright � 2012 The Regents of the University of Michigan 3 * 4 * Olga Kornievskaia <aglo@umich.edu> 5 * Casey Bodley <cbodley@umich.edu> 6 * 7 * This library is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU Lesser General Public License as published by 9 * the Free Software Foundation; either version 2.1 of the License, or (at 10 * your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, but 13 * without any warranty; without even the implied warranty of merchantability 14 * or fitness for a particular purpose. See the GNU Lesser General Public 15 * License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public License 18 * along with this library; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20 */ 21 22 #include <windows.h> 23 #include <strsafe.h> 24 #include <sddl.h> 25 26 #include "nfs41_ops.h" 27 #include "delegation.h" 28 #include "daemon_debug.h" 29 #include "util.h" 30 #include "upcall.h" 31 #include "nfs41_xdr.h" 32 33 //#define DEBUG_ACLS 34 #define ACLLVL 2 /* dprintf level for acl logging */ 35 36 extern char localdomain_name[NFS41_HOSTNAME_LEN]; 37 38 static int parse_getacl(unsigned char *buffer, uint32_t length, 39 nfs41_upcall *upcall) 40 { 41 int status; 42 getacl_upcall_args *args = &upcall->args.getacl; 43 44 status = safe_read(&buffer, &length, &args->query, sizeof(args->query)); 45 if (status) goto out; 46 47 dprintf(1, "parsing NFS41_ACL_QUERY: info_class=%d\n", args->query); 48 out: 49 return status; 50 } 51 52 static int create_unknownsid(WELL_KNOWN_SID_TYPE type, PSID *sid, 53 DWORD *sid_len) 54 { 55 int status; 56 *sid_len = 0; 57 *sid = NULL; 58 59 status = CreateWellKnownSid(type, NULL, *sid, sid_len); 60 dprintf(ACLLVL, "create_unknownsid: CreateWellKnownSid type %d returned %d " 61 "GetLastError %d sid len %d needed\n", type, status, 62 GetLastError(), *sid_len); 63 if (status) 64 return ERROR_INTERNAL_ERROR; 65 status = GetLastError(); 66 if (status != ERROR_INSUFFICIENT_BUFFER) 67 return status; 68 *sid = malloc(*sid_len); 69 if (*sid == NULL) 70 return ERROR_INSUFFICIENT_BUFFER; 71 status = CreateWellKnownSid(type, NULL, *sid, sid_len); 72 if (status) 73 return ERROR_SUCCESS; 74 free(*sid); 75 status = GetLastError(); 76 eprintf("create_unknownsid: CreateWellKnownSid failed with %d\n", status); 77 return status; 78 } 79 80 static void convert_nfs4name_2_user_domain(LPSTR nfs4name, 81 LPSTR *domain) 82 { 83 LPSTR p = nfs4name; 84 for(; p[0] != '\0'; p++) { 85 if (p[0] == '@') { 86 p[0] = '\0'; 87 *domain = &p[1]; 88 break; 89 } 90 } 91 } 92 93 static int map_name_2_sid(DWORD *sid_len, PSID *sid, LPCSTR name) 94 { 95 int status = ERROR_INTERNAL_ERROR; 96 SID_NAME_USE sid_type; 97 LPSTR tmp_buf = NULL; 98 DWORD tmp = 0; 99 100 status = LookupAccountName(NULL, name, NULL, sid_len, NULL, &tmp, &sid_type); 101 dprintf(ACLLVL, "map_name_2_sid: LookupAccountName for %s returned %d " 102 "GetLastError %d name len %d domain len %d\n", name, status, 103 GetLastError(), *sid_len, tmp); 104 if (status) 105 return ERROR_INTERNAL_ERROR; 106 107 status = GetLastError(); 108 switch(status) { 109 case ERROR_INSUFFICIENT_BUFFER: 110 *sid = malloc(*sid_len); 111 if (*sid == NULL) { 112 status = GetLastError(); 113 goto out; 114 } 115 tmp_buf = (LPSTR) malloc(tmp); 116 if (tmp_buf == NULL) 117 goto out_free_sid; 118 status = LookupAccountName(NULL, name, *sid, sid_len, tmp_buf, 119 &tmp, &sid_type); 120 free(tmp_buf); 121 if (!status) { 122 eprintf("map_name_2_sid: LookupAccountName for %s failed " 123 "with %d\n", name, GetLastError()); 124 goto out_free_sid; 125 } else { 126 #ifdef DEBUG_ACLS 127 LPSTR ssid = NULL; 128 if (IsValidSid(*sid)) 129 if (ConvertSidToStringSidA(*sid, &ssid)) 130 dprintf(1, "map_name_2_sid: sid_type = %d SID %s\n", 131 sid_type, ssid); 132 else 133 dprintf(1, "map_name_2_sid: ConvertSidToStringSidA failed " 134 "with %d\n", GetLastError()); 135 else 136 dprintf(1, "map_name_2_sid: Invalid Sid ?\n"); 137 if (ssid) LocalFree(ssid); 138 #endif 139 } 140 status = ERROR_SUCCESS; 141 break; 142 case ERROR_NONE_MAPPED: 143 status = create_unknownsid(WinNullSid, sid, sid_len); 144 if (status) 145 goto out_free_sid; 146 } 147 out: 148 return status; 149 out_free_sid: 150 status = GetLastError(); 151 free(*sid); 152 goto out; 153 } 154 155 static void free_sids(PSID *sids, int count) 156 { 157 int i; 158 for(i = 0; i < count; i++) 159 free(sids[i]); 160 free(sids); 161 } 162 163 static int check_4_special_identifiers(char *who, PSID *sid, DWORD *sid_len, 164 BOOLEAN *flag) 165 { 166 int status = ERROR_SUCCESS; 167 WELL_KNOWN_SID_TYPE type = 0; 168 *flag = TRUE; 169 if (!strncmp(who, ACE4_OWNER, strlen(ACE4_OWNER)-1)) 170 type = WinCreatorOwnerSid; 171 else if (!strncmp(who, ACE4_GROUP, strlen(ACE4_GROUP)-1)) 172 type = WinCreatorGroupSid; 173 else if (!strncmp(who, ACE4_EVERYONE, strlen(ACE4_EVERYONE)-1)) 174 type = WinWorldSid; 175 else if (!strncmp(who, ACE4_NOBODY, strlen(ACE4_NOBODY))) 176 type = WinNullSid; 177 else 178 *flag = FALSE; 179 if (*flag) 180 status = create_unknownsid(type, sid, sid_len); 181 return status; 182 } 183 184 static int convert_nfs4acl_2_dacl(nfsacl41 *acl, int file_type, 185 PACL *dacl_out, PSID **sids_out) 186 { 187 int status = ERROR_NOT_SUPPORTED, size = 0; 188 uint32_t i; 189 DWORD sid_len; 190 PSID *sids; 191 PACL dacl; 192 LPSTR domain = NULL; 193 BOOLEAN flag; 194 195 sids = malloc(acl->count * sizeof(PSID)); 196 if (sids == NULL) { 197 status = GetLastError(); 198 goto out; 199 } 200 for (i = 0; i < acl->count; i++) { 201 convert_nfs4name_2_user_domain(acl->aces[i].who, &domain); 202 dprintf(ACLLVL, "handle_getacl: for user=%s domain=%s\n", 203 acl->aces[i].who, domain?domain:"<null>"); 204 status = check_4_special_identifiers(acl->aces[i].who, &sids[i], 205 &sid_len, &flag); 206 if (status) { 207 free_sids(sids, i); 208 goto out; 209 } 210 if (!flag) { 211 status = map_name_2_sid(&sid_len, &sids[i], acl->aces[i].who); 212 if (status) { 213 free_sids(sids, i); 214 goto out; 215 } 216 } 217 size += sid_len - sizeof(DWORD); 218 } 219 size += sizeof(ACL) + (sizeof(ACCESS_ALLOWED_ACE)*acl->count); 220 size = (size + sizeof(DWORD) - 1) & 0xfffffffc; //align size on word boundry 221 dacl = malloc(size); 222 if (dacl == NULL) 223 goto out_free_sids; 224 225 if (InitializeAcl(dacl, size, ACL_REVISION)) { 226 ACCESS_MASK mask; 227 for (i = 0; i < acl->count; i++) { 228 // nfs4 acemask should be exactly the same as file access mask 229 mask = acl->aces[i].acemask; 230 dprintf(ACLLVL, "access mask %x ace type %s\n", mask, 231 acl->aces[i].acetype?"DENIED ACE":"ALLOWED ACE"); 232 if (acl->aces[i].acetype == ACE4_ACCESS_ALLOWED_ACE_TYPE) { 233 status = AddAccessAllowedAce(dacl, ACL_REVISION, mask, sids[i]); 234 if (!status) { 235 eprintf("convert_nfs4acl_2_dacl: AddAccessAllowedAce failed " 236 "with %d\n", status); 237 goto out_free_dacl; 238 } 239 else status = ERROR_SUCCESS; 240 } else if (acl->aces[i].acetype == ACE4_ACCESS_DENIED_ACE_TYPE) { 241 status = AddAccessDeniedAce(dacl, ACL_REVISION, mask, sids[i]); 242 if (!status) { 243 eprintf("convert_nfs4acl_2_dacl: AddAccessDeniedAce failed " 244 "with %d\n", status); 245 goto out_free_dacl; 246 } 247 else status = ERROR_SUCCESS; 248 } else { 249 eprintf("convert_nfs4acl_2_dacl: unknown acetype %d\n", 250 acl->aces[i].acetype); 251 status = ERROR_INTERNAL_ERROR; 252 free(dacl); 253 free_sids(sids, acl->count); 254 goto out; 255 } 256 } 257 } else { 258 eprintf("convert_nfs4acl_2_dacl: InitializeAcl failed with %d\n", status); 259 goto out_free_dacl; 260 } 261 status = ERROR_SUCCESS; 262 *sids_out = sids; 263 *dacl_out = dacl; 264 out: 265 return status; 266 out_free_dacl: 267 free(dacl); 268 out_free_sids: 269 free_sids(sids, acl->count); 270 status = GetLastError(); 271 goto out; 272 } 273 274 static int handle_getacl(nfs41_upcall *upcall) 275 { 276 int status = ERROR_NOT_SUPPORTED; 277 getacl_upcall_args *args = &upcall->args.getacl; 278 nfs41_open_state *state = upcall->state_ref; 279 nfs41_file_info info = { 0 }; 280 bitmap4 attr_request = { 0 }; 281 LPSTR domain = NULL; 282 SECURITY_DESCRIPTOR sec_desc; 283 PACL dacl = NULL; 284 PSID *sids = NULL; 285 PSID osid = NULL, gsid = NULL; 286 DWORD sid_len; 287 char owner[NFS4_OPAQUE_LIMIT], group[NFS4_OPAQUE_LIMIT]; 288 nfsacl41 acl = { 0 }; 289 290 // need to cache owner/group information XX 291 attr_request.count = 2; 292 attr_request.arr[1] = FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP; 293 if (args->query & DACL_SECURITY_INFORMATION) { 294 info.acl = &acl; 295 attr_request.arr[0] |= FATTR4_WORD0_ACL; 296 } 297 info.owner = owner; 298 info.owner_group = group; 299 status = nfs41_getattr(state->session, &state->file, &attr_request, &info); 300 if (status) { 301 eprintf("handle_getacl: nfs41_cached_getattr() failed with %d\n", 302 status); 303 goto out; 304 } 305 306 status = InitializeSecurityDescriptor(&sec_desc, 307 SECURITY_DESCRIPTOR_REVISION); 308 if (!status) { 309 status = GetLastError(); 310 eprintf("handle_getacl: InitializeSecurityDescriptor failed with %d\n", 311 status); 312 goto out; 313 } 314 /* can't (re)use the same sid variable for both owner and group sids 315 * because security descriptor is created in absolute-form and it just 316 * stores pointers to the sids. thus each owner and group needs its own 317 * memory. free them after creating self-relative security descriptor. 318 */ 319 if (args->query & OWNER_SECURITY_INFORMATION) { 320 // parse user@domain. currently ignoring domain part XX 321 convert_nfs4name_2_user_domain(info.owner, &domain); 322 dprintf(ACLLVL, "handle_getacl: OWNER_SECURITY_INFORMATION: for user=%s " 323 "domain=%s\n", info.owner, domain?domain:"<null>"); 324 sid_len = 0; 325 status = map_name_2_sid(&sid_len, &osid, info.owner); 326 if (status) 327 goto out; 328 status = SetSecurityDescriptorOwner(&sec_desc, osid, TRUE); 329 if (!status) { 330 status = GetLastError(); 331 eprintf("handle_getacl: SetSecurityDescriptorOwner failed with " 332 "%d\n", status); 333 goto out; 334 } 335 } 336 if (args->query & GROUP_SECURITY_INFORMATION) { 337 convert_nfs4name_2_user_domain(info.owner_group, &domain); 338 dprintf(ACLLVL, "handle_getacl: GROUP_SECURITY_INFORMATION: for %s " 339 "domain=%s\n", info.owner_group, domain?domain:"<null>"); 340 sid_len = 0; 341 status = map_name_2_sid(&sid_len, &gsid, info.owner_group); 342 if (status) 343 goto out; 344 status = SetSecurityDescriptorGroup(&sec_desc, gsid, TRUE); 345 if (!status) { 346 status = GetLastError(); 347 eprintf("handle_getacl: SetSecurityDescriptorGroup failed with " 348 "%d\n", status); 349 goto out; 350 } 351 } 352 if (args->query & DACL_SECURITY_INFORMATION) { 353 dprintf(ACLLVL, "handle_getacl: DACL_SECURITY_INFORMATION\n"); 354 status = convert_nfs4acl_2_dacl(info.acl, state->type, &dacl, &sids); 355 if (status) 356 goto out; 357 status = SetSecurityDescriptorDacl(&sec_desc, TRUE, dacl, TRUE); 358 if (!status) { 359 status = GetLastError(); 360 eprintf("handle_getacl: SetSecurityDescriptorDacl failed with " 361 "%d\n", status); 362 goto out; 363 } 364 } 365 366 args->sec_desc_len = 0; 367 status = MakeSelfRelativeSD(&sec_desc, args->sec_desc, &args->sec_desc_len); 368 if (status) { 369 status = ERROR_INTERNAL_ERROR; 370 goto out; 371 } 372 status = GetLastError(); 373 if (status != ERROR_INSUFFICIENT_BUFFER) { 374 eprintf("handle_getacl: MakeSelfRelativeSD failes with %d\n", status); 375 goto out; 376 } 377 args->sec_desc = malloc(args->sec_desc_len); 378 if (args->sec_desc == NULL) { 379 status = GetLastError(); 380 goto out; 381 } 382 status = MakeSelfRelativeSD(&sec_desc, args->sec_desc, &args->sec_desc_len); 383 if (!status) { 384 status = GetLastError(); 385 eprintf("handle_getacl: MakeSelfRelativeSD failes with %d\n", status); 386 free(args->sec_desc); 387 goto out; 388 } else status = ERROR_SUCCESS; 389 390 out: 391 if (args->query & OWNER_SECURITY_INFORMATION) { 392 if (osid) free(osid); 393 } 394 if (args->query & GROUP_SECURITY_INFORMATION) { 395 if (gsid) free(gsid); 396 } 397 if (args->query & DACL_SECURITY_INFORMATION) { 398 if (sids) free_sids(sids, info.acl->count); 399 free(dacl); 400 nfsacl41_free(info.acl); 401 } 402 return status; 403 } 404 405 static int marshall_getacl(unsigned char *buffer, uint32_t *length, 406 nfs41_upcall *upcall) 407 { 408 int status = ERROR_NOT_SUPPORTED; 409 getacl_upcall_args *args = &upcall->args.getacl; 410 411 status = safe_write(&buffer, length, &args->sec_desc_len, sizeof(DWORD)); 412 if (status) goto out; 413 status = safe_write(&buffer, length, args->sec_desc, args->sec_desc_len); 414 free(args->sec_desc); 415 if (status) goto out; 416 out: 417 return status; 418 } 419 420 const nfs41_upcall_op nfs41_op_getacl = { 421 parse_getacl, 422 handle_getacl, 423 marshall_getacl 424 }; 425 426 static int parse_setacl(unsigned char *buffer, uint32_t length, 427 nfs41_upcall *upcall) 428 { 429 int status; 430 setacl_upcall_args *args = &upcall->args.setacl; 431 ULONG sec_desc_len; 432 433 status = safe_read(&buffer, &length, &args->query, sizeof(args->query)); 434 if (status) goto out; 435 status = safe_read(&buffer, &length, &sec_desc_len, sizeof(ULONG)); 436 if (status) goto out; 437 args->sec_desc = (PSECURITY_DESCRIPTOR)buffer; 438 439 dprintf(1, "parsing NFS41_ACL_SET: info_class=%d sec_desc_len=%d\n", 440 args->query, sec_desc_len); 441 out: 442 return status; 443 } 444 445 static int is_well_known_sid(PSID sid, char *who) 446 { 447 int status, i; 448 for (i = 0; i < 78; i++) { 449 status = IsWellKnownSid(sid, (WELL_KNOWN_SID_TYPE)i); 450 if (!status) continue; 451 else { 452 dprintf(ACLLVL, "WELL_KNOWN_SID_TYPE %d\n", i); 453 switch((WELL_KNOWN_SID_TYPE)i) { 454 case WinCreatorOwnerSid: 455 memcpy(who, ACE4_OWNER, strlen(ACE4_OWNER)+1); 456 return TRUE; 457 case WinNullSid: 458 memcpy(who, ACE4_NOBODY, strlen(ACE4_NOBODY)+1); 459 return TRUE; 460 case WinAnonymousSid: 461 memcpy(who, ACE4_ANONYMOUS, strlen(ACE4_ANONYMOUS)+1); 462 return TRUE; 463 case WinWorldSid: 464 memcpy(who, ACE4_EVERYONE, strlen(ACE4_EVERYONE)+1); 465 return TRUE; 466 case WinCreatorGroupSid: 467 case WinBuiltinUsersSid: 468 memcpy(who, ACE4_GROUP, strlen(ACE4_GROUP)+1); 469 return TRUE; 470 case WinAuthenticatedUserSid: 471 memcpy(who, ACE4_AUTHENTICATED, strlen(ACE4_AUTHENTICATED)+1); 472 return TRUE; 473 case WinDialupSid: 474 memcpy(who, ACE4_DIALUP, strlen(ACE4_DIALUP)+1); 475 return TRUE; 476 case WinNetworkSid: 477 memcpy(who, ACE4_NETWORK, strlen(ACE4_NETWORK)+1); 478 return TRUE; 479 case WinBatchSid: 480 memcpy(who, ACE4_BATCH, strlen(ACE4_BATCH)+1); 481 return TRUE; 482 case WinInteractiveSid: 483 memcpy(who, ACE4_INTERACTIVE, strlen(ACE4_INTERACTIVE)+1); 484 return TRUE; 485 case WinNetworkServiceSid: 486 case WinLocalServiceSid: 487 case WinServiceSid: 488 memcpy(who, ACE4_SERVICE, strlen(ACE4_SERVICE)+1); 489 return TRUE; 490 default: return FALSE; 491 } 492 } 493 } 494 return FALSE; 495 } 496 497 static void map_aceflags(BYTE win_aceflags, uint32_t *nfs4_aceflags) 498 { 499 if (win_aceflags & OBJECT_INHERIT_ACE) 500 *nfs4_aceflags |= ACE4_FILE_INHERIT_ACE; 501 if (win_aceflags & CONTAINER_INHERIT_ACE) 502 *nfs4_aceflags |= ACE4_DIRECTORY_INHERIT_ACE; 503 if (win_aceflags & NO_PROPAGATE_INHERIT_ACE) 504 *nfs4_aceflags |= ACE4_NO_PROPAGATE_INHERIT_ACE; 505 if (win_aceflags & INHERIT_ONLY_ACE) 506 *nfs4_aceflags |= ACE4_INHERIT_ONLY_ACE; 507 if (win_aceflags & INHERITED_ACE) 508 *nfs4_aceflags |= ACE4_INHERITED_ACE; 509 dprintf(ACLLVL, "ACE FLAGS: %x nfs4 aceflags %x\n", 510 win_aceflags, *nfs4_aceflags); 511 } 512 513 static void map_acemask(ACCESS_MASK mask, int file_type, uint32_t *nfs4_mask) 514 { 515 dprintf(ACLLVL, "ACE MASK: %x\n", mask); 516 print_windows_access_mask(0, mask); 517 /* check if any GENERIC bits set */ 518 if (mask & 0xf000000) { 519 if (mask & GENERIC_ALL) { 520 if (file_type == NF4DIR) 521 *nfs4_mask |= ACE4_ALL_DIR; 522 else 523 *nfs4_mask |= ACE4_ALL_FILE; 524 } else { 525 if (mask & GENERIC_READ) 526 *nfs4_mask |= ACE4_GENERIC_READ; 527 if (mask & GENERIC_WRITE) 528 *nfs4_mask |= ACE4_GENERIC_WRITE; 529 if (mask & GENERIC_EXECUTE) 530 *nfs4_mask |= ACE4_GENERIC_EXECUTE; 531 } 532 } 533 else /* ignoring generic and reserved bits */ 534 *nfs4_mask = mask & 0x00ffffff; 535 print_nfs_access_mask(0, *nfs4_mask); 536 } 537 538 static int map_nfs4ace_who(PSID sid, PSID owner_sid, PSID group_sid, char *who_out, char *domain) 539 { 540 int status = ERROR_INTERNAL_ERROR; 541 DWORD size = 0, tmp_size = 0; 542 SID_NAME_USE sid_type; 543 LPSTR tmp_buf = NULL, who = NULL; 544 545 /* for ace mapping, we want to map owner's sid into "owner@" 546 * but for set_owner attribute we want to map owner into a user name 547 * same applies to group 548 */ 549 status = 0; 550 if (owner_sid) { 551 if (EqualSid(sid, owner_sid)) { 552 dprintf(ACLLVL, "map_nfs4ace_who: this is owner's sid\n"); 553 memcpy(who_out, ACE4_OWNER, strlen(ACE4_OWNER)+1); 554 return ERROR_SUCCESS; 555 } 556 } 557 if (group_sid) { 558 if (EqualSid(sid, group_sid)) { 559 dprintf(ACLLVL, "map_nfs4ace_who: this is group's sid\n"); 560 memcpy(who_out, ACE4_GROUP, strlen(ACE4_GROUP)+1); 561 return ERROR_SUCCESS; 562 } 563 } 564 status = is_well_known_sid(sid, who_out); 565 if (status) { 566 if (!strncmp(who_out, ACE4_NOBODY, strlen(ACE4_NOBODY))) { 567 size = (DWORD)strlen(ACE4_NOBODY); 568 goto add_domain; 569 } 570 else 571 return ERROR_SUCCESS; 572 } 573 574 status = LookupAccountSid(NULL, sid, who, &size, tmp_buf, 575 &tmp_size, &sid_type); 576 dprintf(ACLLVL, "map_nfs4ace_who: LookupAccountSid returned %d GetLastError " 577 "%d name len %d domain len %d\n", status, GetLastError(), 578 size, tmp_size); 579 if (status) 580 return ERROR_INTERNAL_ERROR; 581 status = GetLastError(); 582 if (status != ERROR_INSUFFICIENT_BUFFER) 583 return ERROR_INTERNAL_ERROR; 584 who = malloc(size); 585 if (who == NULL) { 586 status = GetLastError(); 587 goto out; 588 } 589 tmp_buf = malloc(tmp_size); 590 if (tmp_buf == NULL) 591 goto out_free_who; 592 status = LookupAccountSid(NULL, sid, who, &size, tmp_buf, 593 &tmp_size, &sid_type); 594 free(tmp_buf); 595 if (!status) { 596 eprintf("map_nfs4ace_who: LookupAccountSid failed with %d\n", 597 GetLastError()); 598 goto out_free_who; 599 } 600 memcpy(who_out, who, size); 601 add_domain: 602 memcpy(who_out+size, "@", sizeof(char)); 603 memcpy(who_out+size+1, domain, strlen(domain)+1); 604 dprintf(ACLLVL, "map_nfs4ace_who: who=%s\n", who_out); 605 if (who) free(who); 606 status = ERROR_SUCCESS; 607 out: 608 return status; 609 out_free_who: 610 free(who); 611 status = GetLastError(); 612 goto out; 613 } 614 static int map_dacl_2_nfs4acl(PACL acl, PSID sid, PSID gsid, nfsacl41 *nfs4_acl, 615 int file_type, char *domain) 616 { 617 int status; 618 if (acl == NULL) { 619 dprintf(ACLLVL, "this is a NULL dacl: all access to an object\n"); 620 nfs4_acl->count = 1; 621 nfs4_acl->aces = calloc(1, sizeof(nfsace4)); 622 if (nfs4_acl->aces == NULL) { 623 status = GetLastError(); 624 goto out; 625 } 626 nfs4_acl->flag = 0; 627 memcpy(nfs4_acl->aces->who, ACE4_EVERYONE, strlen(ACE4_EVERYONE)+1); 628 nfs4_acl->aces->acetype = ACE4_ACCESS_ALLOWED_ACE_TYPE; 629 if (file_type == NF4DIR) 630 nfs4_acl->aces->acemask = ACE4_ALL_DIR; 631 else 632 nfs4_acl->aces->acemask = ACE4_ALL_FILE; 633 nfs4_acl->aces->aceflag = 0; 634 } else { 635 int i; 636 PACE_HEADER ace; 637 PBYTE tmp_pointer; 638 639 dprintf(ACLLVL, "NON-NULL dacl with %d ACEs\n", acl->AceCount); 640 print_hexbuf_no_asci(3, (unsigned char *)"ACL\n", 641 (unsigned char *)acl, acl->AclSize); 642 nfs4_acl->count = acl->AceCount; 643 nfs4_acl->aces = calloc(nfs4_acl->count, sizeof(nfsace4)); 644 if (nfs4_acl->aces == NULL) { 645 status = GetLastError(); 646 goto out; 647 } 648 nfs4_acl->flag = 0; 649 for (i = 0; i < acl->AceCount; i++) { 650 status = GetAce(acl, i, &ace); 651 if (!status) { 652 status = GetLastError(); 653 eprintf("map_dacl_2_nfs4acl: GetAce failed with %d\n", status); 654 goto out_free; 655 } 656 tmp_pointer = (PBYTE)ace; 657 print_hexbuf_no_asci(3, (unsigned char *)"ACE\n", 658 (unsigned char *)ace, ace->AceSize); 659 dprintf(ACLLVL, "ACE TYPE: %x\n", ace->AceType); 660 if (ace->AceType == ACCESS_ALLOWED_ACE_TYPE) 661 nfs4_acl->aces[i].acetype = ACE4_ACCESS_ALLOWED_ACE_TYPE; 662 else if (ace->AceType == ACCESS_DENIED_ACE_TYPE) 663 nfs4_acl->aces[i].acetype = ACE4_ACCESS_DENIED_ACE_TYPE; 664 else { 665 eprintf("map_dacl_2_nfs4acl: unsupported ACE type %d\n", 666 ace->AceType); 667 status = ERROR_NOT_SUPPORTED; 668 goto out_free; 669 } 670 671 map_aceflags(ace->AceFlags, &nfs4_acl->aces[i].aceflag); 672 map_acemask(*(PACCESS_MASK)(ace + 1), file_type, 673 &nfs4_acl->aces[i].acemask); 674 675 tmp_pointer += sizeof(ACCESS_MASK) + sizeof(ACE_HEADER); 676 status = map_nfs4ace_who(tmp_pointer, sid, gsid, nfs4_acl->aces[i].who, 677 domain); 678 if (status) 679 goto out_free; 680 } 681 } 682 status = ERROR_SUCCESS; 683 out: 684 return status; 685 out_free: 686 free(nfs4_acl->aces); 687 goto out; 688 } 689 690 static int handle_setacl(nfs41_upcall *upcall) 691 { 692 int status = ERROR_NOT_SUPPORTED; 693 setacl_upcall_args *args = &upcall->args.setacl; 694 nfs41_open_state *state = upcall->state_ref; 695 nfs41_file_info info = { 0 }; 696 stateid_arg stateid; 697 nfsacl41 nfs4_acl = { 0 }; 698 PSID sid = NULL, gsid = NULL; 699 BOOL sid_default, gsid_default; 700 701 if (args->query & OWNER_SECURITY_INFORMATION) { 702 char owner[NFS4_OPAQUE_LIMIT]; 703 dprintf(ACLLVL, "handle_setacl: OWNER_SECURITY_INFORMATION\n"); 704 status = GetSecurityDescriptorOwner(args->sec_desc, &sid, &sid_default); 705 if (!status) { 706 status = GetLastError(); 707 eprintf("GetSecurityDescriptorOwner failed with %d\n", status); 708 goto out; 709 } 710 info.owner = owner; 711 status = map_nfs4ace_who(sid, NULL, NULL, info.owner, localdomain_name); 712 if (status) 713 goto out; 714 else { 715 info.attrmask.arr[1] |= FATTR4_WORD1_OWNER; 716 info.attrmask.count = 2; 717 } 718 } 719 if (args->query & GROUP_SECURITY_INFORMATION) { 720 char group[NFS4_OPAQUE_LIMIT]; 721 dprintf(ACLLVL, "handle_setacl: GROUP_SECURITY_INFORMATION\n"); 722 status = GetSecurityDescriptorGroup(args->sec_desc, &sid, &sid_default); 723 if (!status) { 724 status = GetLastError(); 725 eprintf("GetSecurityDescriptorOwner failed with %d\n", status); 726 goto out; 727 } 728 info.owner_group = group; 729 status = map_nfs4ace_who(sid, NULL, NULL, info.owner_group, 730 localdomain_name); 731 if (status) 732 goto out; 733 else { 734 info.attrmask.arr[1] |= FATTR4_WORD1_OWNER_GROUP; 735 info.attrmask.count = 2; 736 } 737 } 738 if (args->query & DACL_SECURITY_INFORMATION) { 739 BOOL dacl_present, dacl_default; 740 PACL acl; 741 dprintf(ACLLVL, "handle_setacl: DACL_SECURITY_INFORMATION\n"); 742 status = GetSecurityDescriptorDacl(args->sec_desc, &dacl_present, 743 &acl, &dacl_default); 744 if (!status) { 745 status = GetLastError(); 746 eprintf("GetSecurityDescriptorDacl failed with %d\n", status); 747 goto out; 748 } 749 status = GetSecurityDescriptorOwner(args->sec_desc, &sid, &sid_default); 750 if (!status) { 751 status = GetLastError(); 752 eprintf("GetSecurityDescriptorOwner failed with %d\n", status); 753 goto out; 754 } 755 status = GetSecurityDescriptorGroup(args->sec_desc, &gsid, &gsid_default); 756 if (!status) { 757 status = GetLastError(); 758 eprintf("GetSecurityDescriptorOwner failed with %d\n", status); 759 goto out; 760 } 761 status = map_dacl_2_nfs4acl(acl, sid, gsid, &nfs4_acl, state->type, 762 localdomain_name); 763 if (status) 764 goto out; 765 else { 766 info.acl = &nfs4_acl; 767 info.attrmask.arr[0] |= FATTR4_WORD0_ACL; 768 if (!info.attrmask.count) 769 info.attrmask.count = 1; 770 } 771 } 772 773 /* break read delegations before SETATTR */ 774 nfs41_delegation_return(state->session, &state->file, 775 OPEN_DELEGATE_WRITE, FALSE); 776 777 nfs41_open_stateid_arg(state, &stateid); 778 status = nfs41_setattr(state->session, &state->file, &stateid, &info); 779 if (status) { 780 dprintf(ACLLVL, "handle_setacl: nfs41_setattr() failed with error %s.\n", 781 nfs_error_string(status)); 782 status = nfs_to_windows_error(status, ERROR_NOT_SUPPORTED); 783 } 784 args->ctime = info.change; 785 if (args->query & DACL_SECURITY_INFORMATION) 786 free(nfs4_acl.aces); 787 out: 788 return status; 789 } 790 791 static int marshall_setacl(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall) 792 { 793 setacl_upcall_args *args = &upcall->args.setacl; 794 return safe_write(&buffer, length, &args->ctime, sizeof(args->ctime)); 795 } 796 797 const nfs41_upcall_op nfs41_op_setacl = { 798 parse_setacl, 799 handle_setacl, 800 marshall_setacl 801 };