]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/posix1e/acl_to_text_nfs4.c
Import CK as of commit 0f017230ccc86929f56bf44ef2dca93d7df8076b.
[FreeBSD/FreeBSD.git] / lib / libc / posix1e / acl_to_text_nfs4.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2008, 2009 Edward Tomasz NapieraƂa <trasz@FreeBSD.org>
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 <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <assert.h>
37 #include <string.h>
38 #include <pwd.h>
39 #include <grp.h>
40 #include <sys/syscall.h>
41 #include <sys/types.h>
42 #include <sys/acl.h>
43
44 #include "acl_support.h"
45
46 #define MAX_ENTRY_LENGTH 512
47
48 static int
49 format_who(char *str, size_t size, const acl_entry_t entry, int numeric)
50 {
51         int error;
52         acl_tag_t tag;
53         struct passwd *pwd;
54         struct group *grp;
55         uid_t *id;
56
57         error = acl_get_tag_type(entry, &tag);
58         if (error)
59                 return (error);
60
61         switch (tag) {
62         case ACL_USER_OBJ:
63                 snprintf(str, size, "owner@");
64                 break;
65
66         case ACL_USER:
67                 id = (uid_t *)acl_get_qualifier(entry);
68                 if (id == NULL)
69                         return (-1);
70                 /* XXX: Thread-unsafe. */
71                 if (!numeric)
72                         pwd = getpwuid(*id);
73                 else
74                         pwd = NULL;
75                 if (pwd == NULL)
76                         snprintf(str, size, "user:%d", (unsigned int)*id);
77                 else
78                         snprintf(str, size, "user:%s", pwd->pw_name);
79                 break;
80
81         case ACL_GROUP_OBJ:
82                 snprintf(str, size, "group@");
83                 break;
84
85         case ACL_GROUP:
86                 id = (uid_t *)acl_get_qualifier(entry);
87                 if (id == NULL)
88                         return (-1);
89                 /* XXX: Thread-unsafe. */
90                 if (!numeric)
91                         grp = getgrgid(*id);
92                 else
93                         grp = NULL;
94                 if (grp == NULL)
95                         snprintf(str, size, "group:%d", (unsigned int)*id);
96                 else
97                         snprintf(str, size, "group:%s", grp->gr_name);
98                 break;
99
100         case ACL_EVERYONE:
101                 snprintf(str, size, "everyone@");
102                 break;
103
104         default:
105                 return (-1);
106         }
107
108         return (0);
109 }
110
111 static int
112 format_entry_type(char *str, size_t size, const acl_entry_t entry)
113 {
114         int error;
115         acl_entry_type_t entry_type;
116
117         error = acl_get_entry_type_np(entry, &entry_type);
118         if (error)
119                 return (error);
120
121         switch (entry_type) {
122         case ACL_ENTRY_TYPE_ALLOW:
123                 snprintf(str, size, "allow");
124                 break;
125         case ACL_ENTRY_TYPE_DENY:
126                 snprintf(str, size, "deny");
127                 break;
128         case ACL_ENTRY_TYPE_AUDIT:
129                 snprintf(str, size, "audit");
130                 break;
131         case ACL_ENTRY_TYPE_ALARM:
132                 snprintf(str, size, "alarm");
133                 break;
134         default:
135                 return (-1);
136         }
137
138         return (0);
139 }
140
141 static int
142 format_additional_id(char *str, size_t size, const acl_entry_t entry)
143 {
144         int error;
145         acl_tag_t tag;
146         uid_t *id;
147
148         error = acl_get_tag_type(entry, &tag);
149         if (error)
150                 return (error);
151
152         switch (tag) {
153         case ACL_USER_OBJ:
154         case ACL_GROUP_OBJ:
155         case ACL_EVERYONE:
156                 str[0] = '\0';
157                 break;
158
159         default:
160                 id = (uid_t *)acl_get_qualifier(entry);
161                 if (id == NULL)
162                         return (-1);
163                 snprintf(str, size, ":%d", (unsigned int)*id);
164         }
165
166         return (0);
167 }
168
169 static int
170 format_entry(char *str, size_t size, const acl_entry_t entry, int flags)
171 {
172         size_t off = 0, min_who_field_length = 18;
173         acl_permset_t permset;
174         acl_flagset_t flagset;
175         int error, len;
176         char buf[MAX_ENTRY_LENGTH + 1];
177
178         assert(_entry_brand(entry) == ACL_BRAND_NFS4);
179
180         error = acl_get_flagset_np(entry, &flagset);
181         if (error)
182                 return (error);
183
184         error = acl_get_permset(entry, &permset);
185         if (error)
186                 return (error);
187
188         error = format_who(buf, sizeof(buf), entry,
189             flags & ACL_TEXT_NUMERIC_IDS);
190         if (error)
191                 return (error);
192         len = strlen(buf);
193         if (len < min_who_field_length)
194                 len = min_who_field_length;
195         off += snprintf(str + off, size - off, "%*s:", len, buf);
196
197         error = _nfs4_format_access_mask(buf, sizeof(buf), *permset,
198             flags & ACL_TEXT_VERBOSE);
199         if (error)
200                 return (error);
201         off += snprintf(str + off, size - off, "%s:", buf);
202
203         error = _nfs4_format_flags(buf, sizeof(buf), *flagset,
204             flags & ACL_TEXT_VERBOSE);
205         if (error)
206                 return (error);
207         off += snprintf(str + off, size - off, "%s:", buf);
208
209         error = format_entry_type(buf, sizeof(buf), entry);
210         if (error)
211                 return (error);
212         off += snprintf(str + off, size - off, "%s", buf);
213
214         if (flags & ACL_TEXT_APPEND_ID) {
215                 error = format_additional_id(buf, sizeof(buf), entry);
216                 if (error)
217                         return (error);
218                 off += snprintf(str + off, size - off, "%s", buf);
219         }
220
221         off += snprintf(str + off, size - off, "\n");
222
223         /* Make sure we didn't truncate anything. */
224         assert (off < size);
225
226         return (0);
227 }
228
229 char *
230 _nfs4_acl_to_text_np(const acl_t aclp, ssize_t *len_p, int flags)
231 {
232         int error, off = 0, size, entry_id = ACL_FIRST_ENTRY;
233         char *str;
234         acl_entry_t entry;
235
236         if (aclp->ats_acl.acl_cnt == 0)
237                 return strdup("");
238
239         size = aclp->ats_acl.acl_cnt * MAX_ENTRY_LENGTH;
240         str = malloc(size);
241         if (str == NULL)
242                 return (NULL);
243
244         while (acl_get_entry(aclp, entry_id, &entry) == 1) {
245                 entry_id = ACL_NEXT_ENTRY;
246
247                 assert(off < size);
248
249                 error = format_entry(str + off, size - off, entry, flags);
250                 if (error) {
251                         free(str);
252                         errno = EINVAL;
253                         return (NULL);
254                 }
255
256                 off = strlen(str);
257         }
258
259         assert(off < size);
260         str[off] = '\0';
261
262         if (len_p != NULL)
263                 *len_p = off;
264
265         return (str);
266 }