xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_acl.c (revision dd72704bd9e794056c558153663c739e2012d721)
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 boolean_t
112 smb_acl_isvalid(smb_acl_t *acl, int which_acl __unused)
113 {
114 	if (acl->sl_bsize < SMB_ACL_HDRSIZE)
115 		return (B_FALSE);
116 
117 	if (acl->sl_revision != ACL_REVISION) {
118 		/*
119 		 * we are rejecting ACLs with object-specific ACEs for now
120 		 */
121 		return (B_FALSE);
122 	}
123 
124 	return (B_TRUE);
125 }
126 
127 /*
128  * smb_acl_sort
129  *
130  * Sorts the given ACL in place if it needs to be sorted.
131  *
132  * The following is an excerpt from MSDN website.
133  *
134  * Order of ACEs in a DACL
135  *
136  * For Windows NT versions 4.0 and earlier, the preferred order of ACEs
137  * is simple: In a DACL, all access-denied ACEs should precede any
138  * access-allowed ACEs.
139  *
140  * For Windows 2000 or later, the proper order of ACEs is more complicated
141  * because of the introduction of object-specific ACEs and automatic
142  * inheritance.
143  *
144  * The following describes the preferred order:
145  *
146  * To ensure that noninherited ACEs have precedence over inherited ACEs,
147  * place all noninherited ACEs in a group before any inherited ACEs. This
148  * ordering ensures, for example, that a noninherited access-denied ACE
149  * is enforced regardless of any inherited ACE that allows access.
150  * Within the groups of noninherited ACEs and inherited ACEs, order ACEs
151  * according to ACE type, as the following shows:
152  *	. Access-denied ACEs that apply to the object itself
153  *	. Access-denied ACEs that apply to a subobject of the
154  *	  object, such as a property set or property
155  *	. Access-allowed ACEs that apply to the object itself
156  *	. Access-allowed ACEs that apply to a subobject of the object
157  *
158  * So, here is the desired ACE order
159  *
160  * deny-direct, allow-direct, deny-inherited, allow-inherited
161  *
162  * Of course, not all ACE types are required in an ACL.
163  */
164 void
165 smb_acl_sort(smb_acl_t *acl)
166 {
167 	list_t ace_grps[SMB_AG_NUM];
168 	list_t *alist;
169 	smb_ace_t *ace;
170 	uint8_t ace_flags;
171 	int ag, i;
172 
173 	assert(acl);
174 
175 	if (acl->sl_acecnt == 0) {
176 		/*
177 		 * ACL with no entry is a valid ACL and it means
178 		 * no access for anybody.
179 		 */
180 		return;
181 	}
182 
183 	for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
184 		list_create(&ace_grps[i], sizeof (smb_ace_t),
185 		    offsetof(smb_ace_t, se_sln));
186 	}
187 
188 	for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; ++i, ace++) {
189 		ace_flags = ace->se_hdr.se_flags;
190 
191 		switch (ace->se_hdr.se_type) {
192 		case ACCESS_DENIED_ACE_TYPE:
193 			ag = (ace_flags & INHERITED_ACE) ?
194 			    SMB_AG_DNY_INHRT : SMB_AG_DNY_DRCT;
195 			break;
196 
197 		case ACCESS_ALLOWED_ACE_TYPE:
198 			ag = (ace_flags & INHERITED_ACE) ?
199 			    SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT;
200 			break;
201 
202 		default:
203 			/*
204 			 * This is the lowest priority group so we put
205 			 * evertything unknown here.
206 			 */
207 			ag = SMB_AG_ALW_INHRT;
208 			break;
209 		}
210 
211 		/* Add the ACE to the selected group */
212 		list_insert_tail(&ace_grps[ag], ace);
213 	}
214 
215 	/*
216 	 * start with highest priority ACE group and append
217 	 * the ACEs to the ACL.
218 	 */
219 	for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) {
220 		alist = &ace_grps[i];
221 		while ((ace = list_head(alist)) != NULL) {
222 			list_remove(alist, ace);
223 			list_insert_tail(&acl->sl_sorted, ace);
224 		}
225 		list_destroy(alist);
226 	}
227 }
228 
229 /*
230  * smb_acl_from_zfs
231  *
232  * Converts given ZFS ACL to a Windows ACL.
233  *
234  * A pointer to allocated memory for the Windows ACL will be
235  * returned upon successful conversion.
236  */
237 smb_acl_t *
238 smb_acl_from_zfs(acl_t *zacl)
239 {
240 	ace_t *zace;
241 	int numaces;
242 	smb_acl_t *acl;
243 	smb_ace_t *ace;
244 	smb_idmap_batch_t sib;
245 	smb_idmap_t *sim;
246 	idmap_stat idm_stat;
247 
248 	idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt,
249 	    SMB_IDMAP_ID2SID);
250 	if (idm_stat != IDMAP_SUCCESS)
251 		return (NULL);
252 
253 	if (smb_fsacl_getsids(&sib, zacl) != IDMAP_SUCCESS) {
254 		smb_idmap_batch_destroy(&sib);
255 		return (NULL);
256 	}
257 
258 	acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt);
259 
260 	sim = sib.sib_maps;
261 	for (numaces = 0, zace = zacl->acl_aclp;
262 	    numaces < zacl->acl_cnt;
263 	    zace++, numaces++, sim++) {
264 		assert(sim->sim_sid);
265 		if (sim->sim_sid == NULL) {
266 			smb_acl_free(acl);
267 			acl = NULL;
268 			break;
269 		}
270 
271 		ace = &acl->sl_aces[numaces];
272 		ace->se_hdr.se_type = zace->a_type;
273 		ace->se_hdr.se_flags = smb_ace_flags_fromzfs(zace->a_flags);
274 		ace->se_mask = zace->a_access_mask;
275 		ace->se_sid = smb_sid_dup(sim->sim_sid);
276 		ace->se_hdr.se_bsize = smb_ace_len(ace);
277 
278 		acl->sl_bsize += ace->se_hdr.se_bsize;
279 	}
280 
281 	smb_idmap_batch_destroy(&sib);
282 	return (acl);
283 }
284 
285 /*
286  * smb_acl_to_zfs
287  *
288  * Converts given Windows ACL to a ZFS ACL.
289  *
290  * fs_acl will contain a pointer to the created ZFS ACL.
291  * The allocated memory should be freed by calling
292  * smb_fsacl_free().
293  *
294  * Since the output parameter, fs_acl, is allocated in this
295  * function, the caller has to make sure *fs_acl is NULL which
296  * means it's not pointing to any memory.
297  */
298 uint32_t
299 smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl)
300 {
301 	char sidstr[SMB_SID_STRSZ];
302 	smb_ace_t *ace;
303 	acl_t *zacl;
304 	ace_t *zace;
305 	smb_idmap_batch_t sib;
306 	smb_idmap_t *sim;
307 	idmap_stat idm_stat;
308 	int i;
309 
310 	assert(fs_acl);
311 	assert(*fs_acl == NULL);
312 
313 	if (acl && !smb_acl_isvalid(acl, which_acl))
314 		return (NT_STATUS_INVALID_ACL);
315 
316 	if ((acl == NULL) || (acl->sl_acecnt == 0)) {
317 		if (which_acl == SMB_DACL_SECINFO) {
318 			*fs_acl = smb_fsacl_null_empty(acl == NULL);
319 		}
320 
321 		return (NT_STATUS_SUCCESS);
322 	}
323 
324 	idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt,
325 	    SMB_IDMAP_SID2ID);
326 	if (idm_stat != IDMAP_SUCCESS)
327 		return (NT_STATUS_INTERNAL_ERROR);
328 
329 	zacl = smb_fsacl_alloc(acl->sl_acecnt, flags);
330 
331 	zace = zacl->acl_aclp;
332 	ace = acl->sl_aces;
333 	sim = sib.sib_maps;
334 
335 	for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
336 		zace->a_type = ace->se_hdr.se_type & ACE_ALL_TYPES;
337 		zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask);
338 		zace->a_flags = smb_ace_flags_tozfs(ace->se_hdr.se_flags);
339 		zace->a_who = (uid_t)-1;
340 
341 		smb_sid_tostr(ace->se_sid, sidstr);
342 
343 		if (!smb_ace_wellknown_update(sidstr, zace)) {
344 			sim->sim_id = &zace->a_who;
345 			idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim,
346 			    ace->se_sid, SMB_IDMAP_UNKNOWN);
347 
348 			if (idm_stat != IDMAP_SUCCESS) {
349 				smb_fsacl_free(zacl);
350 				smb_idmap_batch_destroy(&sib);
351 				return (NT_STATUS_INTERNAL_ERROR);
352 			}
353 		}
354 	}
355 
356 	idm_stat = smb_idmap_batch_getmappings(&sib);
357 	if (idm_stat != IDMAP_SUCCESS) {
358 		smb_fsacl_free(zacl);
359 		smb_idmap_batch_destroy(&sib);
360 		return (NT_STATUS_NONE_MAPPED);
361 	}
362 
363 	/*
364 	 * Set the ACEs group flag based on the type of ID returned.
365 	 */
366 	zace = zacl->acl_aclp;
367 	ace = acl->sl_aces;
368 	sim = sib.sib_maps;
369 	for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
370 		if (zace->a_who == (uid_t)-1)
371 			continue;
372 
373 		if (sim->sim_idtype == SMB_IDMAP_GROUP)
374 			zace->a_flags |= ACE_IDENTIFIER_GROUP;
375 	}
376 
377 	smb_idmap_batch_destroy(&sib);
378 
379 	*fs_acl = zacl;
380 	return (NT_STATUS_SUCCESS);
381 }
382 
383 static boolean_t
384 smb_ace_wellknown_update(const char *sid, ace_t *zace)
385 {
386 	struct {
387 		char		*sid;
388 		uint16_t	flags;
389 	} map[] = {
390 		{ NT_WORLD_SIDSTR,			ACE_EVERYONE },
391 		{ NT_BUILTIN_CURRENT_OWNER_SIDSTR,	ACE_OWNER },
392 		{ NT_BUILTIN_CURRENT_GROUP_SIDSTR,
393 			(ACE_GROUP | ACE_IDENTIFIER_GROUP) },
394 	};
395 
396 	int	i;
397 
398 	for (i = 0; i < (sizeof (map) / sizeof (map[0])); ++i) {
399 		if (strcmp(sid, map[i].sid) == 0) {
400 			zace->a_flags |= map[i].flags;
401 			return (B_TRUE);
402 		}
403 	}
404 
405 	return (B_FALSE);
406 }
407 
408 /*
409  * smb_fsacl_getsids
410  *
411  * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs.
412  */
413 static idmap_stat
414 smb_fsacl_getsids(smb_idmap_batch_t *sib, acl_t *zacl)
415 {
416 	ace_t *zace;
417 	idmap_stat idm_stat;
418 	smb_idmap_t *sim;
419 	uid_t id;
420 	int i, idtype;
421 
422 	sim = sib->sib_maps;
423 
424 	for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt;
425 	    zace++, i++, sim++) {
426 		id = (uid_t)-1;	/* some types do not need id */
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