1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 1999-2002 Robert N. M. Watson
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 * acl_to_text - return a text string with a text representation of the acl
30 * in it.
31 */
32
33#include "namespace.h"
34#include <sys/param.h>
35#include <sys/acl.h>
36#include "un-namespace.h"
37#include <sys/errno.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41
42#include "acl_support.h"
43
44/*
45 * acl_to_text - generate a text form of an acl
46 * spec says nothing about output ordering, so leave in acl order
47 *
48 * This function will not produce nice results if it is called with
49 * a non-POSIX.1e semantics ACL.
50 */
51
52char *_nfs4_acl_to_text_np(const acl_t acl, ssize_t *len_p, int flags);
53
54static char *
55_posix1e_acl_to_text(acl_t acl, ssize_t *len_p, int flags)
56{
57	struct acl	*acl_int;
58	char		*buf, *tmpbuf;
59	char		 name_buf[MAXLOGNAME];
60	char		 perm_buf[_POSIX1E_ACL_STRING_PERM_MAXSIZE+1],
61			 effective_perm_buf[_POSIX1E_ACL_STRING_PERM_MAXSIZE+1];
62	int		 i, error, len;
63	uid_t		 ae_id;
64	acl_tag_t	 ae_tag;
65	acl_perm_t	 ae_perm, effective_perm, mask_perm;
66
67	buf = strdup("");
68	if (buf == NULL)
69		return(NULL);
70
71	acl_int = &acl->ats_acl;
72
73	mask_perm = ACL_PERM_BITS;	/* effective is regular if no mask */
74	for (i = 0; i < acl_int->acl_cnt; i++)
75		if (acl_int->acl_entry[i].ae_tag == ACL_MASK)
76			mask_perm = acl_int->acl_entry[i].ae_perm;
77
78	for (i = 0; i < acl_int->acl_cnt; i++) {
79		ae_tag = acl_int->acl_entry[i].ae_tag;
80		ae_id = acl_int->acl_entry[i].ae_id;
81		ae_perm = acl_int->acl_entry[i].ae_perm;
82
83		switch(ae_tag) {
84		case ACL_USER_OBJ:
85			error = _posix1e_acl_perm_to_string(ae_perm,
86			    _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
87			if (error)
88				goto error_label;
89			len = asprintf(&tmpbuf, "%suser::%s\n", buf,
90			    perm_buf);
91			if (len == -1)
92				goto error_label;
93			free(buf);
94			buf = tmpbuf;
95			break;
96
97		case ACL_USER:
98			error = _posix1e_acl_perm_to_string(ae_perm,
99			    _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
100			if (error)
101				goto error_label;
102
103			error = _posix1e_acl_id_to_name(ae_tag, ae_id,
104			    MAXLOGNAME, name_buf, flags);
105			if (error)
106				goto error_label;
107
108			effective_perm = ae_perm & mask_perm;
109			if (effective_perm != ae_perm) {
110				error = _posix1e_acl_perm_to_string(
111				    effective_perm,
112				    _POSIX1E_ACL_STRING_PERM_MAXSIZE+1,
113				    effective_perm_buf);
114				if (error)
115					goto error_label;
116				len = asprintf(&tmpbuf, "%suser:%s:%s\t\t# "
117				    "effective: %s\n",
118				    buf, name_buf, perm_buf,
119				    effective_perm_buf);
120			} else {
121				len = asprintf(&tmpbuf, "%suser:%s:%s\n", buf,
122				    name_buf, perm_buf);
123			}
124			if (len == -1)
125				goto error_label;
126			free(buf);
127			buf = tmpbuf;
128			break;
129
130		case ACL_GROUP_OBJ:
131			error = _posix1e_acl_perm_to_string(ae_perm,
132			    _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
133			if (error)
134				goto error_label;
135
136			effective_perm = ae_perm & mask_perm;
137			if (effective_perm != ae_perm) {
138				error = _posix1e_acl_perm_to_string(
139				    effective_perm,
140				    _POSIX1E_ACL_STRING_PERM_MAXSIZE+1,
141				    effective_perm_buf);
142				if (error)
143					goto error_label;
144				len = asprintf(&tmpbuf, "%sgroup::%s\t\t# "
145				    "effective: %s\n",
146				    buf, perm_buf, effective_perm_buf);
147			} else {
148				len = asprintf(&tmpbuf, "%sgroup::%s\n", buf,
149				    perm_buf);
150			}
151			if (len == -1)
152				goto error_label;
153			free(buf);
154			buf = tmpbuf;
155			break;
156
157		case ACL_GROUP:
158			error = _posix1e_acl_perm_to_string(ae_perm,
159			    _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
160			if (error)
161				goto error_label;
162
163			error = _posix1e_acl_id_to_name(ae_tag, ae_id,
164			    MAXLOGNAME, name_buf, flags);
165			if (error)
166				goto error_label;
167
168			effective_perm = ae_perm & mask_perm;
169			if (effective_perm != ae_perm) {
170				error = _posix1e_acl_perm_to_string(
171				    effective_perm,
172				    _POSIX1E_ACL_STRING_PERM_MAXSIZE+1,
173				    effective_perm_buf);
174				if (error)
175					goto error_label;
176				len = asprintf(&tmpbuf, "%sgroup:%s:%s\t\t# "
177				    "effective: %s\n",
178				    buf, name_buf, perm_buf,
179				    effective_perm_buf);
180			} else {
181				len = asprintf(&tmpbuf, "%sgroup:%s:%s\n", buf,
182				    name_buf, perm_buf);
183			}
184			if (len == -1)
185				goto error_label;
186			free(buf);
187			buf = tmpbuf;
188			break;
189
190		case ACL_MASK:
191			error = _posix1e_acl_perm_to_string(ae_perm,
192			    _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
193			if (error)
194				goto error_label;
195
196			len = asprintf(&tmpbuf, "%smask::%s\n", buf,
197			    perm_buf);
198			if (len == -1)
199				goto error_label;
200			free(buf);
201			buf = tmpbuf;
202			break;
203
204		case ACL_OTHER:
205			error = _posix1e_acl_perm_to_string(ae_perm,
206			    _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
207			if (error)
208				goto error_label;
209
210			len = asprintf(&tmpbuf, "%sother::%s\n", buf,
211			    perm_buf);
212			if (len == -1)
213				goto error_label;
214			free(buf);
215			buf = tmpbuf;
216			break;
217
218		default:
219			errno = EINVAL;
220			goto error_label;
221		}
222	}
223
224	if (len_p) {
225		*len_p = strlen(buf);
226	}
227	return (buf);
228
229error_label:
230	/* jump to here sets errno already, we just clean up */
231	if (buf) free(buf);
232	return (NULL);
233}
234
235char *
236acl_to_text_np(acl_t acl, ssize_t *len_p, int flags)
237{
238
239	if (acl == NULL) {
240		errno = EINVAL;
241		return(NULL);
242	}
243
244	switch (_acl_brand(acl)) {
245	case ACL_BRAND_POSIX:
246		return (_posix1e_acl_to_text(acl, len_p, flags));
247	case ACL_BRAND_NFS4:
248		return (_nfs4_acl_to_text_np(acl, len_p, flags));
249	default:
250		errno = EINVAL;
251		return (NULL);
252	}
253}
254
255char *
256acl_to_text(acl_t acl, ssize_t *len_p)
257{
258
259	return (acl_to_text_np(acl, len_p, 0));
260}
261