1*9aa2a9c3Schristos /*-
2*9aa2a9c3Schristos * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*9aa2a9c3Schristos *
4*9aa2a9c3Schristos * Copyright (c) 1999-2002 Robert N. M. Watson
5*9aa2a9c3Schristos * All rights reserved.
6*9aa2a9c3Schristos *
7*9aa2a9c3Schristos * Redistribution and use in source and binary forms, with or without
8*9aa2a9c3Schristos * modification, are permitted provided that the following conditions
9*9aa2a9c3Schristos * are met:
10*9aa2a9c3Schristos * 1. Redistributions of source code must retain the above copyright
11*9aa2a9c3Schristos * notice, this list of conditions and the following disclaimer.
12*9aa2a9c3Schristos * 2. Redistributions in binary form must reproduce the above copyright
13*9aa2a9c3Schristos * notice, this list of conditions and the following disclaimer in the
14*9aa2a9c3Schristos * documentation and/or other materials provided with the distribution.
15*9aa2a9c3Schristos *
16*9aa2a9c3Schristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*9aa2a9c3Schristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*9aa2a9c3Schristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*9aa2a9c3Schristos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*9aa2a9c3Schristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*9aa2a9c3Schristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*9aa2a9c3Schristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*9aa2a9c3Schristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*9aa2a9c3Schristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*9aa2a9c3Schristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*9aa2a9c3Schristos * SUCH DAMAGE.
27*9aa2a9c3Schristos */
28*9aa2a9c3Schristos /*
29*9aa2a9c3Schristos * acl_to_text - return a text string with a text representation of the acl
30*9aa2a9c3Schristos * in it.
31*9aa2a9c3Schristos */
32*9aa2a9c3Schristos
33*9aa2a9c3Schristos #include <sys/cdefs.h>
34*9aa2a9c3Schristos #if 0
35*9aa2a9c3Schristos __FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_to_text.c 326193 2017-11-25 17:12:48Z pfg $");
36*9aa2a9c3Schristos #else
37*9aa2a9c3Schristos __RCSID("$NetBSD: acl_to_text.c,v 1.1 2020/05/16 18:31:47 christos Exp $");
38*9aa2a9c3Schristos #endif
39*9aa2a9c3Schristos
40*9aa2a9c3Schristos #include "namespace.h"
41*9aa2a9c3Schristos #include <sys/types.h>
42*9aa2a9c3Schristos #include <sys/acl.h>
43*9aa2a9c3Schristos #include <errno.h>
44*9aa2a9c3Schristos #include <stdio.h>
45*9aa2a9c3Schristos #include <stdlib.h>
46*9aa2a9c3Schristos #include <string.h>
47*9aa2a9c3Schristos
48*9aa2a9c3Schristos #include "acl_support.h"
49*9aa2a9c3Schristos
50*9aa2a9c3Schristos /*
51*9aa2a9c3Schristos * acl_to_text - generate a text form of an acl
52*9aa2a9c3Schristos * spec says nothing about output ordering, so leave in acl order
53*9aa2a9c3Schristos *
54*9aa2a9c3Schristos * This function will not produce nice results if it is called with
55*9aa2a9c3Schristos * a non-POSIX.1e semantics ACL.
56*9aa2a9c3Schristos */
57*9aa2a9c3Schristos
58*9aa2a9c3Schristos char *_nfs4_acl_to_text_np(const acl_t acl, ssize_t *len_p, int flags);
59*9aa2a9c3Schristos
60*9aa2a9c3Schristos static char *
_posix1e_acl_to_text(acl_t acl,ssize_t * len_p,int flags)61*9aa2a9c3Schristos _posix1e_acl_to_text(acl_t acl, ssize_t *len_p, int flags)
62*9aa2a9c3Schristos {
63*9aa2a9c3Schristos struct acl *acl_int;
64*9aa2a9c3Schristos char *buf, *tmpbuf;
65*9aa2a9c3Schristos char name_buf[MAXLOGNAME];
66*9aa2a9c3Schristos char perm_buf[_POSIX1E_ACL_STRING_PERM_MAXSIZE+1],
67*9aa2a9c3Schristos effective_perm_buf[_POSIX1E_ACL_STRING_PERM_MAXSIZE+1];
68*9aa2a9c3Schristos size_t i;
69*9aa2a9c3Schristos int error, len;
70*9aa2a9c3Schristos uid_t ae_id;
71*9aa2a9c3Schristos acl_tag_t ae_tag;
72*9aa2a9c3Schristos acl_perm_t ae_perm, effective_perm, mask_perm;
73*9aa2a9c3Schristos
74*9aa2a9c3Schristos buf = strdup("");
75*9aa2a9c3Schristos if (buf == NULL)
76*9aa2a9c3Schristos return(NULL);
77*9aa2a9c3Schristos
78*9aa2a9c3Schristos acl_int = &acl->ats_acl;
79*9aa2a9c3Schristos
80*9aa2a9c3Schristos mask_perm = ACL_PERM_BITS; /* effective is regular if no mask */
81*9aa2a9c3Schristos for (i = 0; i < acl_int->acl_cnt; i++)
82*9aa2a9c3Schristos if (acl_int->acl_entry[i].ae_tag == ACL_MASK)
83*9aa2a9c3Schristos mask_perm = acl_int->acl_entry[i].ae_perm;
84*9aa2a9c3Schristos
85*9aa2a9c3Schristos for (i = 0; i < acl_int->acl_cnt; i++) {
86*9aa2a9c3Schristos ae_tag = acl_int->acl_entry[i].ae_tag;
87*9aa2a9c3Schristos ae_id = acl_int->acl_entry[i].ae_id;
88*9aa2a9c3Schristos ae_perm = acl_int->acl_entry[i].ae_perm;
89*9aa2a9c3Schristos
90*9aa2a9c3Schristos switch(ae_tag) {
91*9aa2a9c3Schristos case ACL_USER_OBJ:
92*9aa2a9c3Schristos error = _posix1e_acl_perm_to_string(ae_perm,
93*9aa2a9c3Schristos _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
94*9aa2a9c3Schristos if (error)
95*9aa2a9c3Schristos goto error_label;
96*9aa2a9c3Schristos len = asprintf(&tmpbuf, "%suser::%s\n", buf,
97*9aa2a9c3Schristos perm_buf);
98*9aa2a9c3Schristos if (len == -1)
99*9aa2a9c3Schristos goto error_label;
100*9aa2a9c3Schristos free(buf);
101*9aa2a9c3Schristos buf = tmpbuf;
102*9aa2a9c3Schristos break;
103*9aa2a9c3Schristos
104*9aa2a9c3Schristos case ACL_USER:
105*9aa2a9c3Schristos error = _posix1e_acl_perm_to_string(ae_perm,
106*9aa2a9c3Schristos _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
107*9aa2a9c3Schristos if (error)
108*9aa2a9c3Schristos goto error_label;
109*9aa2a9c3Schristos
110*9aa2a9c3Schristos error = _posix1e_acl_id_to_name(ae_tag, ae_id,
111*9aa2a9c3Schristos MAXLOGNAME, name_buf, flags);
112*9aa2a9c3Schristos if (error)
113*9aa2a9c3Schristos goto error_label;
114*9aa2a9c3Schristos
115*9aa2a9c3Schristos effective_perm = ae_perm & mask_perm;
116*9aa2a9c3Schristos if (effective_perm != ae_perm) {
117*9aa2a9c3Schristos error = _posix1e_acl_perm_to_string(
118*9aa2a9c3Schristos effective_perm,
119*9aa2a9c3Schristos _POSIX1E_ACL_STRING_PERM_MAXSIZE+1,
120*9aa2a9c3Schristos effective_perm_buf);
121*9aa2a9c3Schristos if (error)
122*9aa2a9c3Schristos goto error_label;
123*9aa2a9c3Schristos len = asprintf(&tmpbuf, "%suser:%s:%s\t\t# "
124*9aa2a9c3Schristos "effective: %s\n",
125*9aa2a9c3Schristos buf, name_buf, perm_buf,
126*9aa2a9c3Schristos effective_perm_buf);
127*9aa2a9c3Schristos } else {
128*9aa2a9c3Schristos len = asprintf(&tmpbuf, "%suser:%s:%s\n", buf,
129*9aa2a9c3Schristos name_buf, perm_buf);
130*9aa2a9c3Schristos }
131*9aa2a9c3Schristos if (len == -1)
132*9aa2a9c3Schristos goto error_label;
133*9aa2a9c3Schristos free(buf);
134*9aa2a9c3Schristos buf = tmpbuf;
135*9aa2a9c3Schristos break;
136*9aa2a9c3Schristos
137*9aa2a9c3Schristos case ACL_GROUP_OBJ:
138*9aa2a9c3Schristos error = _posix1e_acl_perm_to_string(ae_perm,
139*9aa2a9c3Schristos _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
140*9aa2a9c3Schristos if (error)
141*9aa2a9c3Schristos goto error_label;
142*9aa2a9c3Schristos
143*9aa2a9c3Schristos effective_perm = ae_perm & mask_perm;
144*9aa2a9c3Schristos if (effective_perm != ae_perm) {
145*9aa2a9c3Schristos error = _posix1e_acl_perm_to_string(
146*9aa2a9c3Schristos effective_perm,
147*9aa2a9c3Schristos _POSIX1E_ACL_STRING_PERM_MAXSIZE+1,
148*9aa2a9c3Schristos effective_perm_buf);
149*9aa2a9c3Schristos if (error)
150*9aa2a9c3Schristos goto error_label;
151*9aa2a9c3Schristos len = asprintf(&tmpbuf, "%sgroup::%s\t\t# "
152*9aa2a9c3Schristos "effective: %s\n",
153*9aa2a9c3Schristos buf, perm_buf, effective_perm_buf);
154*9aa2a9c3Schristos } else {
155*9aa2a9c3Schristos len = asprintf(&tmpbuf, "%sgroup::%s\n", buf,
156*9aa2a9c3Schristos perm_buf);
157*9aa2a9c3Schristos }
158*9aa2a9c3Schristos if (len == -1)
159*9aa2a9c3Schristos goto error_label;
160*9aa2a9c3Schristos free(buf);
161*9aa2a9c3Schristos buf = tmpbuf;
162*9aa2a9c3Schristos break;
163*9aa2a9c3Schristos
164*9aa2a9c3Schristos case ACL_GROUP:
165*9aa2a9c3Schristos error = _posix1e_acl_perm_to_string(ae_perm,
166*9aa2a9c3Schristos _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
167*9aa2a9c3Schristos if (error)
168*9aa2a9c3Schristos goto error_label;
169*9aa2a9c3Schristos
170*9aa2a9c3Schristos error = _posix1e_acl_id_to_name(ae_tag, ae_id,
171*9aa2a9c3Schristos MAXLOGNAME, name_buf, flags);
172*9aa2a9c3Schristos if (error)
173*9aa2a9c3Schristos goto error_label;
174*9aa2a9c3Schristos
175*9aa2a9c3Schristos effective_perm = ae_perm & mask_perm;
176*9aa2a9c3Schristos if (effective_perm != ae_perm) {
177*9aa2a9c3Schristos error = _posix1e_acl_perm_to_string(
178*9aa2a9c3Schristos effective_perm,
179*9aa2a9c3Schristos _POSIX1E_ACL_STRING_PERM_MAXSIZE+1,
180*9aa2a9c3Schristos effective_perm_buf);
181*9aa2a9c3Schristos if (error)
182*9aa2a9c3Schristos goto error_label;
183*9aa2a9c3Schristos len = asprintf(&tmpbuf, "%sgroup:%s:%s\t\t# "
184*9aa2a9c3Schristos "effective: %s\n",
185*9aa2a9c3Schristos buf, name_buf, perm_buf,
186*9aa2a9c3Schristos effective_perm_buf);
187*9aa2a9c3Schristos } else {
188*9aa2a9c3Schristos len = asprintf(&tmpbuf, "%sgroup:%s:%s\n", buf,
189*9aa2a9c3Schristos name_buf, perm_buf);
190*9aa2a9c3Schristos }
191*9aa2a9c3Schristos if (len == -1)
192*9aa2a9c3Schristos goto error_label;
193*9aa2a9c3Schristos free(buf);
194*9aa2a9c3Schristos buf = tmpbuf;
195*9aa2a9c3Schristos break;
196*9aa2a9c3Schristos
197*9aa2a9c3Schristos case ACL_MASK:
198*9aa2a9c3Schristos error = _posix1e_acl_perm_to_string(ae_perm,
199*9aa2a9c3Schristos _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
200*9aa2a9c3Schristos if (error)
201*9aa2a9c3Schristos goto error_label;
202*9aa2a9c3Schristos
203*9aa2a9c3Schristos len = asprintf(&tmpbuf, "%smask::%s\n", buf,
204*9aa2a9c3Schristos perm_buf);
205*9aa2a9c3Schristos if (len == -1)
206*9aa2a9c3Schristos goto error_label;
207*9aa2a9c3Schristos free(buf);
208*9aa2a9c3Schristos buf = tmpbuf;
209*9aa2a9c3Schristos break;
210*9aa2a9c3Schristos
211*9aa2a9c3Schristos case ACL_OTHER:
212*9aa2a9c3Schristos error = _posix1e_acl_perm_to_string(ae_perm,
213*9aa2a9c3Schristos _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
214*9aa2a9c3Schristos if (error)
215*9aa2a9c3Schristos goto error_label;
216*9aa2a9c3Schristos
217*9aa2a9c3Schristos len = asprintf(&tmpbuf, "%sother::%s\n", buf,
218*9aa2a9c3Schristos perm_buf);
219*9aa2a9c3Schristos if (len == -1)
220*9aa2a9c3Schristos goto error_label;
221*9aa2a9c3Schristos free(buf);
222*9aa2a9c3Schristos buf = tmpbuf;
223*9aa2a9c3Schristos break;
224*9aa2a9c3Schristos
225*9aa2a9c3Schristos default:
226*9aa2a9c3Schristos errno = EINVAL;
227*9aa2a9c3Schristos goto error_label;
228*9aa2a9c3Schristos }
229*9aa2a9c3Schristos }
230*9aa2a9c3Schristos
231*9aa2a9c3Schristos if (len_p) {
232*9aa2a9c3Schristos *len_p = strlen(buf);
233*9aa2a9c3Schristos }
234*9aa2a9c3Schristos return (buf);
235*9aa2a9c3Schristos
236*9aa2a9c3Schristos error_label:
237*9aa2a9c3Schristos /* jump to here sets errno already, we just clean up */
238*9aa2a9c3Schristos if (buf) free(buf);
239*9aa2a9c3Schristos return (NULL);
240*9aa2a9c3Schristos }
241*9aa2a9c3Schristos
242*9aa2a9c3Schristos char *
acl_to_text_np(acl_t acl,ssize_t * len_p,int flags)243*9aa2a9c3Schristos acl_to_text_np(acl_t acl, ssize_t *len_p, int flags)
244*9aa2a9c3Schristos {
245*9aa2a9c3Schristos
246*9aa2a9c3Schristos if (acl == NULL) {
247*9aa2a9c3Schristos errno = EINVAL;
248*9aa2a9c3Schristos return(NULL);
249*9aa2a9c3Schristos }
250*9aa2a9c3Schristos
251*9aa2a9c3Schristos switch (_acl_brand(acl)) {
252*9aa2a9c3Schristos case ACL_BRAND_POSIX:
253*9aa2a9c3Schristos return (_posix1e_acl_to_text(acl, len_p, flags));
254*9aa2a9c3Schristos case ACL_BRAND_NFS4:
255*9aa2a9c3Schristos return (_nfs4_acl_to_text_np(acl, len_p, flags));
256*9aa2a9c3Schristos default:
257*9aa2a9c3Schristos errno = EINVAL;
258*9aa2a9c3Schristos return (NULL);
259*9aa2a9c3Schristos }
260*9aa2a9c3Schristos }
261*9aa2a9c3Schristos
262*9aa2a9c3Schristos char *
acl_to_text(acl_t acl,ssize_t * len_p)263*9aa2a9c3Schristos acl_to_text(acl_t acl, ssize_t *len_p)
264*9aa2a9c3Schristos {
265*9aa2a9c3Schristos
266*9aa2a9c3Schristos return (acl_to_text_np(acl, len_p, 0));
267*9aa2a9c3Schristos }
268