xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_acl.c (revision e4d060fb4c00d44cd578713eb9a921f594b733b8)
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 
26 #include <stddef.h>
27 #include <strings.h>
28 #include <assert.h>
29 
30 #include <smbsrv/smb.h>
31 #include <smbsrv/smb_sid.h>
32 #include <smbsrv/smb_idmap.h>
33 
34 #define	ACE_ALL_TYPES	0x001F
35 
36 /*
37  * ACE groups within a DACL
38  *
39  * This is from lower to higher ACE order priority
40  */
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
47 
48 #define	DEFAULT_DACL_ACENUM	2
49 acl_t *acl_alloc(enum acl_type);
50 
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 *);
58 
59 smb_acl_t *
60 smb_acl_alloc(uint8_t revision, uint16_t bsize, uint16_t acecnt)
61 {
62 	smb_acl_t *acl;
63 	int size;
64 
65 	size = sizeof (smb_acl_t) + (acecnt * sizeof (smb_ace_t));
66 	if ((acl = malloc(size)) == NULL)
67 		return (NULL);
68 
69 	acl->sl_revision = revision;
70 	acl->sl_bsize = bsize;
71 	acl->sl_acecnt = acecnt;
72 	acl->sl_aces = (smb_ace_t *)(acl + 1);
73 
74 	list_create(&acl->sl_sorted, sizeof (smb_ace_t),
75 	    offsetof(smb_ace_t, se_sln));
76 	return (acl);
77 }
78 
79 void
80 smb_acl_free(smb_acl_t *acl)
81 {
82 	int i;
83 	void *ace;
84 
85 	if (acl == NULL)
86 		return;
87 
88 	for (i = 0; i < acl->sl_acecnt; i++)
89 		smb_sid_free(acl->sl_aces[i].se_sid);
90 
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);
95 
96 }
97 
98 /*
99  * smb_acl_len
100  *
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
104  */
105 uint16_t
106 smb_acl_len(smb_acl_t *acl)
107 {
108 	return ((acl) ? acl->sl_bsize : 0);
109 }
110 
111 /*ARGSUSED*/
112 boolean_t
113 smb_acl_isvalid(smb_acl_t *acl, int which_acl)
114 {
115 	if (acl->sl_bsize < SMB_ACL_HDRSIZE)
116 		return (B_FALSE);
117 
118 	if (acl->sl_revision != ACL_REVISION) {
119 		/*
120 		 * we are rejecting ACLs with object-specific ACEs for now
121 		 */
122 		return (B_FALSE);
123 	}
124 
125 	return (B_TRUE);
126 }
127 
128 /*
129  * smb_acl_sort
130  *
131  * Sorts the given ACL in place if it needs to be sorted.
132  *
133  * The following is an excerpt from MSDN website.
134  *
135  * Order of ACEs in a DACL
136  *
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.
140  *
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.
144  *
145  * The following describes the preferred order:
146  *
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
158  *
159  * So, here is the desired ACE order
160  *
161  * deny-direct, allow-direct, deny-inherited, allow-inherited
162  *
163  * Of course, not all ACE types are required in an ACL.
164  */
165 void
166 smb_acl_sort(smb_acl_t *acl)
167 {
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;
173 
174 	assert(acl);
175 
176 	if (acl->sl_acecnt == 0) {
177 		/*
178 		 * ACL with no entry is a valid ACL and it means
179 		 * no access for anybody.
180 		 */
181 		return;
182 	}
183 
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));
187 	}
188 
189 	for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; ++i, ace++) {
190 		ace_flags = ace->se_hdr.se_flags;
191 
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;
197 
198 		case ACCESS_ALLOWED_ACE_TYPE:
199 			ag = (ace_flags & INHERITED_ACE) ?
200 			    SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT;
201 			break;
202 
203 		default:
204 			/*
205 			 * This is the lowest priority group so we put
206 			 * evertything unknown here.
207 			 */
208 			ag = SMB_AG_ALW_INHRT;
209 			break;
210 		}
211 
212 		/* Add the ACE to the selected group */
213 		list_insert_tail(&ace_grps[ag], ace);
214 	}
215 
216 	/*
217 	 * start with highest priority ACE group and append
218 	 * the ACEs to the ACL.
219 	 */
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);
225 		}
226 		list_destroy(alist);
227 	}
228 }
229 
230 /*
231  * smb_acl_from_zfs
232  *
233  * Converts given ZFS ACL to a Windows ACL.
234  *
235  * A pointer to allocated memory for the Windows ACL will be
236  * returned upon successful conversion.
237  */
238 smb_acl_t *
239 smb_acl_from_zfs(acl_t *zacl)
240 {
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;
248 
249 	idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt,
250 	    SMB_IDMAP_ID2SID);
251 	if (idm_stat != IDMAP_SUCCESS)
252 		return (NULL);
253 
254 	if (smb_fsacl_getsids(&sib, zacl) != IDMAP_SUCCESS) {
255 		smb_idmap_batch_destroy(&sib);
256 		return (NULL);
257 	}
258 
259 	acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt);
260 
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;
270 		}
271 
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);
278 
279 		acl->sl_bsize += ace->se_hdr.se_bsize;
280 	}
281 
282 	smb_idmap_batch_destroy(&sib);
283 	return (acl);
284 }
285 
286 /*
287  * smb_acl_to_zfs
288  *
289  * Converts given Windows ACL to a ZFS ACL.
290  *
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().
294  *
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.
298  */
299 uint32_t
300 smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl)
301 {
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;
310 
311 	assert(fs_acl);
312 	assert(*fs_acl == NULL);
313 
314 	if (acl && !smb_acl_isvalid(acl, which_acl))
315 		return (NT_STATUS_INVALID_ACL);
316 
317 	if ((acl == NULL) || (acl->sl_acecnt == 0)) {
318 		if (which_acl == SMB_DACL_SECINFO) {
319 			*fs_acl = smb_fsacl_null_empty(acl == NULL);
320 		}
321 
322 		return (NT_STATUS_SUCCESS);
323 	}
324 
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);
329 
330 	zacl = smb_fsacl_alloc(acl->sl_acecnt, flags);
331 
332 	zace = zacl->acl_aclp;
333 	ace = acl->sl_aces;
334 	sim = sib.sib_maps;
335 
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;
341 
342 		smb_sid_tostr(ace->se_sid, sidstr);
343 
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);
348 
349 			if (idm_stat != IDMAP_SUCCESS) {
350 				smb_fsacl_free(zacl);
351 				smb_idmap_batch_destroy(&sib);
352 				return (NT_STATUS_INTERNAL_ERROR);
353 			}
354 		}
355 	}
356 
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);
362 	}
363 
364 	/*
365 	 * Set the ACEs group flag based on the type of ID returned.
366 	 */
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;
373 
374 		if (sim->sim_idtype == SMB_IDMAP_GROUP)
375 			zace->a_flags |= ACE_IDENTIFIER_GROUP;
376 	}
377 
378 	smb_idmap_batch_destroy(&sib);
379 
380 	*fs_acl = zacl;
381 	return (NT_STATUS_SUCCESS);
382 }
383 
384 static boolean_t
385 smb_ace_wellknown_update(const char *sid, ace_t *zace)
386 {
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) },
395 	};
396 
397 	int	i;
398 
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);
403 		}
404 	}
405 
406 	return (B_FALSE);
407 }
408 
409 /*
410  * smb_fsacl_getsids
411  *
412  * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs.
413  */
414 static idmap_stat
415 smb_fsacl_getsids(smb_idmap_batch_t *sib, acl_t *zacl)
416 {
417 	ace_t *zace;
418 	idmap_stat idm_stat;
419 	smb_idmap_t *sim;
420 	uid_t id;
421 	int i, idtype;
422 
423 	sim = sib->sib_maps;
424 
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;
431 
432 		case (ACE_GROUP | ACE_IDENTIFIER_GROUP):
433 			/* owning group */
434 			idtype = SMB_IDMAP_GROUPAT;
435 			break;
436 
437 		case ACE_IDENTIFIER_GROUP:
438 			/* regular group */
439 			id = zace->a_who;
440 			idtype = SMB_IDMAP_GROUP;
441 			break;
442 
443 		case ACE_EVERYONE:
444 			idtype = SMB_IDMAP_EVERYONE;
445 			break;
446 
447 		default:
448 			/* user entry */
449 			id = zace->a_who;
450 			idtype = SMB_IDMAP_USER;
451 		}
452 
453 		idm_stat = smb_idmap_batch_getsid(sib->sib_idmaph, sim,
454 		    id, idtype);
455 
456 		if (idm_stat != IDMAP_SUCCESS) {
457 			return (idm_stat);
458 		}
459 	}
460 
461 	idm_stat = smb_idmap_batch_getmappings(sib);
462 	return (idm_stat);
463 }
464 
465 /*
466  * smb_fsacl_null_empty
467  *
468  * NULL DACL means everyone full-access
469  * Empty DACL means everyone full-deny
470  *
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.
478  */
479 static acl_t *
480 smb_fsacl_null_empty(boolean_t null)
481 {
482 	acl_t *zacl;
483 	ace_t *zace;
484 
485 	zacl = smb_fsacl_alloc(1, ACL_AUTO_INHERIT);
486 	zace = zacl->acl_aclp;
487 
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;
496 	}
497 
498 	return (zacl);
499 }
500 
501 /*
502  * FS ACL (acl_t) Functions
503  */
504 acl_t *
505 smb_fsacl_alloc(int acenum, int flags)
506 {
507 	acl_t *acl;
508 
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);
513 
514 	acl->acl_flags = flags;
515 	return (acl);
516 }
517 
518 void
519 smb_fsacl_free(acl_t *acl)
520 {
521 	if (acl)
522 		acl_free(acl);
523 }
524 
525 /*
526  * ACE Functions
527  */
528 
529 /*
530  * smb_ace_len
531  *
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)
534  */
535 static uint16_t
536 smb_ace_len(smb_ace_t *ace)
537 {
538 	assert(ace);
539 	assert(ace->se_sid);
540 
541 	if (ace == NULL)
542 		return (0);
543 
544 	return (SMB_ACE_HDRSIZE + sizeof (ace->se_mask) +
545 	    smb_sid_len(ace->se_sid));
546 }
547 
548 /*
549  * smb_ace_mask_g2s
550  *
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.
554  */
555 static uint32_t
556 smb_ace_mask_g2s(uint32_t mask)
557 {
558 	if (mask & GENERIC_ALL) {
559 		mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE
560 		    | GENERIC_EXECUTE);
561 
562 		mask |= FILE_ALL_ACCESS;
563 		return (mask);
564 	}
565 
566 	if (mask & GENERIC_READ) {
567 		mask &= ~GENERIC_READ;
568 		mask |= FILE_GENERIC_READ;
569 	}
570 
571 	if (mask & GENERIC_WRITE) {
572 		mask &= ~GENERIC_WRITE;
573 		mask |= FILE_GENERIC_WRITE;
574 	}
575 
576 	if (mask & GENERIC_EXECUTE) {
577 		mask &= ~GENERIC_EXECUTE;
578 		mask |= FILE_GENERIC_EXECUTE;
579 	}
580 
581 	return (mask);
582 }
583 
584 /*
585  * smb_ace_flags_tozfs
586  *
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.
590  */
591 static uint16_t
592 smb_ace_flags_tozfs(uint8_t c_flags)
593 {
594 	uint16_t z_flags = 0;
595 
596 	if (c_flags & SUCCESSFUL_ACCESS_ACE_FLAG)
597 		z_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
598 
599 	if (c_flags & FAILED_ACCESS_ACE_FLAG)
600 		z_flags |= ACE_FAILED_ACCESS_ACE_FLAG;
601 
602 	if (c_flags & INHERITED_ACE)
603 		z_flags |= ACE_INHERITED_ACE;
604 
605 	z_flags |= (c_flags & ACE_INHERIT_FLAGS);
606 
607 	return (z_flags);
608 }
609 
610 static uint8_t
611 smb_ace_flags_fromzfs(uint16_t z_flags)
612 {
613 	uint8_t c_flags;
614 
615 	c_flags = z_flags & ACE_INHERIT_FLAGS;
616 
617 	if (z_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
618 		c_flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
619 
620 	if (z_flags & ACE_FAILED_ACCESS_ACE_FLAG)
621 		c_flags |= FAILED_ACCESS_ACE_FLAG;
622 
623 	if (z_flags & ACE_INHERITED_ACE)
624 		c_flags |= INHERITED_ACE;
625 
626 	return (c_flags);
627 }
628