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
49acl_t *acl_alloc(enum acl_type);
50
51static idmap_stat smb_fsacl_getsids(smb_idmap_batch_t *, acl_t *);
52static acl_t *smb_fsacl_null_empty(boolean_t);
53static uint16_t smb_ace_len(smb_ace_t *);
54static uint32_t smb_ace_mask_g2s(uint32_t);
55static uint16_t smb_ace_flags_tozfs(uint8_t);
56static uint8_t smb_ace_flags_fromzfs(uint16_t);
57static boolean_t smb_ace_wellknown_update(const char *, ace_t *);
58
59smb_acl_t *
60smb_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
79void
80smb_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 */
105uint16_t
106smb_acl_len(smb_acl_t *acl)
107{
108	return ((acl) ? acl->sl_bsize : 0);
109}
110
111/*ARGSUSED*/
112boolean_t
113smb_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 */
165void
166smb_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 */
238smb_acl_t *
239smb_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 */
299uint32_t
300smb_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
384static boolean_t
385smb_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 */
414static idmap_stat
415smb_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 */
479static acl_t *
480smb_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 */
504acl_t *
505smb_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
518void
519smb_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 */
535static uint16_t
536smb_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 */
555static uint32_t
556smb_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 */
591static uint16_t
592smb_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
610static uint8_t
611smb_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