8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / smbsrv / libsmb / common / smb_acl.c
blobdf5bc7cfb38b41ae47f26b58d3c6041f202c0d69
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <stddef.h>
27 #include <strings.h>
28 #include <assert.h>
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
46 #define SMB_AG_NUM 4
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 *);
59 smb_acl_t *
60 smb_acl_alloc(uint8_t revision, uint16_t bsize, uint16_t acecnt)
62 smb_acl_t *acl;
63 int size;
65 size = sizeof (smb_acl_t) + (acecnt * sizeof (smb_ace_t));
66 if ((acl = malloc(size)) == NULL)
67 return (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));
76 return (acl);
79 void
80 smb_acl_free(smb_acl_t *acl)
82 int i;
83 void *ace;
85 if (acl == NULL)
86 return;
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);
94 free(acl);
99 * smb_acl_len
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
103 * appear on the wire
105 uint16_t
106 smb_acl_len(smb_acl_t *acl)
108 return ((acl) ? acl->sl_bsize : 0);
111 /*ARGSUSED*/
112 boolean_t
113 smb_acl_isvalid(smb_acl_t *acl, int which_acl)
115 if (acl->sl_bsize < SMB_ACL_HDRSIZE)
116 return (B_FALSE);
118 if (acl->sl_revision != ACL_REVISION) {
120 * we are rejecting ACLs with object-specific ACEs for now
122 return (B_FALSE);
125 return (B_TRUE);
129 * smb_acl_sort
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
143 * inheritance.
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.
165 void
166 smb_acl_sort(smb_acl_t *acl)
168 list_t ace_grps[SMB_AG_NUM];
169 list_t *alist;
170 smb_ace_t *ace;
171 uint8_t ace_flags;
172 int ag, i;
174 assert(acl);
176 if (acl->sl_acecnt == 0) {
178 * ACL with no entry is a valid ACL and it means
179 * no access for anybody.
181 return;
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;
196 break;
198 case ACCESS_ALLOWED_ACE_TYPE:
199 ag = (ace_flags & INHERITED_ACE) ?
200 SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT;
201 break;
203 default:
205 * This is the lowest priority group so we put
206 * evertything unknown here.
208 ag = SMB_AG_ALW_INHRT;
209 break;
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);
226 list_destroy(alist);
231 * smb_acl_from_zfs
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.
238 smb_acl_t *
239 smb_acl_from_zfs(acl_t *zacl)
241 ace_t *zace;
242 int numaces;
243 smb_acl_t *acl;
244 smb_ace_t *ace;
245 smb_idmap_batch_t sib;
246 smb_idmap_t *sim;
247 idmap_stat idm_stat;
249 idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt,
250 SMB_IDMAP_ID2SID);
251 if (idm_stat != IDMAP_SUCCESS)
252 return (NULL);
254 if (smb_fsacl_getsids(&sib, zacl) != IDMAP_SUCCESS) {
255 smb_idmap_batch_destroy(&sib);
256 return (NULL);
259 acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt);
261 sim = sib.sib_maps;
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) {
267 smb_acl_free(acl);
268 acl = NULL;
269 break;
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);
283 return (acl);
287 * smb_acl_to_zfs
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
293 * smb_fsacl_free().
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.
299 uint32_t
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];
303 smb_ace_t *ace;
304 acl_t *zacl;
305 ace_t *zace;
306 smb_idmap_batch_t sib;
307 smb_idmap_t *sim;
308 idmap_stat idm_stat;
309 int i;
311 assert(fs_acl);
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,
326 SMB_IDMAP_SID2ID);
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;
333 ace = acl->sl_aces;
334 sim = sib.sib_maps;
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;
368 ace = acl->sl_aces;
369 sim = sib.sib_maps;
370 for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
371 if (zace->a_who == (uid_t)-1)
372 continue;
374 if (sim->sim_idtype == SMB_IDMAP_GROUP)
375 zace->a_flags |= ACE_IDENTIFIER_GROUP;
378 smb_idmap_batch_destroy(&sib);
380 *fs_acl = zacl;
381 return (NT_STATUS_SUCCESS);
384 static boolean_t
385 smb_ace_wellknown_update(const char *sid, ace_t *zace)
387 struct {
388 char *sid;
389 uint16_t flags;
390 } map[] = {
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) },
397 int i;
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;
402 return (B_TRUE);
406 return (B_FALSE);
410 * smb_fsacl_getsids
412 * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs.
414 static idmap_stat
415 smb_fsacl_getsids(smb_idmap_batch_t *sib, acl_t *zacl)
417 ace_t *zace;
418 idmap_stat idm_stat;
419 smb_idmap_t *sim;
420 uid_t id;
421 int i, idtype;
423 sim = sib->sib_maps;
425 for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt;
426 zace++, i++, sim++) {
427 switch (zace->a_flags & ACE_TYPE_FLAGS) {
428 case ACE_OWNER:
429 idtype = SMB_IDMAP_OWNERAT;
430 break;
432 case (ACE_GROUP | ACE_IDENTIFIER_GROUP):
433 /* owning group */
434 idtype = SMB_IDMAP_GROUPAT;
435 break;
437 case ACE_IDENTIFIER_GROUP:
438 /* regular group */
439 id = zace->a_who;
440 idtype = SMB_IDMAP_GROUP;
441 break;
443 case ACE_EVERYONE:
444 idtype = SMB_IDMAP_EVERYONE;
445 break;
447 default:
448 /* user entry */
449 id = zace->a_who;
450 idtype = SMB_IDMAP_USER;
453 idm_stat = smb_idmap_batch_getsid(sib->sib_idmaph, sim,
454 id, idtype);
456 if (idm_stat != IDMAP_SUCCESS) {
457 return (idm_stat);
461 idm_stat = smb_idmap_batch_getmappings(sib);
462 return (idm_stat);
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.
479 static acl_t *
480 smb_fsacl_null_empty(boolean_t null)
482 acl_t *zacl;
483 ace_t *zace;
485 zacl = smb_fsacl_alloc(1, ACL_AUTO_INHERIT);
486 zace = zacl->acl_aclp;
488 zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
489 if (null) {
490 zace->a_access_mask = ACE_ALL_PERMS;
491 zace->a_flags = ACE_EVERYONE;
492 } else {
493 zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL |
494 ACE_READ_ATTRIBUTES;
495 zace->a_flags = ACE_OWNER;
498 return (zacl);
502 * FS ACL (acl_t) Functions
504 acl_t *
505 smb_fsacl_alloc(int acenum, int flags)
507 acl_t *acl;
509 acl = acl_alloc(ACE_T);
510 acl->acl_cnt = acenum;
511 if ((acl->acl_aclp = malloc(acl->acl_entry_size * acenum)) == NULL)
512 return (NULL);
514 acl->acl_flags = flags;
515 return (acl);
518 void
519 smb_fsacl_free(acl_t *acl)
521 if (acl)
522 acl_free(acl);
526 * ACE Functions
530 * smb_ace_len
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)
535 static uint16_t
536 smb_ace_len(smb_ace_t *ace)
538 assert(ace);
539 assert(ace->se_sid);
541 if (ace == NULL)
542 return (0);
544 return (SMB_ACE_HDRSIZE + sizeof (ace->se_mask) +
545 smb_sid_len(ace->se_sid));
549 * smb_ace_mask_g2s
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.
555 static uint32_t
556 smb_ace_mask_g2s(uint32_t mask)
558 if (mask & GENERIC_ALL) {
559 mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE
560 | GENERIC_EXECUTE);
562 mask |= FILE_ALL_ACCESS;
563 return (mask);
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;
581 return (mask);
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.
591 static uint16_t
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);
607 return (z_flags);
610 static uint8_t
611 smb_ace_flags_fromzfs(uint16_t z_flags)
613 uint8_t c_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;
626 return (c_flags);