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.
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.
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]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
30 #include <smbsrv/smb.h>
31 #include <smbsrv/smb_sid.h>
32 #include <smbsrv/smb_idmap.h>
34 #define ACE_ALL_TYPES 0x001F
37 * ACE groups within a DACL
39 * This is from lower to higher ACE order priority
41 #define SMB_AG_START 0
42 #define SMB_AG_ALW_INHRT 0
43 #define SMB_AG_DNY_INHRT 1
44 #define SMB_AG_ALW_DRCT 2
45 #define SMB_AG_DNY_DRCT 3
48 #define DEFAULT_DACL_ACENUM 2
49 acl_t
*acl_alloc(enum acl_type
);
51 static idmap_stat
smb_fsacl_getsids(smb_idmap_batch_t
*, acl_t
*);
52 static acl_t
*smb_fsacl_null_empty(boolean_t
);
53 static uint16_t smb_ace_len(smb_ace_t
*);
54 static uint32_t smb_ace_mask_g2s(uint32_t);
55 static uint16_t smb_ace_flags_tozfs(uint8_t);
56 static uint8_t smb_ace_flags_fromzfs(uint16_t);
57 static boolean_t
smb_ace_wellknown_update(const char *, ace_t
*);
60 smb_acl_alloc(uint8_t revision
, uint16_t bsize
, uint16_t acecnt
)
65 size
= sizeof (smb_acl_t
) + (acecnt
* sizeof (smb_ace_t
));
66 if ((acl
= malloc(size
)) == NULL
)
69 acl
->sl_revision
= revision
;
70 acl
->sl_bsize
= bsize
;
71 acl
->sl_acecnt
= acecnt
;
72 acl
->sl_aces
= (smb_ace_t
*)(acl
+ 1);
74 list_create(&acl
->sl_sorted
, sizeof (smb_ace_t
),
75 offsetof(smb_ace_t
, se_sln
));
80 smb_acl_free(smb_acl_t
*acl
)
88 for (i
= 0; i
< acl
->sl_acecnt
; i
++)
89 smb_sid_free(acl
->sl_aces
[i
].se_sid
);
91 while ((ace
= list_head(&acl
->sl_sorted
)) != NULL
)
92 list_remove(&acl
->sl_sorted
, ace
);
93 list_destroy(&acl
->sl_sorted
);
101 * Returns the size of given ACL in bytes. Note that this
102 * is not an in-memory size, it's the ACL's size as it would
106 smb_acl_len(smb_acl_t
*acl
)
108 return ((acl
) ? acl
->sl_bsize
: 0);
113 smb_acl_isvalid(smb_acl_t
*acl
, int which_acl
)
115 if (acl
->sl_bsize
< SMB_ACL_HDRSIZE
)
118 if (acl
->sl_revision
!= ACL_REVISION
) {
120 * we are rejecting ACLs with object-specific ACEs for now
131 * Sorts the given ACL in place if it needs to be sorted.
133 * The following is an excerpt from MSDN website.
135 * Order of ACEs in a DACL
137 * For Windows NT versions 4.0 and earlier, the preferred order of ACEs
138 * is simple: In a DACL, all access-denied ACEs should precede any
139 * access-allowed ACEs.
141 * For Windows 2000 or later, the proper order of ACEs is more complicated
142 * because of the introduction of object-specific ACEs and automatic
145 * The following describes the preferred order:
147 * To ensure that noninherited ACEs have precedence over inherited ACEs,
148 * place all noninherited ACEs in a group before any inherited ACEs. This
149 * ordering ensures, for example, that a noninherited access-denied ACE
150 * is enforced regardless of any inherited ACE that allows access.
151 * Within the groups of noninherited ACEs and inherited ACEs, order ACEs
152 * according to ACE type, as the following shows:
153 * . Access-denied ACEs that apply to the object itself
154 * . Access-denied ACEs that apply to a subobject of the
155 * object, such as a property set or property
156 * . Access-allowed ACEs that apply to the object itself
157 * . Access-allowed ACEs that apply to a subobject of the object
159 * So, here is the desired ACE order
161 * deny-direct, allow-direct, deny-inherited, allow-inherited
163 * Of course, not all ACE types are required in an ACL.
166 smb_acl_sort(smb_acl_t
*acl
)
168 list_t ace_grps
[SMB_AG_NUM
];
176 if (acl
->sl_acecnt
== 0) {
178 * ACL with no entry is a valid ACL and it means
179 * no access for anybody.
184 for (i
= SMB_AG_START
; i
< SMB_AG_NUM
; i
++) {
185 list_create(&ace_grps
[i
], sizeof (smb_ace_t
),
186 offsetof(smb_ace_t
, se_sln
));
189 for (i
= 0, ace
= acl
->sl_aces
; i
< acl
->sl_acecnt
; ++i
, ace
++) {
190 ace_flags
= ace
->se_hdr
.se_flags
;
192 switch (ace
->se_hdr
.se_type
) {
193 case ACCESS_DENIED_ACE_TYPE
:
194 ag
= (ace_flags
& INHERITED_ACE
) ?
195 SMB_AG_DNY_INHRT
: SMB_AG_DNY_DRCT
;
198 case ACCESS_ALLOWED_ACE_TYPE
:
199 ag
= (ace_flags
& INHERITED_ACE
) ?
200 SMB_AG_ALW_INHRT
: SMB_AG_ALW_DRCT
;
205 * This is the lowest priority group so we put
206 * evertything unknown here.
208 ag
= SMB_AG_ALW_INHRT
;
212 /* Add the ACE to the selected group */
213 list_insert_tail(&ace_grps
[ag
], ace
);
217 * start with highest priority ACE group and append
218 * the ACEs to the ACL.
220 for (i
= SMB_AG_NUM
- 1; i
>= SMB_AG_START
; i
--) {
221 alist
= &ace_grps
[i
];
222 while ((ace
= list_head(alist
)) != NULL
) {
223 list_remove(alist
, ace
);
224 list_insert_tail(&acl
->sl_sorted
, ace
);
233 * Converts given ZFS ACL to a Windows ACL.
235 * A pointer to allocated memory for the Windows ACL will be
236 * returned upon successful conversion.
239 smb_acl_from_zfs(acl_t
*zacl
)
245 smb_idmap_batch_t sib
;
249 idm_stat
= smb_idmap_batch_create(&sib
, zacl
->acl_cnt
,
251 if (idm_stat
!= IDMAP_SUCCESS
)
254 if (smb_fsacl_getsids(&sib
, zacl
) != IDMAP_SUCCESS
) {
255 smb_idmap_batch_destroy(&sib
);
259 acl
= smb_acl_alloc(ACL_REVISION
, SMB_ACL_HDRSIZE
, zacl
->acl_cnt
);
262 for (numaces
= 0, zace
= zacl
->acl_aclp
;
263 numaces
< zacl
->acl_cnt
;
264 zace
++, numaces
++, sim
++) {
265 assert(sim
->sim_sid
);
266 if (sim
->sim_sid
== NULL
) {
272 ace
= &acl
->sl_aces
[numaces
];
273 ace
->se_hdr
.se_type
= zace
->a_type
;
274 ace
->se_hdr
.se_flags
= smb_ace_flags_fromzfs(zace
->a_flags
);
275 ace
->se_mask
= zace
->a_access_mask
;
276 ace
->se_sid
= smb_sid_dup(sim
->sim_sid
);
277 ace
->se_hdr
.se_bsize
= smb_ace_len(ace
);
279 acl
->sl_bsize
+= ace
->se_hdr
.se_bsize
;
282 smb_idmap_batch_destroy(&sib
);
289 * Converts given Windows ACL to a ZFS ACL.
291 * fs_acl will contain a pointer to the created ZFS ACL.
292 * The allocated memory should be freed by calling
295 * Since the output parameter, fs_acl, is allocated in this
296 * function, the caller has to make sure *fs_acl is NULL which
297 * means it's not pointing to any memory.
300 smb_acl_to_zfs(smb_acl_t
*acl
, uint32_t flags
, int which_acl
, acl_t
**fs_acl
)
302 char sidstr
[SMB_SID_STRSZ
];
306 smb_idmap_batch_t sib
;
312 assert(*fs_acl
== NULL
);
314 if (acl
&& !smb_acl_isvalid(acl
, which_acl
))
315 return (NT_STATUS_INVALID_ACL
);
317 if ((acl
== NULL
) || (acl
->sl_acecnt
== 0)) {
318 if (which_acl
== SMB_DACL_SECINFO
) {
319 *fs_acl
= smb_fsacl_null_empty(acl
== NULL
);
322 return (NT_STATUS_SUCCESS
);
325 idm_stat
= smb_idmap_batch_create(&sib
, acl
->sl_acecnt
,
327 if (idm_stat
!= IDMAP_SUCCESS
)
328 return (NT_STATUS_INTERNAL_ERROR
);
330 zacl
= smb_fsacl_alloc(acl
->sl_acecnt
, flags
);
332 zace
= zacl
->acl_aclp
;
336 for (i
= 0; i
< acl
->sl_acecnt
; i
++, zace
++, ace
++, sim
++) {
337 zace
->a_type
= ace
->se_hdr
.se_type
& ACE_ALL_TYPES
;
338 zace
->a_access_mask
= smb_ace_mask_g2s(ace
->se_mask
);
339 zace
->a_flags
= smb_ace_flags_tozfs(ace
->se_hdr
.se_flags
);
340 zace
->a_who
= (uid_t
)-1;
342 smb_sid_tostr(ace
->se_sid
, sidstr
);
344 if (!smb_ace_wellknown_update(sidstr
, zace
)) {
345 sim
->sim_id
= &zace
->a_who
;
346 idm_stat
= smb_idmap_batch_getid(sib
.sib_idmaph
, sim
,
347 ace
->se_sid
, SMB_IDMAP_UNKNOWN
);
349 if (idm_stat
!= IDMAP_SUCCESS
) {
350 smb_fsacl_free(zacl
);
351 smb_idmap_batch_destroy(&sib
);
352 return (NT_STATUS_INTERNAL_ERROR
);
357 idm_stat
= smb_idmap_batch_getmappings(&sib
);
358 if (idm_stat
!= IDMAP_SUCCESS
) {
359 smb_fsacl_free(zacl
);
360 smb_idmap_batch_destroy(&sib
);
361 return (NT_STATUS_NONE_MAPPED
);
365 * Set the ACEs group flag based on the type of ID returned.
367 zace
= zacl
->acl_aclp
;
370 for (i
= 0; i
< acl
->sl_acecnt
; i
++, zace
++, ace
++, sim
++) {
371 if (zace
->a_who
== (uid_t
)-1)
374 if (sim
->sim_idtype
== SMB_IDMAP_GROUP
)
375 zace
->a_flags
|= ACE_IDENTIFIER_GROUP
;
378 smb_idmap_batch_destroy(&sib
);
381 return (NT_STATUS_SUCCESS
);
385 smb_ace_wellknown_update(const char *sid
, ace_t
*zace
)
391 { NT_WORLD_SIDSTR
, ACE_EVERYONE
},
392 { NT_BUILTIN_CURRENT_OWNER_SIDSTR
, ACE_OWNER
},
393 { NT_BUILTIN_CURRENT_GROUP_SIDSTR
,
394 (ACE_GROUP
| ACE_IDENTIFIER_GROUP
) },
399 for (i
= 0; i
< (sizeof (map
) / sizeof (map
[0])); ++i
) {
400 if (strcmp(sid
, map
[i
].sid
) == 0) {
401 zace
->a_flags
|= map
[i
].flags
;
412 * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs.
415 smb_fsacl_getsids(smb_idmap_batch_t
*sib
, acl_t
*zacl
)
425 for (i
= 0, zace
= zacl
->acl_aclp
; i
< zacl
->acl_cnt
;
426 zace
++, i
++, sim
++) {
427 switch (zace
->a_flags
& ACE_TYPE_FLAGS
) {
429 idtype
= SMB_IDMAP_OWNERAT
;
432 case (ACE_GROUP
| ACE_IDENTIFIER_GROUP
):
434 idtype
= SMB_IDMAP_GROUPAT
;
437 case ACE_IDENTIFIER_GROUP
:
440 idtype
= SMB_IDMAP_GROUP
;
444 idtype
= SMB_IDMAP_EVERYONE
;
450 idtype
= SMB_IDMAP_USER
;
453 idm_stat
= smb_idmap_batch_getsid(sib
->sib_idmaph
, sim
,
456 if (idm_stat
!= IDMAP_SUCCESS
) {
461 idm_stat
= smb_idmap_batch_getmappings(sib
);
466 * smb_fsacl_null_empty
468 * NULL DACL means everyone full-access
469 * Empty DACL means everyone full-deny
471 * ZFS ACL must have at least one entry so smb server has
472 * to simulate the aforementioned expected behavior by adding
473 * an entry in case the requested DACL is null or empty. Adding
474 * a everyone full-deny entry has proved to be problematic in
475 * tests since a deny entry takes precedence over allow entries.
476 * So, instead of adding a everyone full-deny, an owner ACE with
477 * owner implicit permissions will be set.
480 smb_fsacl_null_empty(boolean_t null
)
485 zacl
= smb_fsacl_alloc(1, ACL_AUTO_INHERIT
);
486 zace
= zacl
->acl_aclp
;
488 zace
->a_type
= ACE_ACCESS_ALLOWED_ACE_TYPE
;
490 zace
->a_access_mask
= ACE_ALL_PERMS
;
491 zace
->a_flags
= ACE_EVERYONE
;
493 zace
->a_access_mask
= ACE_READ_ACL
| ACE_WRITE_ACL
|
495 zace
->a_flags
= ACE_OWNER
;
502 * FS ACL (acl_t) Functions
505 smb_fsacl_alloc(int acenum
, int flags
)
509 acl
= acl_alloc(ACE_T
);
510 acl
->acl_cnt
= acenum
;
511 if ((acl
->acl_aclp
= malloc(acl
->acl_entry_size
* acenum
)) == NULL
)
514 acl
->acl_flags
= flags
;
519 smb_fsacl_free(acl_t
*acl
)
532 * Returns the length of the given ACE as it appears in an
533 * ACL on the wire (i.e. a flat buffer which contains the SID)
536 smb_ace_len(smb_ace_t
*ace
)
544 return (SMB_ACE_HDRSIZE
+ sizeof (ace
->se_mask
) +
545 smb_sid_len(ace
->se_sid
));
551 * Converts generic access bits in the given mask (if any)
552 * to file specific bits. Generic access masks shouldn't be
553 * stored in filesystem ACEs.
556 smb_ace_mask_g2s(uint32_t mask
)
558 if (mask
& GENERIC_ALL
) {
559 mask
&= ~(GENERIC_ALL
| GENERIC_READ
| GENERIC_WRITE
562 mask
|= FILE_ALL_ACCESS
;
566 if (mask
& GENERIC_READ
) {
567 mask
&= ~GENERIC_READ
;
568 mask
|= FILE_GENERIC_READ
;
571 if (mask
& GENERIC_WRITE
) {
572 mask
&= ~GENERIC_WRITE
;
573 mask
|= FILE_GENERIC_WRITE
;
576 if (mask
& GENERIC_EXECUTE
) {
577 mask
&= ~GENERIC_EXECUTE
;
578 mask
|= FILE_GENERIC_EXECUTE
;
585 * smb_ace_flags_tozfs
587 * This function maps the flags which have different values
588 * in Windows and Solaris. The ones with the same value are
589 * transferred untouched.
592 smb_ace_flags_tozfs(uint8_t c_flags
)
594 uint16_t z_flags
= 0;
596 if (c_flags
& SUCCESSFUL_ACCESS_ACE_FLAG
)
597 z_flags
|= ACE_SUCCESSFUL_ACCESS_ACE_FLAG
;
599 if (c_flags
& FAILED_ACCESS_ACE_FLAG
)
600 z_flags
|= ACE_FAILED_ACCESS_ACE_FLAG
;
602 if (c_flags
& INHERITED_ACE
)
603 z_flags
|= ACE_INHERITED_ACE
;
605 z_flags
|= (c_flags
& ACE_INHERIT_FLAGS
);
611 smb_ace_flags_fromzfs(uint16_t z_flags
)
615 c_flags
= z_flags
& ACE_INHERIT_FLAGS
;
617 if (z_flags
& ACE_SUCCESSFUL_ACCESS_ACE_FLAG
)
618 c_flags
|= SUCCESSFUL_ACCESS_ACE_FLAG
;
620 if (z_flags
& ACE_FAILED_ACCESS_ACE_FLAG
)
621 c_flags
|= FAILED_ACCESS_ACE_FLAG
;
623 if (z_flags
& ACE_INHERITED_ACE
)
624 c_flags
|= INHERITED_ACE
;