1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2023 RackTop Systems, Inc.
26 */
27
28 /*
29 * SMB server interfaces for ACL conversion (smb_acl_...)
30 *
31 * There are two variants of this interface:
32 * This is the library version. See also:
33 * $SRC/uts/common/fs/smbsrv/smb_acl.c
34 */
35
36 #include <stddef.h>
37 #include <strings.h>
38 #include <syslog.h>
39 #include <assert.h>
40
41 #include <smbsrv/smb.h>
42 #include <smbsrv/smb_sid.h>
43 #include <smbsrv/smb_idmap.h>
44
45 #define ACE_ALL_TYPES 0x001F
46
47 /*
48 * ACE groups within a DACL
49 *
50 * This is from lower to higher ACE order priority
51 */
52 #define SMB_AG_START 0
53 #define SMB_AG_ALW_INHRT 0
54 #define SMB_AG_DNY_INHRT 1
55 #define SMB_AG_ALW_DRCT 2
56 #define SMB_AG_DNY_DRCT 3
57 #define SMB_AG_NUM 4
58
59 #define DEFAULT_DACL_ACENUM 2
60 acl_t *acl_alloc(enum acl_type);
61
62 static idmap_stat smb_fsacl_getsids(smb_idmap_batch_t *, acl_t *);
63 static acl_t *smb_fsacl_null_empty(boolean_t);
64 static boolean_t smb_ace_isvalid(smb_ace_t *, int);
65 static uint16_t smb_ace_len(smb_ace_t *);
66 static uint32_t smb_ace_mask_g2s(uint32_t);
67 static uint16_t smb_ace_flags_tozfs(uint8_t);
68 static uint8_t smb_ace_flags_fromzfs(uint16_t);
69 static boolean_t smb_ace_wellknown_update(const char *, ace_t *);
70
71 smb_acl_t *
smb_acl_alloc(uint8_t revision,uint16_t bsize,uint16_t acecnt)72 smb_acl_alloc(uint8_t revision, uint16_t bsize, uint16_t acecnt)
73 {
74 smb_acl_t *acl;
75 int size;
76
77 size = sizeof (smb_acl_t) + (acecnt * sizeof (smb_ace_t));
78 if ((acl = malloc(size)) == NULL)
79 return (NULL);
80
81 acl->sl_revision = revision;
82 acl->sl_bsize = bsize;
83 acl->sl_acecnt = acecnt;
84 acl->sl_aces = (smb_ace_t *)(acl + 1);
85
86 list_create(&acl->sl_sorted, sizeof (smb_ace_t),
87 offsetof(smb_ace_t, se_sln));
88 return (acl);
89 }
90
91 void
smb_acl_free(smb_acl_t * acl)92 smb_acl_free(smb_acl_t *acl)
93 {
94 int i;
95 void *ace;
96
97 if (acl == NULL)
98 return;
99
100 for (i = 0; i < acl->sl_acecnt; i++)
101 smb_sid_free(acl->sl_aces[i].se_sid);
102
103 while ((ace = list_head(&acl->sl_sorted)) != NULL)
104 list_remove(&acl->sl_sorted, ace);
105 list_destroy(&acl->sl_sorted);
106 free(acl);
107 }
108
109 /*
110 * smb_acl_len
111 *
112 * Returns the size of given ACL in bytes. Note that this
113 * is not an in-memory size, it's the ACL's size as it would
114 * appear on the wire
115 */
116 uint16_t
smb_acl_len(smb_acl_t * acl)117 smb_acl_len(smb_acl_t *acl)
118 {
119 return ((acl) ? acl->sl_bsize : 0);
120 }
121
122 boolean_t
smb_acl_isvalid(smb_acl_t * acl,int which_acl)123 smb_acl_isvalid(smb_acl_t *acl, int which_acl)
124 {
125 int i;
126
127 if (acl->sl_bsize < SMB_ACL_HDRSIZE)
128 return (B_FALSE);
129
130 if (acl->sl_revision != ACL_REVISION) {
131 /*
132 * we are rejecting ACLs with object-specific ACEs for now
133 */
134 return (B_FALSE);
135 }
136
137 for (i = 0; i < acl->sl_acecnt; i++) {
138 if (!smb_ace_isvalid(&acl->sl_aces[i], which_acl))
139 return (B_FALSE);
140 }
141
142 return (B_TRUE);
143 }
144
145 /*
146 * smb_acl_sort
147 *
148 * Sorts the given ACL in place if it needs to be sorted.
149 *
150 * The following is an excerpt from MSDN website.
151 *
152 * Order of ACEs in a DACL
153 *
154 * For Windows NT versions 4.0 and earlier, the preferred order of ACEs
155 * is simple: In a DACL, all access-denied ACEs should precede any
156 * access-allowed ACEs.
157 *
158 * For Windows 2000 or later, the proper order of ACEs is more complicated
159 * because of the introduction of object-specific ACEs and automatic
160 * inheritance.
161 *
162 * The following describes the preferred order:
163 *
164 * To ensure that noninherited ACEs have precedence over inherited ACEs,
165 * place all noninherited ACEs in a group before any inherited ACEs. This
166 * ordering ensures, for example, that a noninherited access-denied ACE
167 * is enforced regardless of any inherited ACE that allows access.
168 * Within the groups of noninherited ACEs and inherited ACEs, order ACEs
169 * according to ACE type, as the following shows:
170 * . Access-denied ACEs that apply to the object itself
171 * . Access-denied ACEs that apply to a subobject of the
172 * object, such as a property set or property
173 * . Access-allowed ACEs that apply to the object itself
174 * . Access-allowed ACEs that apply to a subobject of the object
175 *
176 * So, here is the desired ACE order
177 *
178 * deny-direct, allow-direct, deny-inherited, allow-inherited
179 *
180 * Of course, not all ACE types are required in an ACL.
181 */
182 void
smb_acl_sort(smb_acl_t * acl)183 smb_acl_sort(smb_acl_t *acl)
184 {
185 list_t ace_grps[SMB_AG_NUM];
186 list_t *alist;
187 smb_ace_t *ace;
188 uint8_t ace_flags;
189 int ag, i;
190
191 assert(acl);
192
193 if (acl->sl_acecnt == 0) {
194 /*
195 * ACL with no entry is a valid ACL and it means
196 * no access for anybody.
197 */
198 return;
199 }
200
201 for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
202 list_create(&ace_grps[i], sizeof (smb_ace_t),
203 offsetof(smb_ace_t, se_sln));
204 }
205
206 for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; ++i, ace++) {
207 ace_flags = ace->se_hdr.se_flags;
208
209 switch (ace->se_hdr.se_type) {
210 case ACCESS_DENIED_ACE_TYPE:
211 ag = (ace_flags & INHERITED_ACE) ?
212 SMB_AG_DNY_INHRT : SMB_AG_DNY_DRCT;
213 break;
214
215 case ACCESS_ALLOWED_ACE_TYPE:
216 ag = (ace_flags & INHERITED_ACE) ?
217 SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT;
218 break;
219
220 default:
221 /*
222 * This is the lowest priority group so we put
223 * evertything unknown here.
224 */
225 ag = SMB_AG_ALW_INHRT;
226 break;
227 }
228
229 /* Add the ACE to the selected group */
230 list_insert_tail(&ace_grps[ag], ace);
231 }
232
233 /*
234 * start with highest priority ACE group and append
235 * the ACEs to the ACL.
236 */
237 for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) {
238 alist = &ace_grps[i];
239 while ((ace = list_head(alist)) != NULL) {
240 list_remove(alist, ace);
241 list_insert_tail(&acl->sl_sorted, ace);
242 }
243 list_destroy(alist);
244 }
245 }
246
247 /*
248 * Error handling call-back for smb_idmap_batch_getmappings.
249 * Would be nice if this could report the path, but that's not
250 * passed down here. For now, use a dtrace fbt probe here.
251 */
252 static void
smb_acl_bgm_error(smb_idmap_batch_t * sib,smb_idmap_t * sim)253 smb_acl_bgm_error(smb_idmap_batch_t *sib, smb_idmap_t *sim)
254 {
255
256 if ((sib->sib_flags & SMB_IDMAP_SKIP_ERRS) != 0)
257 return;
258
259 if ((sib->sib_flags & SMB_IDMAP_ID2SID) != 0) {
260 /*
261 * Note: The ID and type we asked idmap to map
262 * were saved in *sim_id and sim_idtype.
263 */
264 uid_t id = (sim->sim_id == NULL) ? (uid_t)-1 : *sim->sim_id;
265 syslog(LOG_ERR, "!smb_acl: Can't get SID for "
266 "ID=%u type=%d, status=%d",
267 id, sim->sim_idtype, sim->sim_stat);
268 }
269
270 if ((sib->sib_flags & SMB_IDMAP_SID2ID) != 0) {
271 syslog(LOG_ERR, "!smb_acl: Can't get ID for "
272 "SID %s-%u, status=%d",
273 sim->sim_domsid, sim->sim_rid, sim->sim_stat);
274 }
275 }
276
277 /*
278 * smb_acl_from_zfs
279 *
280 * Converts given ZFS ACL to a Windows ACL.
281 *
282 * A pointer to allocated memory for the Windows ACL will be
283 * returned upon successful conversion.
284 */
285 smb_acl_t *
smb_acl_from_zfs(acl_t * zacl)286 smb_acl_from_zfs(acl_t *zacl)
287 {
288 ace_t *zace;
289 int numaces;
290 smb_acl_t *acl;
291 smb_ace_t *ace;
292 smb_idmap_batch_t sib;
293 smb_idmap_t *sim;
294 idmap_stat idm_stat;
295
296 idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt,
297 SMB_IDMAP_ID2SID);
298 if (idm_stat != IDMAP_SUCCESS)
299 return (NULL);
300
301 /*
302 * Note that smb_fsacl_getsids sets up references in
303 * sib.sib_maps to the zace->a_who fields that live
304 * until smb_idmap_batch_destroy is called.
305 */
306 if (smb_fsacl_getsids(&sib, zacl) != IDMAP_SUCCESS) {
307 smb_idmap_batch_destroy(&sib);
308 return (NULL);
309 }
310
311 acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt);
312
313 sim = sib.sib_maps;
314 for (numaces = 0, zace = zacl->acl_aclp;
315 numaces < zacl->acl_cnt;
316 zace++, numaces++, sim++) {
317 assert(sim->sim_sid);
318 if (sim->sim_sid == NULL) {
319 smb_acl_free(acl);
320 acl = NULL;
321 break;
322 }
323
324 ace = &acl->sl_aces[numaces];
325 ace->se_hdr.se_type = zace->a_type;
326 ace->se_hdr.se_flags = smb_ace_flags_fromzfs(zace->a_flags);
327 ace->se_mask = zace->a_access_mask;
328 ace->se_sid = smb_sid_dup(sim->sim_sid);
329 ace->se_hdr.se_bsize = smb_ace_len(ace);
330
331 acl->sl_bsize += ace->se_hdr.se_bsize;
332 }
333
334 smb_idmap_batch_destroy(&sib);
335 return (acl);
336 }
337
338 /*
339 * smb_acl_to_zfs
340 *
341 * Converts given Windows ACL to a ZFS ACL.
342 *
343 * fs_acl will contain a pointer to the created ZFS ACL.
344 * The allocated memory should be freed by calling
345 * smb_fsacl_free().
346 *
347 * Since the output parameter, fs_acl, is allocated in this
348 * function, the caller has to make sure *fs_acl is NULL which
349 * means it's not pointing to any memory.
350 */
351 uint32_t
smb_acl_to_zfs(smb_acl_t * acl,uint32_t flags,int which_acl,acl_t ** fs_acl)352 smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl)
353 {
354 char sidstr[SMB_SID_STRSZ];
355 smb_ace_t *ace;
356 acl_t *zacl;
357 ace_t *zace;
358 smb_idmap_batch_t sib;
359 smb_idmap_t *sim;
360 idmap_stat idm_stat;
361 int i;
362
363 assert(fs_acl);
364 assert(*fs_acl == NULL);
365
366 if (acl && !smb_acl_isvalid(acl, which_acl))
367 return (NT_STATUS_INVALID_ACL);
368
369 if ((acl == NULL) || (acl->sl_acecnt == 0)) {
370 if (which_acl == SMB_DACL_SECINFO) {
371 *fs_acl = smb_fsacl_null_empty(acl == NULL);
372 }
373
374 return (NT_STATUS_SUCCESS);
375 }
376
377 idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt,
378 SMB_IDMAP_SID2ID);
379 if (idm_stat != IDMAP_SUCCESS)
380 return (NT_STATUS_INTERNAL_ERROR);
381
382 zacl = smb_fsacl_alloc(acl->sl_acecnt, flags);
383
384 zace = zacl->acl_aclp;
385 ace = acl->sl_aces;
386 sim = sib.sib_maps;
387
388 for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
389 zace->a_type = ace->se_hdr.se_type & ACE_ALL_TYPES;
390 zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask);
391 zace->a_flags = smb_ace_flags_tozfs(ace->se_hdr.se_flags);
392 zace->a_who = (uid_t)-1;
393
394 smb_sid_tostr(ace->se_sid, sidstr);
395
396 if (!smb_ace_wellknown_update(sidstr, zace)) {
397 sim->sim_id = &zace->a_who;
398 idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim,
399 ace->se_sid, SMB_IDMAP_UNKNOWN);
400
401 if (idm_stat != IDMAP_SUCCESS) {
402 smb_fsacl_free(zacl);
403 smb_idmap_batch_destroy(&sib);
404 return (NT_STATUS_INTERNAL_ERROR);
405 }
406 }
407 }
408
409 idm_stat = smb_idmap_batch_getmappings(&sib, smb_acl_bgm_error);
410 if (idm_stat != IDMAP_SUCCESS) {
411 smb_fsacl_free(zacl);
412 smb_idmap_batch_destroy(&sib);
413 return (NT_STATUS_NONE_MAPPED);
414 }
415
416 /*
417 * Set the ACEs group flag based on the type of ID returned.
418 */
419 zace = zacl->acl_aclp;
420 ace = acl->sl_aces;
421 sim = sib.sib_maps;
422 for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
423 if (zace->a_who == (uid_t)-1)
424 continue;
425
426 if (sim->sim_idtype == SMB_IDMAP_GROUP)
427 zace->a_flags |= ACE_IDENTIFIER_GROUP;
428 }
429
430 smb_idmap_batch_destroy(&sib);
431
432 *fs_acl = zacl;
433 return (NT_STATUS_SUCCESS);
434 }
435
436 static boolean_t
smb_ace_wellknown_update(const char * sid,ace_t * zace)437 smb_ace_wellknown_update(const char *sid, ace_t *zace)
438 {
439 struct {
440 char *sid;
441 uint16_t flags;
442 } map[] = {
443 { NT_WORLD_SIDSTR, ACE_EVERYONE },
444 { NT_BUILTIN_CURRENT_OWNER_SIDSTR, ACE_OWNER },
445 { NT_BUILTIN_CURRENT_GROUP_SIDSTR,
446 (ACE_GROUP | ACE_IDENTIFIER_GROUP) },
447 };
448
449 int i;
450
451 for (i = 0; i < (sizeof (map) / sizeof (map[0])); ++i) {
452 if (strcmp(sid, map[i].sid) == 0) {
453 zace->a_flags |= map[i].flags;
454 return (B_TRUE);
455 }
456 }
457
458 return (B_FALSE);
459 }
460
461 /*
462 * smb_fsacl_getsids
463 *
464 * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs.
465 * Note: sib is type SMB_IDMAP_ID2SID, zacl->acl_cnt entries.
466 */
467 static idmap_stat
smb_fsacl_getsids(smb_idmap_batch_t * sib,acl_t * zacl)468 smb_fsacl_getsids(smb_idmap_batch_t *sib, acl_t *zacl)
469 {
470 ace_t *zace;
471 idmap_stat idm_stat;
472 smb_idmap_t *sim;
473 uid_t id;
474 int i, idtype;
475
476 sim = sib->sib_maps;
477
478 for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt;
479 zace++, i++, sim++) {
480 id = (uid_t)-1; /* some types do not need id */
481 switch (zace->a_flags & ACE_TYPE_FLAGS) {
482 case ACE_OWNER:
483 idtype = SMB_IDMAP_OWNERAT;
484 break;
485
486 case (ACE_GROUP | ACE_IDENTIFIER_GROUP):
487 /* owning group */
488 idtype = SMB_IDMAP_GROUPAT;
489 break;
490
491 case ACE_IDENTIFIER_GROUP:
492 /* regular group */
493 idtype = SMB_IDMAP_GROUP;
494 id = zace->a_who;
495 /* for smb_acl_bgm_error ID2SID */
496 sim->sim_id = &zace->a_who;
497 break;
498
499 case ACE_EVERYONE:
500 idtype = SMB_IDMAP_EVERYONE;
501 break;
502
503 default:
504 /* user entry */
505 idtype = SMB_IDMAP_USER;
506 id = zace->a_who;
507 /* for smb_acl_bgm_error ID2SID */
508 sim->sim_id = &zace->a_who;
509 break;
510 }
511
512 idm_stat = smb_idmap_batch_getsid(sib->sib_idmaph, sim,
513 id, idtype);
514
515 if (idm_stat != IDMAP_SUCCESS) {
516 return (idm_stat);
517 }
518 }
519
520 idm_stat = smb_idmap_batch_getmappings(sib, smb_acl_bgm_error);
521 return (idm_stat);
522 }
523
524 /*
525 * smb_fsacl_null_empty
526 *
527 * NULL DACL means everyone full-access
528 * Empty DACL means everyone full-deny
529 *
530 * ZFS ACL must have at least one entry so smb server has
531 * to simulate the aforementioned expected behavior by adding
532 * an entry in case the requested DACL is null or empty. Adding
533 * a everyone full-deny entry has proved to be problematic in
534 * tests since a deny entry takes precedence over allow entries.
535 * So, instead of adding a everyone full-deny, an owner ACE with
536 * owner implicit permissions will be set.
537 */
538 static acl_t *
smb_fsacl_null_empty(boolean_t null)539 smb_fsacl_null_empty(boolean_t null)
540 {
541 acl_t *zacl;
542 ace_t *zace;
543
544 zacl = smb_fsacl_alloc(1, ACL_AUTO_INHERIT);
545 zace = zacl->acl_aclp;
546
547 zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
548 if (null) {
549 zace->a_access_mask = ACE_ALL_PERMS;
550 zace->a_flags = ACE_EVERYONE;
551 } else {
552 zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL |
553 ACE_READ_ATTRIBUTES;
554 zace->a_flags = ACE_OWNER;
555 }
556
557 return (zacl);
558 }
559
560 /*
561 * FS ACL (acl_t) Functions
562 */
563 acl_t *
smb_fsacl_alloc(int acenum,int flags)564 smb_fsacl_alloc(int acenum, int flags)
565 {
566 acl_t *acl;
567
568 acl = acl_alloc(ACE_T);
569 acl->acl_cnt = acenum;
570 if ((acl->acl_aclp = malloc(acl->acl_entry_size * acenum)) == NULL)
571 return (NULL);
572
573 acl->acl_flags = flags;
574 return (acl);
575 }
576
577 void
smb_fsacl_free(acl_t * acl)578 smb_fsacl_free(acl_t *acl)
579 {
580 if (acl)
581 acl_free(acl);
582 }
583
584 /*
585 * ACE Functions
586 */
587
588 /*
589 * This is generic (ACL version 2) vs. object-specific
590 * (ACL version 4) ACE types.
591 */
592 boolean_t
smb_ace_is_generic(int type)593 smb_ace_is_generic(int type)
594 {
595 switch (type) {
596 case ACE_ACCESS_ALLOWED_ACE_TYPE:
597 case ACE_ACCESS_DENIED_ACE_TYPE:
598 case ACE_SYSTEM_AUDIT_ACE_TYPE:
599 case ACE_SYSTEM_ALARM_ACE_TYPE:
600 case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
601 case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
602 case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
603 case ACE_SYSTEM_ALARM_CALLBACK_ACE_TYPE:
604 return (B_TRUE);
605
606 default:
607 break;
608 }
609
610 return (B_FALSE);
611 }
612
613 boolean_t
smb_ace_is_access(int type)614 smb_ace_is_access(int type)
615 {
616 switch (type) {
617 case ACE_ACCESS_ALLOWED_ACE_TYPE:
618 case ACE_ACCESS_DENIED_ACE_TYPE:
619 case ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
620 case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
621 case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
622 case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
623 case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
624 case ACE_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
625 case ACE_ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
626 return (B_TRUE);
627
628 default:
629 break;
630 }
631
632 return (B_FALSE);
633 }
634
635 boolean_t
smb_ace_is_audit(int type)636 smb_ace_is_audit(int type)
637 {
638 switch (type) {
639 case ACE_SYSTEM_AUDIT_ACE_TYPE:
640 case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
641 case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
642 case ACE_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
643 return (B_TRUE);
644
645 default:
646 break;
647 }
648
649 return (B_FALSE);
650 }
651
652 /*
653 * smb_ace_len
654 *
655 * Returns the length of the given ACE as it appears in an
656 * ACL on the wire (i.e. a flat buffer which contains the SID)
657 */
658 static uint16_t
smb_ace_len(smb_ace_t * ace)659 smb_ace_len(smb_ace_t *ace)
660 {
661 assert(ace);
662 assert(ace->se_sid);
663
664 if (ace == NULL)
665 return (0);
666
667 return (SMB_ACE_HDRSIZE + sizeof (ace->se_mask) +
668 smb_sid_len(ace->se_sid));
669 }
670
671 /*
672 * smb_ace_mask_g2s
673 *
674 * Converts generic access bits in the given mask (if any)
675 * to file specific bits. Generic access masks shouldn't be
676 * stored in filesystem ACEs.
677 */
678 static uint32_t
smb_ace_mask_g2s(uint32_t mask)679 smb_ace_mask_g2s(uint32_t mask)
680 {
681 if (mask & GENERIC_ALL) {
682 mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE
683 | GENERIC_EXECUTE);
684
685 mask |= FILE_ALL_ACCESS;
686 return (mask);
687 }
688
689 if (mask & GENERIC_READ) {
690 mask &= ~GENERIC_READ;
691 mask |= FILE_GENERIC_READ;
692 }
693
694 if (mask & GENERIC_WRITE) {
695 mask &= ~GENERIC_WRITE;
696 mask |= FILE_GENERIC_WRITE;
697 }
698
699 if (mask & GENERIC_EXECUTE) {
700 mask &= ~GENERIC_EXECUTE;
701 mask |= FILE_GENERIC_EXECUTE;
702 }
703
704 return (mask);
705 }
706
707 /*
708 * smb_ace_flags_tozfs
709 *
710 * This function maps the flags which have different values
711 * in Windows and Solaris. The ones with the same value are
712 * transferred untouched.
713 */
714 static uint16_t
smb_ace_flags_tozfs(uint8_t c_flags)715 smb_ace_flags_tozfs(uint8_t c_flags)
716 {
717 uint16_t z_flags = 0;
718
719 if (c_flags & SUCCESSFUL_ACCESS_ACE_FLAG)
720 z_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
721
722 if (c_flags & FAILED_ACCESS_ACE_FLAG)
723 z_flags |= ACE_FAILED_ACCESS_ACE_FLAG;
724
725 if (c_flags & INHERITED_ACE)
726 z_flags |= ACE_INHERITED_ACE;
727
728 z_flags |= (c_flags & ACE_INHERIT_FLAGS);
729
730 return (z_flags);
731 }
732
733 static uint8_t
smb_ace_flags_fromzfs(uint16_t z_flags)734 smb_ace_flags_fromzfs(uint16_t z_flags)
735 {
736 uint8_t c_flags;
737
738 c_flags = z_flags & ACE_INHERIT_FLAGS;
739
740 if (z_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
741 c_flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
742
743 if (z_flags & ACE_FAILED_ACCESS_ACE_FLAG)
744 c_flags |= FAILED_ACCESS_ACE_FLAG;
745
746 if (z_flags & ACE_INHERITED_ACE)
747 c_flags |= INHERITED_ACE;
748
749 return (c_flags);
750 }
751
752 static boolean_t
smb_ace_isvalid(smb_ace_t * ace,int which_acl)753 smb_ace_isvalid(smb_ace_t *ace, int which_acl)
754 {
755 uint16_t min_len;
756
757 min_len = sizeof (smb_acehdr_t);
758
759 if (ace->se_hdr.se_bsize < min_len)
760 return (B_FALSE);
761
762 if (smb_ace_is_access(ace->se_hdr.se_type) &&
763 (which_acl != SMB_DACL_SECINFO))
764 return (B_FALSE);
765
766 if (smb_ace_is_audit(ace->se_hdr.se_type) &&
767 (which_acl != SMB_SACL_SECINFO))
768 return (B_FALSE);
769
770 if (smb_ace_is_generic(ace->se_hdr.se_type)) {
771 if (!smb_sid_isvalid(ace->se_sid))
772 return (B_FALSE);
773
774 min_len += sizeof (ace->se_mask);
775 min_len += smb_sid_len(ace->se_sid);
776
777 if (ace->se_hdr.se_bsize < min_len)
778 return (B_FALSE);
779 }
780
781 /*
782 * object-specific ACE validation will be added later.
783 */
784 return (B_TRUE);
785 }
786