xref: /netbsd-src/lib/libc/posix1e/acl_to_text_nfs4.c (revision 53b02e147d4ed531c0d2a5ca9b3e8026ba3e99b5)
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.1 2020/05/16 18:31:47 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
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
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
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
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 	unsigned int 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:", 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 *
235 _nfs4_acl_to_text_np(const acl_t aclp, ssize_t *len_p, int flags)
236 {
237 	int error, off = 0, size, entry_id = ACL_FIRST_ENTRY;
238 	char *str;
239 	acl_entry_t entry;
240 
241 	if (aclp->ats_acl.acl_cnt == 0)
242 		return strdup("");
243 
244 	size = aclp->ats_acl.acl_cnt * MAX_ENTRY_LENGTH;
245 	str = malloc(size);
246 	if (str == NULL)
247 		return (NULL);
248 
249 	while (acl_get_entry(aclp, entry_id, &entry) == 1) {
250 		entry_id = ACL_NEXT_ENTRY;
251 
252 		assert(off < size);
253 
254 		error = format_entry(str + off, size - off, entry, flags);
255 		if (error) {
256 			free(str);
257 			errno = EINVAL;
258 			return (NULL);
259 		}
260 
261 		off = strlen(str);
262 	}
263 
264 	assert(off < size);
265 	str[off] = '\0';
266 
267 	if (len_p != NULL)
268 		*len_p = off;
269 
270 	return (str);
271 }
272