acl_strip.c revision 212906
1266072Sdes/*-
2266072Sdes * Copyright (c) 2001 Chris D. Faulhaber
3285206Sdes * All rights reserved.
4266072Sdes *
5266072Sdes * Redistribution and use in source and binary forms, with or without
6266072Sdes * modification, are permitted provided that the following conditions
7266072Sdes * are met:
8266072Sdes * 1. Redistributions of source code must retain the above copyright
9266072Sdes *    notice, this list of conditions and the following disclaimer.
10266072Sdes * 2. Redistributions in binary form must reproduce the above copyright
11285206Sdes *    notice, this list of conditions and the following disclaimer in the
12285206Sdes *    documentation and/or other materials provided with the distribution.
13285206Sdes *
14285206Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15285206Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16285206Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17285206Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18285206Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19266072Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20285206Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21285206Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22285206Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23285206Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24266072Sdes * SUCH DAMAGE.
25285206Sdes */
26285206Sdes
27266072Sdes#include <sys/cdefs.h>
28266072Sdes__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_strip.c 212906 2010-09-20 17:10:06Z trasz $");
29266072Sdes
30266072Sdes#include <errno.h>
31285206Sdes#include <stdio.h>
32266072Sdes#include <assert.h>
33266072Sdes#include <sys/acl.h>
34285206Sdes#include <sys/stat.h>
35266072Sdes
36266072Sdes#include "acl_support.h"
37266072Sdes
38266072Sdes/*
39266072Sdes * These three routines from sys/kern/subr_acl_nfs4.c are used by both kernel
40266072Sdes * and libc.
41266072Sdes */
42266072Sdesvoid	acl_nfs4_trivial_from_mode(struct acl *aclp, mode_t mode);
43266072Sdesvoid	acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode,
44266072Sdes	    int file_owner_id);
45266072Sdesvoid	acl_nfs4_sync_mode_from_acl(mode_t *_mode, const struct acl *aclp);
46266072Sdes
47266072Sdesstatic acl_t
48266072Sdes_nfs4_acl_strip_np(const acl_t aclp, int canonical_six)
49266072Sdes{
50266072Sdes	acl_t newacl;
51266072Sdes	mode_t mode = 0;
52266072Sdes
53266072Sdes	newacl = acl_init(ACL_MAX_ENTRIES);
54266072Sdes	if (newacl == NULL) {
55266072Sdes		errno = ENOMEM;
56266072Sdes		return (NULL);
57266072Sdes	}
58266072Sdes
59266072Sdes	_acl_brand_as(newacl, ACL_BRAND_NFS4);
60266072Sdes
61266072Sdes	acl_nfs4_sync_mode_from_acl(&mode, &(aclp->ats_acl));
62285206Sdes	if (canonical_six)
63266072Sdes		acl_nfs4_sync_acl_from_mode(&(newacl->ats_acl), mode, -1);
64266072Sdes	else
65266072Sdes		acl_nfs4_trivial_from_mode(&(newacl->ats_acl), mode);
66266072Sdes
67266072Sdes	return (newacl);
68266072Sdes}
69266072Sdes
70266072Sdesstatic acl_t
71266072Sdes_posix1e_acl_strip_np(const acl_t aclp, int recalculate_mask)
72266072Sdes{
73266072Sdes	acl_t acl_new, acl_old;
74266072Sdes	acl_entry_t entry, entry_new;
75266072Sdes	acl_permset_t perm;
76266072Sdes	acl_tag_t tag;
77266072Sdes	int entry_id, have_mask_entry;
78266072Sdes
79266072Sdes	assert(_acl_brand(aclp) == ACL_BRAND_POSIX);
80266072Sdes
81266072Sdes	acl_old = acl_dup(aclp);
82266072Sdes	if (acl_old == NULL)
83266072Sdes		return (NULL);
84266072Sdes
85266072Sdes	assert(_acl_brand(acl_old) == ACL_BRAND_POSIX);
86285206Sdes
87266072Sdes	have_mask_entry = 0;
88266072Sdes	acl_new = acl_init(ACL_MAX_ENTRIES);
89266072Sdes	if (acl_new == NULL)
90266072Sdes		return (NULL);
91266072Sdes	tag = ACL_UNDEFINED_TAG;
92266072Sdes
93266072Sdes	/* only save the default user/group/other entries */
94266072Sdes	entry_id = ACL_FIRST_ENTRY;
95266072Sdes	while (acl_get_entry(acl_old, entry_id, &entry) == 1) {
96266072Sdes		entry_id = ACL_NEXT_ENTRY;
97266072Sdes
98266072Sdes		assert(_entry_brand(entry) == ACL_BRAND_POSIX);
99266072Sdes
100266072Sdes		if (acl_get_tag_type(entry, &tag) == -1)
101266072Sdes			return (NULL);
102266072Sdes
103266072Sdes		switch(tag) {
104266072Sdes		case ACL_USER_OBJ:
105266072Sdes		case ACL_GROUP_OBJ:
106285206Sdes		case ACL_OTHER:
107285206Sdes			if (acl_get_tag_type(entry, &tag) == -1)
108285206Sdes				return (NULL);
109285206Sdes			if (acl_get_permset(entry, &perm) == -1)
110285206Sdes				return (NULL);
111285206Sdes			if (acl_create_entry(&acl_new, &entry_new) == -1)
112285206Sdes				return (NULL);
113285206Sdes			if (acl_set_tag_type(entry_new, tag) == -1)
114285206Sdes				return (NULL);
115285206Sdes			if (acl_set_permset(entry_new, perm) == -1)
116285206Sdes				return (NULL);
117285206Sdes			if (acl_copy_entry(entry_new, entry) == -1)
118285206Sdes				return (NULL);
119285206Sdes			assert(_entry_brand(entry_new) == ACL_BRAND_POSIX);
120285206Sdes			break;
121285206Sdes		case ACL_MASK:
122285206Sdes			have_mask_entry = 1;
123285206Sdes			break;
124285206Sdes		default:
125266072Sdes			break;
126266072Sdes		}
127285206Sdes	}
128285206Sdes
129285206Sdes	assert(_acl_brand(acl_new) == ACL_BRAND_POSIX);
130266072Sdes
131285206Sdes	if (have_mask_entry && recalculate_mask) {
132285206Sdes		if (acl_calc_mask(&acl_new) == -1)
133285206Sdes			return (NULL);
134285206Sdes	}
135285206Sdes
136266072Sdes	return (acl_new);
137266072Sdes}
138266072Sdes
139266072Sdesacl_t
140266072Sdesacl_strip_np(const acl_t aclp, int recalculate_mask)
141266072Sdes{
142285206Sdes	switch (_acl_brand(aclp)) {
143266072Sdes	case ACL_BRAND_NFS4:
144266072Sdes		return (_nfs4_acl_strip_np(aclp, 1));
145266072Sdes
146266072Sdes	case ACL_BRAND_POSIX:
147266072Sdes		return (_posix1e_acl_strip_np(aclp, recalculate_mask));
148266072Sdes
149266072Sdes	default:
150266072Sdes		errno = EINVAL;
151266072Sdes		return (NULL);
152266072Sdes	}
153266072Sdes}
154266072Sdes
155266072Sdes/*
156266072Sdes * Return 1, if ACL is trivial, 0 otherwise.
157266072Sdes *
158266072Sdes * ACL is trivial, iff its meaning could be fully expressed using just file
159266072Sdes * mode.  In other words, ACL is trivial iff it doesn't have "+" to the right
160266072Sdes * of the mode bits in "ls -l" output ;-)
161266072Sdes */
162266072Sdesint
163266072Sdesacl_is_trivial_np(const acl_t aclp, int *trivialp)
164266072Sdes{
165266072Sdes	acl_t tmpacl;
166266072Sdes	int differs;
167266072Sdes
168266072Sdes	if (aclp == NULL || trivialp == NULL) {
169266072Sdes		errno = EINVAL;
170266072Sdes		return (-1);
171266072Sdes	}
172266072Sdes
173266072Sdes	switch (_acl_brand(aclp)) {
174266072Sdes	case ACL_BRAND_POSIX:
175266072Sdes		if (aclp->ats_acl.acl_cnt == 3)
176266072Sdes			*trivialp = 1;
177266072Sdes		else
178266072Sdes			*trivialp = 0;
179266072Sdes
180266072Sdes		return (0);
181266072Sdes
182266072Sdes	case ACL_BRAND_NFS4:
183266072Sdes		/*
184266072Sdes		 * If the ACL has more than canonical six entries,
185266072Sdes		 * it's non trivial by definition.
186266072Sdes		 */
187266072Sdes		if (aclp->ats_acl.acl_cnt > 6) {
188266072Sdes			*trivialp = 0;
189285206Sdes			return (0);
190266072Sdes		}
191266072Sdes
192285206Sdes		/*
193266072Sdes		 * Calculate trivial ACL - using acl_strip_np(3) - and compare
194285206Sdes		 * with the original.
195266072Sdes		 */
196266072Sdes		tmpacl = _nfs4_acl_strip_np(aclp, 0);
197266072Sdes		if (tmpacl == NULL)
198285206Sdes			return (-1);
199266072Sdes
200266072Sdes		differs = _acl_differs(aclp, tmpacl);
201266072Sdes		acl_free(tmpacl);
202266072Sdes
203266072Sdes		if (differs == 0) {
204266072Sdes			*trivialp = 1;
205266072Sdes			return (0);
206266072Sdes		}
207266072Sdes
208266072Sdes		/*
209266072Sdes		 * Try again with an old-style, "canonical six" trivial ACL.
210266072Sdes		 */
211285206Sdes		tmpacl = _nfs4_acl_strip_np(aclp, 1);
212266072Sdes		if (tmpacl == NULL)
213266072Sdes			return (-1);
214266072Sdes
215266072Sdes		differs = _acl_differs(aclp, tmpacl);
216266072Sdes		acl_free(tmpacl);
217266072Sdes
218266072Sdes		if (differs)
219266072Sdes			*trivialp = 0;
220266072Sdes		else
221266072Sdes			*trivialp = 1;
222285206Sdes
223266072Sdes		return (0);
224266072Sdes
225266072Sdes	default:
226285206Sdes		errno = EINVAL;
227266072Sdes		return (-1);
228285206Sdes	}
229285206Sdes}
230266072Sdes