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