]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/posix1e/acl_strip.c
Merge ACPICA 20190329.
[FreeBSD/FreeBSD.git] / lib / libc / posix1e / acl_strip.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2001 Chris D. Faulhaber
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <errno.h>
33 #include <stdio.h>
34 #include <assert.h>
35 #include <sys/acl.h>
36 #include <sys/stat.h>
37
38 #include "acl_support.h"
39
40 /*
41  * These routines from sys/kern/subr_acl_nfs4.c are used by both kernel
42  * and libc.
43  */
44 void    acl_nfs4_sync_mode_from_acl(mode_t *_mode, const struct acl *aclp);
45 void    acl_nfs4_trivial_from_mode_libc(struct acl *aclp, int file_owner_id,
46             int canonical_six);
47
48 static acl_t
49 _nfs4_acl_strip_np(const acl_t aclp, int canonical_six)
50 {
51         acl_t newacl;
52         mode_t mode = 0;
53
54         newacl = acl_init(ACL_MAX_ENTRIES);
55         if (newacl == NULL) {
56                 errno = ENOMEM;
57                 return (NULL);
58         }
59
60         _acl_brand_as(newacl, ACL_BRAND_NFS4);
61
62         acl_nfs4_sync_mode_from_acl(&mode, &(aclp->ats_acl));
63         acl_nfs4_trivial_from_mode_libc(&(newacl->ats_acl), mode, canonical_six);
64
65         return (newacl);
66 }
67
68 static acl_t
69 _posix1e_acl_strip_np(const acl_t aclp, int recalculate_mask)
70 {
71         acl_t acl_new, acl_old;
72         acl_entry_t entry, entry_new;
73         acl_tag_t tag;
74         int entry_id, have_mask_entry;
75
76         assert(_acl_brand(aclp) == ACL_BRAND_POSIX);
77
78         acl_old = acl_dup(aclp);
79         if (acl_old == NULL)
80                 return (NULL);
81
82         assert(_acl_brand(acl_old) == ACL_BRAND_POSIX);
83
84         have_mask_entry = 0;
85         acl_new = acl_init(ACL_MAX_ENTRIES);
86         if (acl_new == NULL) {
87                 acl_free(acl_old);
88                 return (NULL);
89         }
90         tag = ACL_UNDEFINED_TAG;
91
92         /* only save the default user/group/other entries */
93         entry_id = ACL_FIRST_ENTRY;
94         while (acl_get_entry(acl_old, entry_id, &entry) == 1) {
95                 entry_id = ACL_NEXT_ENTRY;
96
97                 assert(_entry_brand(entry) == ACL_BRAND_POSIX);
98
99                 if (acl_get_tag_type(entry, &tag) == -1)
100                         goto fail;
101
102                 switch(tag) {
103                 case ACL_USER_OBJ:
104                 case ACL_GROUP_OBJ:
105                 case ACL_OTHER:
106                         if (acl_create_entry(&acl_new, &entry_new) == -1)
107                                 goto fail;
108                         if (acl_copy_entry(entry_new, entry) == -1)
109                                 goto fail;
110                         assert(_entry_brand(entry_new) == ACL_BRAND_POSIX);
111                         break;
112                 case ACL_MASK:
113                         have_mask_entry = 1;
114                         break;
115                 default:
116                         break;
117                 }
118         }
119
120         assert(_acl_brand(acl_new) == ACL_BRAND_POSIX);
121
122         if (have_mask_entry && recalculate_mask) {
123                 if (acl_calc_mask(&acl_new) == -1)
124                         goto fail;
125         }
126
127         return (acl_new);
128
129 fail:
130         acl_free(acl_new);
131         acl_free(acl_old);
132
133         return (NULL);
134 }
135
136 acl_t
137 acl_strip_np(const acl_t aclp, int recalculate_mask)
138 {
139         switch (_acl_brand(aclp)) {
140         case ACL_BRAND_NFS4:
141                 return (_nfs4_acl_strip_np(aclp, 0));
142
143         case ACL_BRAND_POSIX:
144                 return (_posix1e_acl_strip_np(aclp, recalculate_mask));
145
146         default:
147                 errno = EINVAL;
148                 return (NULL);
149         }
150 }
151
152 /*
153  * Return 1, if ACL is trivial, 0 otherwise.
154  *
155  * ACL is trivial, iff its meaning could be fully expressed using just file
156  * mode.  In other words, ACL is trivial iff it doesn't have "+" to the right
157  * of the mode bits in "ls -l" output ;-)
158  */
159 int
160 acl_is_trivial_np(const acl_t aclp, int *trivialp)
161 {
162         acl_t tmpacl;
163         int differs;
164
165         if (aclp == NULL || trivialp == NULL) {
166                 errno = EINVAL;
167                 return (-1);
168         }
169
170         switch (_acl_brand(aclp)) {
171         case ACL_BRAND_POSIX:
172                 if (aclp->ats_acl.acl_cnt == 3)
173                         *trivialp = 1;
174                 else
175                         *trivialp = 0;
176
177                 return (0);
178
179         case ACL_BRAND_NFS4:
180                 /*
181                  * If the ACL has more than canonical six entries,
182                  * it's non trivial by definition.
183                  */
184                 if (aclp->ats_acl.acl_cnt > 6) {
185                         *trivialp = 0;
186                         return (0);
187                 }
188                         
189                 /*
190                  * Calculate trivial ACL - using acl_strip_np(3) - and compare
191                  * with the original.
192                  */
193                 tmpacl = _nfs4_acl_strip_np(aclp, 0);
194                 if (tmpacl == NULL)
195                         return (-1);
196
197                 differs = _acl_differs(aclp, tmpacl);
198                 acl_free(tmpacl);
199
200                 if (differs == 0) {
201                         *trivialp = 1;
202                         return (0);
203                 }
204
205                 /*
206                  * Try again with an old-style, "canonical six" trivial ACL.
207                  */
208                 tmpacl = _nfs4_acl_strip_np(aclp, 1);
209                 if (tmpacl == NULL)
210                         return (-1);
211
212                 differs = _acl_differs(aclp, tmpacl);
213                 acl_free(tmpacl);
214
215                 if (differs)
216                         *trivialp = 0;
217                 else
218                         *trivialp = 1;
219
220                 return (0);
221
222         default:
223                 errno = EINVAL;
224                 return (-1);
225         }
226 }