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
parse_getacl(unsigned char * buffer,uint32_t length,nfs41_upcall * upcall)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
create_unknownsid(WELL_KNOWN_SID_TYPE type,PSID * sid,DWORD * sid_len)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
convert_nfs4name_2_user_domain(LPSTR nfs4name,LPSTR * domain)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
map_name_2_sid(DWORD * sid_len,PSID * sid,LPCSTR name)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
free_sids(PSID * sids,int count)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
check_4_special_identifiers(char * who,PSID * sid,DWORD * sid_len,BOOLEAN * flag)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
convert_nfs4acl_2_dacl(nfsacl41 * acl,int file_type,PACL * dacl_out,PSID ** sids_out)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
handle_getacl(nfs41_upcall * upcall)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
marshall_getacl(unsigned char * buffer,uint32_t * length,nfs41_upcall * upcall)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
parse_setacl(unsigned char * buffer,uint32_t length,nfs41_upcall * upcall)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
is_well_known_sid(PSID sid,char * who)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
map_aceflags(BYTE win_aceflags,uint32_t * nfs4_aceflags)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
map_acemask(ACCESS_MASK mask,int file_type,uint32_t * nfs4_mask)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
map_nfs4ace_who(PSID sid,PSID owner_sid,PSID group_sid,char * who_out,char * domain)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 }
map_dacl_2_nfs4acl(PACL acl,PSID sid,PSID gsid,nfsacl41 * nfs4_acl,int file_type,char * domain)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
handle_setacl(nfs41_upcall * upcall)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
marshall_setacl(unsigned char * buffer,uint32_t * length,nfs41_upcall * upcall)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 };
802