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