1194955Strasz/*-
2194955Strasz * Copyright (c) 2008, 2009 Edward Tomasz Napiera��a <trasz@FreeBSD.org>
3194955Strasz * All rights reserved.
4194955Strasz *
5194955Strasz * Redistribution and use in source and binary forms, with or without
6194955Strasz * modification, are permitted provided that the following conditions
7194955Strasz * are met:
8194955Strasz * 1. Redistributions of source code must retain the above copyright
9194955Strasz *    notice, this list of conditions and the following disclaimer.
10194955Strasz * 2. Redistributions in binary form must reproduce the above copyright
11194955Strasz *    notice, this list of conditions and the following disclaimer in the
12194955Strasz *    documentation and/or other materials provided with the distribution.
13194955Strasz *
14194955Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15194955Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16194955Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17194955Strasz * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18194955Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19194955Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20194955Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21194955Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22194955Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23194955Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24194955Strasz * SUCH DAMAGE.
25194955Strasz */
26194955Strasz
27194955Strasz#include <sys/cdefs.h>
28194955Strasz__FBSDID("$FreeBSD$");
29194955Strasz
30194955Strasz#include <stdio.h>
31194955Strasz#include <stdlib.h>
32194955Strasz#include <unistd.h>
33194955Strasz#include <errno.h>
34194955Strasz#include <assert.h>
35194955Strasz#include <string.h>
36194955Strasz#include <pwd.h>
37194955Strasz#include <grp.h>
38194955Strasz#include <sys/syscall.h>
39194955Strasz#include <sys/types.h>
40194955Strasz#include <sys/acl.h>
41194955Strasz
42194955Strasz#include "acl_support.h"
43194955Strasz
44194955Strasz#define MAX_ENTRY_LENGTH 512
45194955Strasz
46194955Straszstatic int
47194955Straszformat_who(char *str, size_t size, const acl_entry_t entry, int numeric)
48194955Strasz{
49194955Strasz	int error;
50194955Strasz	acl_tag_t tag;
51194955Strasz	struct passwd *pwd;
52194955Strasz	struct group *grp;
53208811Strasz	uid_t *id;
54194955Strasz
55194955Strasz	error = acl_get_tag_type(entry, &tag);
56194955Strasz	if (error)
57194955Strasz		return (error);
58194955Strasz
59194955Strasz	switch (tag) {
60194955Strasz	case ACL_USER_OBJ:
61194955Strasz		snprintf(str, size, "owner@");
62194955Strasz		break;
63194955Strasz
64194955Strasz	case ACL_USER:
65208811Strasz		id = (uid_t *)acl_get_qualifier(entry);
66194955Strasz		if (id == NULL)
67194955Strasz			return (-1);
68194955Strasz		/* XXX: Thread-unsafe. */
69194955Strasz		if (!numeric)
70194955Strasz			pwd = getpwuid(*id);
71194955Strasz		else
72194955Strasz			pwd = NULL;
73194955Strasz		if (pwd == NULL)
74194955Strasz			snprintf(str, size, "user:%d", (unsigned int)*id);
75194955Strasz		else
76194955Strasz			snprintf(str, size, "user:%s", pwd->pw_name);
77194955Strasz		break;
78194955Strasz
79194955Strasz	case ACL_GROUP_OBJ:
80194955Strasz		snprintf(str, size, "group@");
81194955Strasz		break;
82194955Strasz
83194955Strasz	case ACL_GROUP:
84208811Strasz		id = (uid_t *)acl_get_qualifier(entry);
85194955Strasz		if (id == NULL)
86194955Strasz			return (-1);
87194955Strasz		/* XXX: Thread-unsafe. */
88194955Strasz		if (!numeric)
89194955Strasz			grp = getgrgid(*id);
90194955Strasz		else
91194955Strasz			grp = NULL;
92194955Strasz		if (grp == NULL)
93194955Strasz			snprintf(str, size, "group:%d", (unsigned int)*id);
94194955Strasz		else
95194955Strasz			snprintf(str, size, "group:%s", grp->gr_name);
96194955Strasz		break;
97194955Strasz
98194955Strasz	case ACL_EVERYONE:
99194955Strasz		snprintf(str, size, "everyone@");
100194955Strasz		break;
101194955Strasz
102194955Strasz	default:
103194955Strasz		return (-1);
104194955Strasz	}
105194955Strasz
106194955Strasz	return (0);
107194955Strasz}
108194955Strasz
109194955Straszstatic int
110194955Straszformat_entry_type(char *str, size_t size, const acl_entry_t entry)
111194955Strasz{
112194955Strasz	int error;
113194955Strasz	acl_entry_type_t entry_type;
114194955Strasz
115194955Strasz	error = acl_get_entry_type_np(entry, &entry_type);
116194955Strasz	if (error)
117194955Strasz		return (error);
118194955Strasz
119194955Strasz	switch (entry_type) {
120194955Strasz	case ACL_ENTRY_TYPE_ALLOW:
121194955Strasz		snprintf(str, size, "allow");
122194955Strasz		break;
123194955Strasz	case ACL_ENTRY_TYPE_DENY:
124194955Strasz		snprintf(str, size, "deny");
125194955Strasz		break;
126194955Strasz	case ACL_ENTRY_TYPE_AUDIT:
127194955Strasz		snprintf(str, size, "audit");
128194955Strasz		break;
129194955Strasz	case ACL_ENTRY_TYPE_ALARM:
130194955Strasz		snprintf(str, size, "alarm");
131194955Strasz		break;
132194955Strasz	default:
133194955Strasz		return (-1);
134194955Strasz	}
135194955Strasz
136194955Strasz	return (0);
137194955Strasz}
138194955Strasz
139194955Straszstatic int
140194955Straszformat_additional_id(char *str, size_t size, const acl_entry_t entry)
141194955Strasz{
142194955Strasz	int error;
143194955Strasz	acl_tag_t tag;
144208811Strasz	uid_t *id;
145194955Strasz
146194955Strasz	error = acl_get_tag_type(entry, &tag);
147194955Strasz	if (error)
148194955Strasz		return (error);
149194955Strasz
150194955Strasz	switch (tag) {
151194955Strasz	case ACL_USER_OBJ:
152194955Strasz	case ACL_GROUP_OBJ:
153194955Strasz	case ACL_EVERYONE:
154194955Strasz		str[0] = '\0';
155194955Strasz		break;
156194955Strasz
157194955Strasz	default:
158208811Strasz		id = (uid_t *)acl_get_qualifier(entry);
159194955Strasz		if (id == NULL)
160194955Strasz			return (-1);
161194955Strasz		snprintf(str, size, ":%d", (unsigned int)*id);
162194955Strasz	}
163194955Strasz
164194955Strasz	return (0);
165194955Strasz}
166194955Strasz
167194955Straszstatic int
168194955Straszformat_entry(char *str, size_t size, const acl_entry_t entry, int flags)
169194955Strasz{
170205796Strasz	size_t off = 0, min_who_field_length = 18;
171194955Strasz	acl_permset_t permset;
172194955Strasz	acl_flagset_t flagset;
173194955Strasz	int error, len;
174194955Strasz	char buf[MAX_ENTRY_LENGTH + 1];
175194955Strasz
176194955Strasz	assert(_entry_brand(entry) == ACL_BRAND_NFS4);
177194955Strasz
178194955Strasz	error = acl_get_flagset_np(entry, &flagset);
179194955Strasz	if (error)
180194955Strasz		return (error);
181194955Strasz
182194955Strasz	error = acl_get_permset(entry, &permset);
183194955Strasz	if (error)
184194955Strasz		return (error);
185194955Strasz
186194955Strasz	error = format_who(buf, sizeof(buf), entry,
187194955Strasz	    flags & ACL_TEXT_NUMERIC_IDS);
188194955Strasz	if (error)
189194955Strasz		return (error);
190194955Strasz	len = strlen(buf);
191205796Strasz	if (len < min_who_field_length)
192205796Strasz		len = min_who_field_length;
193205796Strasz	off += snprintf(str + off, size - off, "%*s:", len, buf);
194194955Strasz
195194955Strasz	error = _nfs4_format_access_mask(buf, sizeof(buf), *permset,
196194955Strasz	    flags & ACL_TEXT_VERBOSE);
197194955Strasz	if (error)
198194955Strasz		return (error);
199194955Strasz	off += snprintf(str + off, size - off, "%s:", buf);
200194955Strasz
201194955Strasz	error = _nfs4_format_flags(buf, sizeof(buf), *flagset,
202194955Strasz	    flags & ACL_TEXT_VERBOSE);
203194955Strasz	if (error)
204194955Strasz		return (error);
205194955Strasz	off += snprintf(str + off, size - off, "%s:", buf);
206194955Strasz
207194955Strasz	error = format_entry_type(buf, sizeof(buf), entry);
208194955Strasz	if (error)
209194955Strasz		return (error);
210194955Strasz	off += snprintf(str + off, size - off, "%s", buf);
211194955Strasz
212194955Strasz	if (flags & ACL_TEXT_APPEND_ID) {
213194955Strasz		error = format_additional_id(buf, sizeof(buf), entry);
214194955Strasz		if (error)
215194955Strasz			return (error);
216194955Strasz		off += snprintf(str + off, size - off, "%s", buf);
217194955Strasz	}
218194955Strasz
219194955Strasz	off += snprintf(str + off, size - off, "\n");
220194955Strasz
221194955Strasz	/* Make sure we didn't truncate anything. */
222194955Strasz	assert (off < size);
223194955Strasz
224194955Strasz	return (0);
225194955Strasz}
226194955Strasz
227194955Straszchar *
228194955Strasz_nfs4_acl_to_text_np(const acl_t aclp, ssize_t *len_p, int flags)
229194955Strasz{
230194955Strasz	int error, off = 0, size, entry_id = ACL_FIRST_ENTRY;
231194955Strasz	char *str;
232194955Strasz	acl_entry_t entry;
233194955Strasz
234194955Strasz	if (aclp->ats_acl.acl_cnt == 0)
235194955Strasz		return strdup("");
236194955Strasz
237194955Strasz	size = aclp->ats_acl.acl_cnt * MAX_ENTRY_LENGTH;
238194955Strasz	str = malloc(size);
239194955Strasz	if (str == NULL)
240194955Strasz		return (NULL);
241194955Strasz
242194955Strasz	while (acl_get_entry(aclp, entry_id, &entry) == 1) {
243194955Strasz		entry_id = ACL_NEXT_ENTRY;
244194955Strasz
245194955Strasz		assert(off < size);
246194955Strasz
247194955Strasz		error = format_entry(str + off, size - off, entry, flags);
248194955Strasz		if (error) {
249208786Strasz			free(str);
250194955Strasz			errno = EINVAL;
251194955Strasz			return (NULL);
252194955Strasz		}
253194955Strasz
254194955Strasz		off = strlen(str);
255194955Strasz	}
256194955Strasz
257194955Strasz	assert(off < size);
258194955Strasz	str[off] = '\0';
259194955Strasz
260194955Strasz	if (len_p != NULL)
261194955Strasz		*len_p = off;
262194955Strasz
263194955Strasz	return (str);
264194955Strasz}
265