1/*	$NetBSD: extattr.c,v 1.5 2017/03/09 11:39:41 maya Exp $	*/
2
3/*-
4 * Copyright (c) 2001 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/*
30 * TrustedBSD: Utility functions for extended attributes.
31 */
32
33#include <sys/cdefs.h>
34#if defined(LIBC_SCCS) && !defined(lint)
35__RCSID("$NetBSD: extattr.c,v 1.5 2017/03/09 11:39:41 maya Exp $");
36#endif /* LIBC_SCCS and not lint */
37
38#include "namespace.h"
39#include <sys/types.h>
40#include <sys/param.h>
41#include <sys/extattr.h>
42
43#include <errno.h>
44#include <unistd.h>
45#include <stdlib.h>
46#include <string.h>
47
48const int extattr_namespaces[] = {
49	EXTATTR_NAMESPACE_USER,
50	EXTATTR_NAMESPACE_SYSTEM,
51	0,
52};
53
54int
55extattr_namespace_to_string(int attrnamespace, char **string)
56{
57
58	switch(attrnamespace) {
59	case EXTATTR_NAMESPACE_USER:
60		if (string != NULL) {
61			if ((*string =
62			     strdup(EXTATTR_NAMESPACE_USER_STRING)) == NULL)
63				return (-1);
64		}
65		return (0);
66
67	case EXTATTR_NAMESPACE_SYSTEM:
68		if (string != NULL)
69			if ((*string =
70			     strdup(EXTATTR_NAMESPACE_SYSTEM_STRING)) == NULL)
71				return (-1);
72		return (0);
73
74	default:
75		errno = EINVAL;
76		return (-1);
77	}
78}
79
80int
81extattr_string_to_namespace(const char *string, int *attrnamespace)
82{
83
84	if (strcmp(string, EXTATTR_NAMESPACE_USER_STRING) == 0) {
85		if (attrnamespace != NULL)
86			*attrnamespace = EXTATTR_NAMESPACE_USER;
87		return (0);
88	} else if (strcmp(string, EXTATTR_NAMESPACE_SYSTEM_STRING) == 0) {
89		if (attrnamespace != NULL)
90			*attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
91		return (0);
92	} else {
93		errno = EINVAL;
94		return (-1);
95	}
96}
97
98
99int
100extattr_copy_fd(int from_fd, int to_fd, int namespace)
101{
102	ssize_t llen, vlen, maxvlen;
103	size_t alen;
104	void *alist = NULL;
105	void *aval = NULL;
106	size_t i;
107	int error = -1;
108
109	llen = extattr_list_fd(from_fd, namespace, NULL, 0);
110	if (llen == -1) {
111		/* Silently ignore when EA are not supported */
112		if (errno == EOPNOTSUPP)
113			error = 0;
114		goto out;
115	}
116
117	if (llen == 0) {
118		error = 0;
119		goto out;
120	}
121
122	if ((alist = malloc((size_t)llen)) == NULL)
123		goto out;
124
125	llen = extattr_list_fd(from_fd, namespace, alist, (size_t)llen);
126	if (llen == -1)
127		goto out;
128
129	maxvlen = 1024;
130	if ((aval = malloc((size_t)maxvlen)) == NULL)
131		goto out;
132
133	for (i = 0; i < (size_t)llen; i += alen + 1) {
134		char aname[NAME_MAX + 1];
135		char *ap;
136
137		alen = ((uint8_t *)alist)[i];
138		ap = ((char *)alist) + i + 1;
139		(void)memcpy(aname, ap, alen);
140		aname[alen] = '\0';
141
142		vlen = extattr_get_fd(from_fd, namespace, aname, NULL, 0);
143		if (vlen == -1)
144			goto out;
145
146		if (vlen > maxvlen) {
147			if ((aval = realloc(aval, (size_t)vlen)) == NULL)
148				goto out;
149			maxvlen = vlen;
150		}
151
152		if ((vlen = extattr_get_fd(from_fd, namespace, aname,
153					   aval, (size_t)vlen)) == -1)
154			goto out;
155
156		if (extattr_set_fd(to_fd, namespace, aname,
157				   aval, (size_t)vlen) != vlen)
158			goto out;
159	}
160
161	error = 0;
162out:
163	free(aval);
164	free(alist);
165
166	return error;
167}
168
169int
170extattr_copy_file(const char *from, const char *to, int namespace)
171{
172	ssize_t llen, vlen, maxvlen;
173	size_t alen;
174	void *alist = NULL;
175	void *aval = NULL;
176	size_t i;
177	int error = -1;
178
179	llen = extattr_list_file(from, namespace, NULL, 0);
180	if (llen == -1) {
181		/* Silently ignore when EA are not supported */
182		if (errno == EOPNOTSUPP)
183			error = 0;
184		goto out;
185	}
186
187	if (llen == 0) {
188		error = 0;
189		goto out;
190	}
191
192	if ((alist = malloc((size_t)llen)) == NULL)
193		goto out;
194
195	llen = extattr_list_file(from, namespace, alist, (size_t)llen);
196	if (llen == -1)
197		goto out;
198
199	maxvlen = 1024;
200	if ((aval = malloc((size_t)maxvlen)) == NULL)
201		goto out;
202
203	for (i = 0; i < (size_t)llen; i += alen + 1) {
204		char aname[NAME_MAX + 1];
205		char *ap;
206
207		alen = ((uint8_t *)alist)[i];
208		ap = ((char *)alist) + i + 1;
209		(void)memcpy(aname, ap, alen);
210		aname[alen] = '\0';
211
212		vlen = extattr_get_file(from, namespace, aname, NULL, 0);
213		if (vlen == -1)
214			goto out;
215
216		if (vlen > maxvlen) {
217			if ((aval = realloc(aval, (size_t)vlen)) == NULL)
218				goto out;
219			maxvlen = vlen;
220		}
221
222		if ((vlen = extattr_get_file(from, namespace, aname,
223						aval, (size_t)vlen)) == -1)
224			goto out;
225
226		if (extattr_set_file(to, namespace, aname,
227				     aval, (size_t)vlen) != vlen)
228			goto out;
229	}
230
231	error = 0;
232out:
233	free(aval);
234	free(alist);
235
236	return error;
237}
238
239int
240extattr_copy_link(const char *from, const char *to, int namespace)
241{
242	ssize_t llen, vlen, maxvlen;
243	size_t alen;
244	void *alist = NULL;
245	void *aval = NULL;
246	size_t i;
247	int error = -1;
248
249	llen = extattr_list_link(from, namespace, NULL, 0);
250	if (llen == -1) {
251		/* Silently ignore when EA are not supported */
252		if (errno == EOPNOTSUPP)
253			error = 0;
254		goto out;
255	}
256
257	if (llen == 0) {
258		error = 0;
259		goto out;
260	}
261
262	if ((alist = malloc((size_t)llen)) == NULL)
263		goto out;
264
265	llen = extattr_list_link(from, namespace, alist, (size_t)llen);
266	if (llen == -1)
267		goto out;
268
269	maxvlen = 1024;
270	if ((aval = malloc((size_t)maxvlen)) == NULL)
271		goto out;
272
273	for (i = 0; i < (size_t)llen; i += alen + 1) {
274		char aname[NAME_MAX + 1];
275		char *ap;
276
277		alen = ((uint8_t *)alist)[i];
278		ap = ((char *)alist) + i + 1;
279		(void)memcpy(aname, ap, alen);
280		aname[alen] = '\0';
281
282		vlen = extattr_get_link(from, namespace, aname, NULL, 0);
283		if (vlen == -1)
284			goto out;
285
286		if (vlen > maxvlen) {
287			if ((aval = realloc(aval, (size_t)vlen)) == NULL)
288				goto out;
289			maxvlen = vlen;
290		}
291
292		if ((vlen = extattr_get_link(from, namespace, aname,
293					     aval, (size_t)vlen)) == -1)
294			goto out;
295
296		if (extattr_set_link(to, namespace, aname,
297				     aval, (size_t)vlen) != vlen)
298			goto out;
299	}
300
301	error = 0;
302out:
303	free(aval);
304	free(alist);
305
306	return error;
307}
308
309static int
310extattr_namespace_access(int namespace, int mode)
311{
312	switch (namespace) {
313	case EXTATTR_NAMESPACE_SYSTEM:
314		if ((mode & (R_OK|W_OK)) && getuid() != 0)
315			return -1;
316		break;
317	default:
318		break;
319	}
320
321	return 0;
322}
323
324int
325fcpxattr(int from_fd, int to_fd)
326{
327	const int *ns;
328	int error;
329
330	for (ns = extattr_namespaces; *ns; ns++) {
331		if (extattr_namespace_access(*ns, R_OK|W_OK) != 0)
332			continue;
333
334		if ((error = extattr_copy_fd(from_fd, to_fd, *ns)) != 0)
335			return error;
336	}
337
338	return 0;
339}
340
341int
342cpxattr(const char *from, const char *to)
343{
344	const int *ns;
345	int error;
346
347	for (ns = extattr_namespaces; *ns; ns++) {
348		if (extattr_namespace_access(*ns, R_OK|W_OK) != 0)
349			continue;
350
351		if ((error = extattr_copy_file(from, to, *ns)) != 0)
352			return error;
353	}
354
355	return 0;
356}
357
358int
359lcpxattr(const char *from, const char *to)
360{
361	const int *ns;
362	int error;
363
364	for (ns = extattr_namespaces; *ns; ns++) {
365		if (extattr_namespace_access(*ns, R_OK|W_OK) != 0)
366			continue;
367
368		if ((error = extattr_copy_link(from, to, *ns)) != 0)
369			return error;
370	}
371
372	return 0;
373}
374