]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/posix1e/acl_strip.c
Document that `sendfile` will return an invalid value for `sbytes` if provided an...
[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_permset_t perm;
74         acl_tag_t tag;
75         int entry_id, have_mask_entry;
76
77         assert(_acl_brand(aclp) == ACL_BRAND_POSIX);
78
79         acl_old = acl_dup(aclp);
80         if (acl_old == NULL)
81                 return (NULL);
82
83         assert(_acl_brand(acl_old) == ACL_BRAND_POSIX);
84
85         have_mask_entry = 0;
86         acl_new = acl_init(ACL_MAX_ENTRIES);
87         if (acl_new == NULL) {
88                 acl_free(acl_old);
89                 return (NULL);
90         }
91         tag = ACL_UNDEFINED_TAG;
92
93         /* only save the default user/group/other entries */
94         entry_id = ACL_FIRST_ENTRY;
95         while (acl_get_entry(acl_old, entry_id, &entry) == 1) {
96                 entry_id = ACL_NEXT_ENTRY;
97
98                 assert(_entry_brand(entry) == ACL_BRAND_POSIX);
99
100                 if (acl_get_tag_type(entry, &tag) == -1)
101                         goto fail;
102
103                 switch(tag) {
104                 case ACL_USER_OBJ:
105                 case ACL_GROUP_OBJ:
106                 case ACL_OTHER:
107                         if (acl_get_tag_type(entry, &tag) == -1)
108                                 goto fail;
109                         if (acl_get_permset(entry, &perm) == -1)
110                                 goto fail;
111                         if (acl_create_entry(&acl_new, &entry_new) == -1)
112                                 goto fail;
113                         if (acl_set_tag_type(entry_new, tag) == -1)
114                                 goto fail;
115                         if (acl_set_permset(entry_new, perm) == -1)
116                                 goto fail;
117                         if (acl_copy_entry(entry_new, entry) == -1)
118                                 goto fail;
119                         assert(_entry_brand(entry_new) == ACL_BRAND_POSIX);
120                         break;
121                 case ACL_MASK:
122                         have_mask_entry = 1;
123                         break;
124                 default:
125                         break;
126                 }
127         }
128
129         assert(_acl_brand(acl_new) == ACL_BRAND_POSIX);
130
131         if (have_mask_entry && recalculate_mask) {
132                 if (acl_calc_mask(&acl_new) == -1)
133                         goto fail;
134         }
135
136         return (acl_new);
137
138 fail:
139         acl_free(acl_new);
140         acl_free(acl_old);
141
142         return (NULL);
143 }
144
145 acl_t
146 acl_strip_np(const acl_t aclp, int recalculate_mask)
147 {
148         switch (_acl_brand(aclp)) {
149         case ACL_BRAND_NFS4:
150                 return (_nfs4_acl_strip_np(aclp, 0));
151
152         case ACL_BRAND_POSIX:
153                 return (_posix1e_acl_strip_np(aclp, recalculate_mask));
154
155         default:
156                 errno = EINVAL;
157                 return (NULL);
158         }
159 }
160
161 /*
162  * Return 1, if ACL is trivial, 0 otherwise.
163  *
164  * ACL is trivial, iff its meaning could be fully expressed using just file
165  * mode.  In other words, ACL is trivial iff it doesn't have "+" to the right
166  * of the mode bits in "ls -l" output ;-)
167  */
168 int
169 acl_is_trivial_np(const acl_t aclp, int *trivialp)
170 {
171         acl_t tmpacl;
172         int differs;
173
174         if (aclp == NULL || trivialp == NULL) {
175                 errno = EINVAL;
176                 return (-1);
177         }
178
179         switch (_acl_brand(aclp)) {
180         case ACL_BRAND_POSIX:
181                 if (aclp->ats_acl.acl_cnt == 3)
182                         *trivialp = 1;
183                 else
184                         *trivialp = 0;
185
186                 return (0);
187
188         case ACL_BRAND_NFS4:
189                 /*
190                  * If the ACL has more than canonical six entries,
191                  * it's non trivial by definition.
192                  */
193                 if (aclp->ats_acl.acl_cnt > 6) {
194                         *trivialp = 0;
195                         return (0);
196                 }
197                         
198                 /*
199                  * Calculate trivial ACL - using acl_strip_np(3) - and compare
200                  * with the original.
201                  */
202                 tmpacl = _nfs4_acl_strip_np(aclp, 0);
203                 if (tmpacl == NULL)
204                         return (-1);
205
206                 differs = _acl_differs(aclp, tmpacl);
207                 acl_free(tmpacl);
208
209                 if (differs == 0) {
210                         *trivialp = 1;
211                         return (0);
212                 }
213
214                 /*
215                  * Try again with an old-style, "canonical six" trivial ACL.
216                  */
217                 tmpacl = _nfs4_acl_strip_np(aclp, 1);
218                 if (tmpacl == NULL)
219                         return (-1);
220
221                 differs = _acl_differs(aclp, tmpacl);
222                 acl_free(tmpacl);
223
224                 if (differs)
225                         *trivialp = 0;
226                 else
227                         *trivialp = 1;
228
229                 return (0);
230
231         default:
232                 errno = EINVAL;
233                 return (-1);
234         }
235 }