1    	/*
2    	 * posix_acls.c
3    	 * vim:noexpandtab:shiftwidth=8:tabstop=8:
4    	 *
5    	 * Copyright (C) Red Hat  Inc., 2015
6    	 * Author: Niels de Vos <ndevos@redhat.com>
7    	 *	   Jiffin Tony Thottan <jthottan@redhat.com>
8    	 *
9    	 * This program is free software; you can redistribute it and/or
10   	 * modify it under the terms of the GNU Lesser General Public
11   	 * License as published by the Free Software Foundation; either
12   	 * version 3 of the License, or (at your option) any later version.
13   	 *
14   	 * This program is distributed in the hope that it will be useful,
15   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   	 * Lesser General Public License for more details.
18   	 *
19   	 * Conversion routines for fsal_acl <-> POSIX ACl
20   	 *
21   	 * Routines based on the description from an Internet Draft that has also been
22   	 * used for the implementation of the conversion in the Linux kernel
23   	 * NFS-server.
24   	 *
25   	 *     Title: Mapping Between NFSv4 and Posix Draft ACLs
26   	 *   Authors: Marius Aamodt Eriksen & J. Bruce Fields
27   	 *       URL: http://tools.ietf.org/html/draft-ietf-nfsv4-acl-mapping-05
28   	 */
29   	
30   	
31   	#include "posix_acls.h"
32   	
33   	/* Checks whether ACE belongs to effective acl (ACCESS TYPE) */
34   	bool is_ace_valid_for_effective_acl_entry(fsal_ace_t *ace)
35   	{
36   		bool ret;
37   	
38   		if (IS_FSAL_ACE_HAS_INHERITANCE_FLAGS(*ace)) {
39   			if (IS_FSAL_ACE_APPLICABLE_FOR_BOTH_ACL(*ace))
40   				ret = true;
41   			else
42   				ret = false;
43   		} else
44   			ret = true;
45   	
46   		return ret;
47   	}
48   	
49   	/* Checks whether ACE belongs to inherited acl (DEFAULT TYPE) */
50   	bool is_ace_valid_for_inherited_acl_entry(fsal_ace_t *ace)
51   	{
52   	
53   		if (IS_FSAL_ACE_APPLICABLE_FOR_BOTH_ACL(*ace)
54   		    || IS_FSAL_ACE_APPLICABLE_ONLY_FOR_INHERITED_ACL(*ace))
55   			return  true;
56   		else
57   			return false;
58   	
59   	}
60   	
61   	/*
62   	 * Check whether given perm(ACL_READ, ACL_WRITE or ACL_EXECUTE) is allowed for
63   	 * a permset, it depends on given ace and permset of @EVERYONE entry.
64   	 */
65   	bool isallow(fsal_ace_t *ace, acl_permset_t everyone, acl_perm_t perm)
66   	{
67   	
68   		bool ret = acl_get_perm(everyone, perm);
69   	
70   		switch (perm) {
71   		case ACL_READ:
72   			ret |= IS_FSAL_ACE_READ_DATA(*ace);
73   			break;
74   		case ACL_WRITE:
75   			ret |= IS_FSAL_ACE_WRITE_DATA(*ace);
76   			break;
77   		case ACL_EXECUTE:
78   			ret |= IS_FSAL_ACE_EXECUTE(*ace);
79   			break;
80   		}
81   	
82   		return ret;
83   	}
84   	
85   	/*
86   	 * Check whether given perm(ACL_READ, ACL_WRITE or ACL_EXECUTE) is denied for a
87   	 * permset, it depends on permsets of deny entry of the acl and @EVERYONE entry.
88   	 */
89   	bool isdeny(acl_permset_t deny, acl_permset_t everyone, acl_perm_t perm)
90   	{
91   	
92   		return acl_get_perm(deny, perm) || acl_get_perm(everyone, perm);
93   	}
94   	
95   	/* Returns no of possible fsal_ace entries from a given posix_acl */
96   	int ace_count(acl_t acl)
97   	{
98   		int ret;
99   	
100  		ret = acl_entries(acl);
101  		if (ret < 0)
102  			return 0;
103  	
104  		/* Mask is not converted to an ace entry */
105  		if (find_entry(acl, ACL_MASK, 0))
106  			ret--;
107  	
108  		return ret;
109  	}
110  	
111  	/*
112  	 * It traverse entire list of entries for a posix acl and finds ACL entry which
113  	 * corresponds to a given tag and id
114  	 *
115  	 * On success , it returns acl entry otherwise it returns NULL
116  	 */
117  	acl_entry_t find_entry(acl_t acl, acl_tag_t tag,  unsigned int id)
118  	{
119  		acl_entry_t entry;
120  		acl_tag_t entryTag;
121  		int ent, ret;
122  	
123  		if (!acl)
124  			return NULL;
125  	
126  		for (ent = ACL_FIRST_ENTRY; ; ent = ACL_NEXT_ENTRY) {
127  			ret = acl_get_entry(acl, ent, &entry);
128  			if (ret == -1) {
129  				LogWarn(COMPONENT_FSAL, "acl_get entry failed errno %d",
130  						errno);
131  			}
132  			if (ret == 0 || ret == -1)
133  				return NULL;
134  	
135  			if (acl_get_tag_type(entry, &entryTag) == -1) {
136  				LogWarn(COMPONENT_FSAL, "No entry tag for ACL Entry");
137  				continue;
138  			}
139  			if (tag == entryTag) {
140  				if (tag == ACL_USER || tag == ACL_GROUP)
141  					if (id != *(unsigned int *)
142  							acl_get_qualifier(entry))
143  						continue;
144  				break;
145  			}
146  		}
147  	
148  		return entry;
149  	}
150  	
151  	/*
152  	 * It tries to find out whether an entry is present in posix acl for the given
153  	 * (tag, id) tuple and returns it. If not , it will create a new entry for
154  	 * given (tag, id).
155  	 *
156  	 * On success , it returns acl entry otherwise it returns NULL
157  	 */
158  	acl_entry_t get_entry(acl_t acl, acl_tag_t tag, unsigned int id)
159  	{
160  		acl_entry_t entry;
161  		int ret;
162  	
163  		if (!acl)
164  			return NULL;
165  		entry = find_entry(acl, tag, id);
166  	
167  		if (!entry) {
168  			ret = acl_create_entry(&acl, &entry);
169  			if (ret) {
170  				LogMajor(COMPONENT_FSAL, "Cannot create entry");
171  				return NULL;
172  			}
173  			ret = acl_set_tag_type(entry, tag);
174  			if (ret)
175  				LogWarn(COMPONENT_FSAL, "Cannot set tag for Entry");
176  			ret = acl_set_qualifier(entry, &id);
177  		}
178  	
179  		return entry;
180  	}
181  	
182  	/*
183  	 *  @brief convert POSIX ACL into an equivalent FSAL ACL
184  	 *
185  	 * @param[in]  p_posixacl	POSIX ACL
186  	 * @param[in]  is_dir		Represents file/directory
187  	 * @param[in]  is_inherit	Represents type of ace entry
188  	 * @param[in]  ace		Stores the starting of fsal_acl_t
189  	 * @param[out] ace		Stores last ace entry in fsal_acl_t
190  	 *
191  	 * @returns no of entries on success and -1 on failure
192  	 */
193  	
194  	int posix_acl_2_fsal_acl(acl_t p_posixacl, bool is_dir, bool is_inherit,
195  				 fsal_ace_t **ace)
196  	{
197  		int ret = 0, ent, d_ent, total = 0;
198  		fsal_ace_t *pace_deny = NULL, *pace_allow = NULL;
199  		acl_t dup_acl;
200  		acl_entry_t entry, mask, other, d_entry, dup_mask;
201  		acl_tag_t tag;
202  		acl_permset_t p_permset;
203  		bool readmask = true, readother = false, readcurrent = true;
204  		bool writemask = true, writeother = false, writecurrent = true;
205  		bool executemask = true, executeother = false, executecurrent = true;
206  	
207  		if (!p_posixacl)
208  			return -1;
209  	
210  		pace_deny = *ace;
211  		pace_allow = (pace_deny + 1);
212  		/* Store the mask entry values */
213  		mask = find_entry(p_posixacl, ACL_MASK, 0);
214  		if (mask) {
215  			ret = acl_get_permset(mask, &p_permset);
216  			if (ret)
217  				LogWarn(COMPONENT_FSAL,
218  				"Cannot retrieve permission set for the Mask Entry");
219  			if (acl_get_perm(p_permset, ACL_READ) == 0)
220  				readmask = false;
221  			if (acl_get_perm(p_permset, ACL_WRITE) == 0)
222  				writemask = false;
223  			if (acl_get_perm(p_permset, ACL_EXECUTE) == 0)
224  				executemask = false;
225  		}
226  	
227  		other = find_entry(p_posixacl, ACL_OTHER, 0);
228  		if (other) {
229  			ret = acl_get_permset(other, &p_permset);
230  			if (ret)
231  				LogWarn(COMPONENT_FSAL,
232  				"Cannot retrieve permission set for the Mask Entry");
233  			if (acl_get_perm(p_permset, ACL_READ) == 1)
234  				readother = true;
235  			if (acl_get_perm(p_permset, ACL_WRITE) == 1)
236  				writeother = true;
237  			if (acl_get_perm(p_permset, ACL_EXECUTE) == 1)
238  				executeother = true;
239  		}
240  	
241  		/* *
242  		 * Converts each entry in posix acl into fsal_ace by filling type, flag,
243  		 * perm, iflag, flag and who(uid, gid) appropiately
244  		 *
245  		 * Corresponding to each posix acl entry, there is a possiblity of two
246  		 * fsal_aces, it can either be ALLOW or DENY. The DENY added to list
247  		 * depending on the permission set set of other entries.
248  		 *
249  		 * Here both entries are created for a posix acl entry and filled up
250  		 * correspondingly. Then at the end unnecessary DENY entries are removed
251  		 * from the list.
252  		 */
253  		for (ent = ACL_FIRST_ENTRY; ; ent = ACL_NEXT_ENTRY) {
254  	
(1) Event value_overwrite: Overwriting previous write to "ret" with value from "acl_get_entry(p_posixacl, ent, &entry)".
Also see events: [value_overwrite][returned_value]
255  			ret = acl_get_entry(p_posixacl, ent, &entry);
256  			if (ret == 0 || ret == -1) {
257  				LogDebug(COMPONENT_FSAL,
258  						"No more ACL entires remaining");
259  				break;
260  			}
261  			if (acl_get_tag_type(entry, &tag) == -1) {
262  				LogWarn(COMPONENT_FSAL, "No entry tag for ACL Entry");
263  				continue;
264  			}
265  	
266  			/* Mask is not converted to a fsal_acl entry , skipping */
267  			if (tag == ACL_MASK)
268  				continue;
269  	
270  			pace_deny->type = FSAL_ACE_TYPE_DENY;
271  			pace_allow->type = FSAL_ACE_TYPE_ALLOW;
272  	
273  			if (is_inherit)
274  				pace_allow->flag = pace_deny->flag =
275  					FSAL_ACE_FLAG_INHERIT;
276  			else
277  				pace_allow->flag = pace_deny->flag = 0;
278  	
279  			/* Finding uid for the fsal_acl entry */
280  			switch (tag) {
281  			case  ACL_USER_OBJ:
282  				pace_allow->who.uid = pace_deny->who.uid =
283  							FSAL_ACE_SPECIAL_OWNER;
284  				pace_allow->iflag = pace_deny->iflag =
285  							FSAL_ACE_IFLAG_SPECIAL_ID;
286  				break;
287  			case  ACL_GROUP_OBJ:
288  				pace_allow->who.uid = pace_deny->who.uid =
289  							FSAL_ACE_SPECIAL_GROUP;
290  				pace_allow->iflag = pace_deny->iflag =
291  							FSAL_ACE_IFLAG_SPECIAL_ID;
292  				break;
293  			case  ACL_OTHER:
294  				pace_allow->who.uid = pace_deny->who.uid =
295  							FSAL_ACE_SPECIAL_EVERYONE;
296  				pace_allow->iflag = pace_deny->iflag =
297  							FSAL_ACE_IFLAG_SPECIAL_ID;
298  				break;
299  			case  ACL_USER:
300  				pace_allow->who.uid = pace_deny->who.uid =
301  						*(uid_t *)acl_get_qualifier(entry);
302  				break;
303  			case  ACL_GROUP:
304  				pace_allow->who.gid = pace_deny->who.gid =
305  						*(gid_t *)acl_get_qualifier(entry);
306  				pace_allow->flag = pace_deny->flag |=
307  							FSAL_ACE_FLAG_GROUP_ID;
308  				break;
309  			default:
310  				LogWarn(COMPONENT_FSAL, "Invalid tag for the acl");
311  			}
312  	
313  			/* *
314  			 * Finding permission set for the fsal_acl ALLOW entry.
315  			 * Conversion purely is based on
316  			 * http://tools.ietf.org/html/draft-ietf-nfsv4-acl-mapping-05
317  			 * */
318  	
319  			/* *
320  			 * Unconditionally all ALLOW ACL Entry should have these
321  			 * permissions
322  			 * */
323  	
324  			pace_allow->perm = FSAL_ACE_PERM_SET_DEFAULT;
325  			pace_deny->perm = 0;
326  	
327  			ret = acl_get_permset(entry, &p_permset);
328  			if (ret) {
329  				LogWarn(COMPONENT_FSAL,
330  				"Cannot retrieve permission set for the ACL Entry");
331  				continue;
332  			}
333  			/* *
334  			 * Consider Mask bits only for ACL_USER, ACL_GROUP,
335  			 * ACL_GROUP_OBJ entries
336  			 * */
337  			if (acl_get_perm(p_permset, ACL_READ)) {
338  				if (tag == ACL_USER_OBJ || tag == ACL_OTHER || readmask)
339  					pace_allow->perm |= FSAL_ACE_PERM_READ_DATA;
340  			} else
341  				readcurrent = false;
342  	
343  			if (acl_get_perm(p_permset, ACL_WRITE)) {
344  				if (tag == ACL_USER_OBJ || tag == ACL_OTHER ||
345  							writemask)
346  					pace_allow->perm |=
347  						FSAL_ACE_PERM_SET_DEFAULT_WRITE;
348  				if (tag == ACL_USER_OBJ)
349  					pace_allow->perm |=
350  						FSAL_ACE_PERM_SET_OWNER_WRITE;
351  				if (is_dir)
352  					pace_allow->perm |=
353  						FSAL_ACE_PERM_DELETE_CHILD;
354  			} else
355  				writecurrent = false;
356  	
357  			if (acl_get_perm(p_permset, ACL_EXECUTE)) {
358  				if (tag == ACL_USER_OBJ || tag == ACL_OTHER ||
359  							executemask)
360  					pace_allow->perm |= FSAL_ACE_PERM_EXECUTE;
361  			} else
362  				executecurrent = false;
363  	
364  			/* *
365  			 * Filling up permission set for DENY entries based on ALLOW
366  			 * entries , if it is applicable.
367  			 * If the tag is ACL_USER_OBJ or ACL_USER then all later posix
368  			 * acl entries should be considered.
369  			 * If the tag is either ACL_GROUP_OBJ or ACL_GROUP then consider
370  			 * only ACL_OTHER.
371  			 */
372  			if (tag == ACL_USER_OBJ || tag == ACL_USER) {
373  				dup_acl = acl_dup(p_posixacl);
374  	
375  				/*
376  				 * Do not consider ACL_MASK entry in the following loop
377  				 */
378  				if (mask) {
379  					dup_mask = find_entry(dup_acl, ACL_MASK, 0);
380  					if (dup_mask)
381  						acl_delete_entry(dup_acl, dup_mask);
382  				}
383  	
384  				if (tag == ACL_USER_OBJ) {
385  					d_entry = find_entry(dup_acl, ACL_USER_OBJ, 0);
(3) Event returned_value: Assigning value from "acl_get_entry(dup_acl, 1, &d_entry)" to "ret" here, but that stored value is overwritten before it can be used.
Also see events: [value_overwrite][value_overwrite]
386  					ret = acl_get_entry(dup_acl, ACL_NEXT_ENTRY,
387  							&d_entry);
388  				} else
389  					d_entry = find_entry(dup_acl, ACL_GROUP_OBJ, 0);
390  	
391  				for (d_ent = ACL_NEXT_ENTRY; ; d_ent = ACL_NEXT_ENTRY) {
(2) Event value_overwrite: Overwriting previous write to "ret" with value from "acl_get_permset(d_entry, &p_permset)".
Also see events: [value_overwrite][returned_value]
392  					ret = acl_get_permset(d_entry, &p_permset);
393  					if (ret) {
394  						LogWarn(COMPONENT_FSAL,
395  						"Cannot retrieve permission set");
396  						continue;
397  					}
398  	
399  					if (!readcurrent &&
400  						acl_get_perm(p_permset, ACL_READ))
401  						pace_deny->perm |=
402  							FSAL_ACE_PERM_READ_DATA;
403  					if (!writecurrent &&
404  						acl_get_perm(p_permset, ACL_WRITE)) {
405  						pace_deny->perm |=
406  							FSAL_ACE_PERM_SET_DEFAULT_WRITE;
407  						if (tag == ACL_USER_OBJ)
408  							pace_deny->perm |=
409  							FSAL_ACE_PERM_SET_OWNER_WRITE;
410  						if (is_dir)
411  							pace_deny->perm |=
412  							FSAL_ACE_PERM_DELETE_CHILD;
413  					}
414  					if (!executecurrent &&
415  						acl_get_perm(p_permset, ACL_EXECUTE))
416  						pace_deny->perm |=
417  							FSAL_ACE_PERM_EXECUTE;
418  					ret = acl_get_entry(dup_acl, d_ent, &d_entry);
419  					if (ret == 0 || ret == -1) {
420  						LogDebug(COMPONENT_FSAL,
421  						"No more ACL entires remaining");
422  						break;
423  					}
424  				}
425  				acl_free(dup_acl);
426  	
427  			} else if (tag == ACL_GROUP_OBJ || tag == ACL_GROUP) {
428  				if (!readcurrent && readother)
429  					pace_deny->perm |= FSAL_ACE_PERM_READ_DATA;
430  				if (!writecurrent && writeother) {
431  					pace_deny->perm |=
432  						FSAL_ACE_PERM_SET_DEFAULT_WRITE;
433  					if (is_dir)
434  						pace_deny->perm |=
435  							FSAL_ACE_PERM_DELETE_CHILD;
436  				}
437  				if (!executecurrent && executeother)
438  					pace_deny->perm |= FSAL_ACE_PERM_EXECUTE;
439  			}
440  			readcurrent = writecurrent = executecurrent = true;
441  	
442  			/* Removing DENY entries if it is not present */
443  			if (pace_deny->perm == 0) {
444  				*pace_deny = *pace_allow;
445  				memset(pace_allow, 0, sizeof(fsal_ace_t));
446  				total += 1;
447  				pace_deny += 1;
448  				pace_allow += 1;
449  			} else {
450  				total += 2;
451  				pace_deny += 2;
452  				pace_allow += 2;
453  			}
454  	
455  	
456  		}
457  	
458  		*ace = pace_allow - 1;/* Returns last entry in the list */
459  		return total; /* Returning no of entries in the list */
460  	}
461  	
462  	/*
463  	 * @brief convert FSAL ACL into an equivalent POSIX ACL
464  	 *
465  	 * @param[in]  p_fsalacl	FSAL ACL
466  	 * @param[in]  type		Represents type of posix acl( ACCESS/DEFAULT )
467  	 *
468  	 * @return acl_t structure
469  	 */
470  	acl_t fsal_acl_2_posix_acl(fsal_acl_t *p_fsalacl, acl_type_t type)
471  	{
472  		int ret = 0, i;
473  		fsal_ace_t *f_ace;
474  		acl_t allow_acl, deny_acl;
475  		acl_entry_t a_entry, d_entry;
476  		acl_permset_t a_permset, e_a_permset, d_permset, e_d_permset;
477  		acl_tag_t tag = -1;
478  		char *acl_str;
479  		unsigned int id;
480  		bool mask = false;
481  		bool deny_e_r = false, deny_e_w = false, deny_e_x = false;
482  	
483  	
484  		if (p_fsalacl == NULL)
485  			return NULL;
486  	
487  		/* *
488  		 * Check whether ace list contains any inherited entries, if not then
489  		 * returns NULL.
490  		 * */
491  		if (type == ACL_TYPE_DEFAULT) {
492  			for (f_ace = p_fsalacl->aces;
493  				f_ace < p_fsalacl->aces + p_fsalacl->naces; f_ace++) {
494  				if (is_ace_valid_for_inherited_acl_entry(f_ace))
495  					ret++;
496  			}
497  			if (ret == 0)
498  				return NULL;
499  		}
500  	
501  		/*
502  		 * FIXME: Always allocating with maximum possible value of acl entries,
503  		 * there is a possibility of memory leak
504  		 */
505  		allow_acl = acl_init(p_fsalacl->naces + 1);
506  		deny_acl = acl_init(p_fsalacl->naces + 1);
507  	
508  		/* first convert ACE EVERYONE@ to ACL_OTHER */
509  		ret = acl_create_entry(&allow_acl, &a_entry);
510  		if (ret) {
511  			LogMajor(COMPONENT_FSAL, "Cannot create entry for other");
512  			return NULL;
513  		}
514  		ret = acl_set_tag_type(a_entry, ACL_OTHER);
515  		if (ret)
516  			LogWarn(COMPONENT_FSAL, "Cannot set tag for ACL Entry");
517  	
518  		ret = acl_get_permset(a_entry, &e_a_permset);
519  	
520  		/*
521  		 * Deny entry for @EVERYONE created only because it will ease the
522  		 * manipulation of other acl entries. It will be updated only when deny
523  		 * entry for @EVERYONE is encountered
524  		 */
525  		ret = acl_create_entry(&deny_acl, &d_entry);
526  		if (ret)
527  			LogMajor(COMPONENT_FSAL, "Cannot create entry for other");
528  	
529  		ret = acl_set_tag_type(d_entry, ACL_OTHER);
530  		if (ret)
531  			LogWarn(COMPONENT_FSAL, "Cannot set tag for ACL Entry");
532  	
533  		ret = acl_get_permset(d_entry, &e_d_permset);
534  	
535  		for (f_ace = p_fsalacl->aces;
536  			f_ace < p_fsalacl->aces + p_fsalacl->naces; f_ace++) {
537  			if (IS_FSAL_ACE_SPECIAL_EVERYONE(*f_ace)) {
538  				if ((type == ACL_TYPE_ACCESS &&
539  				!is_ace_valid_for_effective_acl_entry(f_ace))
540  				|| (type == ACL_TYPE_DEFAULT &&
541  				!is_ace_valid_for_inherited_acl_entry(f_ace)))
542  					continue;
543  	
544  				if (IS_FSAL_ACE_DENY(*f_ace)) {
545  					if (IS_FSAL_ACE_READ_DATA(*f_ace))
546  						deny_e_r = true;
547  					if (IS_FSAL_ACE_WRITE_DATA(*f_ace))
548  						deny_e_w = true;
549  					if (IS_FSAL_ACE_EXECUTE(*f_ace))
550  						deny_e_x = true;
551  				} else if (IS_FSAL_ACE_ALLOW(*f_ace)) {
552  					if (IS_FSAL_ACE_READ_DATA(*f_ace) && !deny_e_r)
553  						acl_add_perm(e_a_permset, ACL_READ);
554  					if (IS_FSAL_ACE_WRITE_DATA(*f_ace) && !deny_e_w)
555  						acl_add_perm(e_a_permset, ACL_WRITE);
556  					if (IS_FSAL_ACE_EXECUTE(*f_ace) && !deny_e_x)
557  						acl_add_perm(e_a_permset, ACL_EXECUTE);
558  				}
559  			}
560  		}
561  	
562  		/*
563  		 * It is mandatory to have acl entries for ACL_USER_OBJ and
564  		 * ACL_GROUP_OBJ
565  		 */
566  		ret = acl_create_entry(&allow_acl, &a_entry);
567  		if (ret) {
568  			LogMajor(COMPONENT_FSAL, "Cannot create entry for other");
569  			return NULL;
570  		}
571  		ret = acl_set_tag_type(a_entry, ACL_USER_OBJ);
572  		if (ret)
573  			LogWarn(COMPONENT_FSAL, "Cannot set tag for ACL Entry");
574  	
575  		ret = acl_create_entry(&allow_acl, &a_entry);
576  		if (ret) {
577  			LogMajor(COMPONENT_FSAL, "Cannot create entry for other");
578  			return NULL;
579  		}
580  	
581  		ret = acl_set_tag_type(a_entry, ACL_GROUP_OBJ);
582  		if (ret)
583  			LogWarn(COMPONENT_FSAL, "Cannot set tag for ACL Entry");
584  	
585  		/** @todo: Annoymous users/groups (id = -1) should handle properly
586  		 */
587  	
588  		/*
589  		 * It uses two posix acl - allow_acl and deny_acl which represents ALLOW
590  		 * and DENY aces respectively. They are filled according to the order in
591  		 * fsal_acl list. The allow acl is build based on ALLOW ace, @EVERYONE
592  		 * ace and deny acl. The permset for allow acl entry is constructed in
593  		 * such a way that it will contain all permissions(READ,WRITE,EXECUTE)
594  		 * of ALLOW aces plus EVERYONE which is not denied by the corresponding
595  		 * deny acl entry
596  		 *
597  		 * At last allow_acl is returned and deny_acl is ignored.
598  		 */
599  		for (f_ace = p_fsalacl->aces;
600  		     f_ace < p_fsalacl->aces + p_fsalacl->naces;
601  		     f_ace++) {
602  			if ((type == ACL_TYPE_ACCESS &&
603  			    !is_ace_valid_for_effective_acl_entry(f_ace))
604  			    || (type == ACL_TYPE_DEFAULT &&
605  			    !is_ace_valid_for_inherited_acl_entry(f_ace)))
606  				continue;
607  			if (IS_FSAL_ACE_SPECIAL_ID(*f_ace)) {
608  				id = 0;
609  				if (IS_FSAL_ACE_SPECIAL_OWNER(*f_ace))
610  					tag = ACL_USER_OBJ;
611  				if (IS_FSAL_ACE_SPECIAL_GROUP(*f_ace))
612  					tag = ACL_GROUP_OBJ;
613  			} else {
614  				id = GET_FSAL_ACE_WHO(*f_ace);
615  				if (IS_FSAL_ACE_GROUP_ID(*f_ace))
616  					tag = ACL_GROUP;
617  				else
618  					tag = ACL_USER;
619  				/*
620  				 * Mask entry will be created only if it
621  				 * contains user or group entry
622  				 */
623  				mask = true;
624  			}
625  	
626  			if (IS_FSAL_ACE_SPECIAL_EVERYONE(*f_ace)) {
627  				if (IS_FSAL_ACE_DENY(*f_ace)) {
628  					if (deny_e_r)
629  						acl_add_perm(e_d_permset, ACL_READ);
630  					if (deny_e_w)
631  						acl_add_perm(e_d_permset, ACL_WRITE);
632  					if (deny_e_x)
633  						acl_add_perm(e_d_permset, ACL_EXECUTE);
634  				}
635  				continue;
636  			}
637  	
638  			a_entry = get_entry(allow_acl, tag, id);
639  			d_entry = get_entry(deny_acl, tag, id);
640  			ret = acl_get_permset(d_entry, &d_permset);
641  	
642  			if (IS_FSAL_ACE_DENY(*f_ace)) {
643  				if (IS_FSAL_ACE_READ_DATA(*f_ace))
644  					acl_add_perm(d_permset, ACL_READ);
645  				if (IS_FSAL_ACE_WRITE_DATA(*f_ace))
646  					acl_add_perm(d_permset, ACL_WRITE);
647  				if (IS_FSAL_ACE_EXECUTE(*f_ace))
648  					acl_add_perm(d_permset, ACL_EXECUTE);
649  			}
650  			ret = acl_get_permset(a_entry, &a_permset);
651  	
652  			if (isallow(f_ace, e_a_permset, ACL_READ)
653  			    && !isdeny(d_permset, e_d_permset, ACL_READ))
654  				acl_add_perm(a_permset, ACL_READ);
655  	
656  			if (isallow(f_ace, e_a_permset, ACL_WRITE)
657  			    && !isdeny(d_permset, e_d_permset, ACL_WRITE))
658  				acl_add_perm(a_permset, ACL_WRITE);
659  	
660  			if (isallow(f_ace, e_a_permset, ACL_EXECUTE)
661  			    && !isdeny(d_permset, e_d_permset, ACL_EXECUTE))
662  				acl_add_perm(a_permset, ACL_EXECUTE);
663  		}
664  		if (mask) {
665  			ret = acl_calc_mask(&allow_acl);
666  			if (ret)
667  				LogWarn(COMPONENT_FSAL,
668  				"Cannot calculate mask for posix");
669  		}
670  	
671  		/* A valid acl_t should have only one entry for ACL_USER_OBJ,
672  		 * ACL_GROUP_OBJ, ACL_OTHER and ACL_MASK is required only if
673  		 * ACL_USER or ACL_GROUP exists
674  		 */
675  		ret = acl_check(allow_acl, &i);
676  		if (ret) {
677  			if (ret > 0) {
678  				LogWarn(COMPONENT_FSAL,
679  					"Error converting ACL: %s at entry no %d",
680  					acl_error(ret), i);
681  			}
682  	
683  		}
684  	
685  		acl_str = acl_to_any_text(allow_acl, NULL, ',',
686  					TEXT_ABBREVIATE | TEXT_NUMERIC_IDS);
687  		LogDebug(COMPONENT_FSAL, "posix acl = %s ", acl_str);
688  	
689  		acl_free(acl_str);
690  		if (deny_acl)
691  			acl_free(deny_acl);
692  	
693  		return allow_acl;
694  	}
695