1/*	$NetBSD: extattr.c,v 1.2 2005/02/09 21:35:46 kleink 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.2 2005/02/09 21:35:46 kleink 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	int 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 < 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	if (aval != NULL)
164		free(aval);
165
166	if (alist != NULL)
167		free(alist);
168
169	return error;
170}
171
172int
173extattr_copy_file(const char *from, const char *to, int namespace)
174{
175	ssize_t llen, vlen, maxvlen;
176	size_t alen;
177	void *alist = NULL;
178	void *aval = NULL;
179	int i;
180	int error = -1;
181
182	llen = extattr_list_file(from, namespace, NULL, 0);
183	if (llen == -1) {
184		/* Silently ignore when EA are not supported */
185		if (errno == EOPNOTSUPP)
186			error = 0;
187		goto out;
188	}
189
190	if (llen == 0) {
191		error = 0;
192		goto out;
193	}
194
195	if ((alist = malloc((size_t)llen)) == NULL)
196		goto out;
197
198	llen = extattr_list_file(from, namespace, alist, (size_t)llen);
199	if (llen == -1)
200		goto out;
201
202	maxvlen = 1024;
203	if ((aval = malloc((size_t)maxvlen)) == NULL)
204		goto out;
205
206	for (i = 0; i < llen; i += alen + 1) {
207		char aname[NAME_MAX + 1];
208		char *ap;
209
210		alen = ((uint8_t *)alist)[i];
211		ap = ((char *)alist) + i + 1;
212		(void)memcpy(aname, ap, alen);
213		aname[alen] = '\0';
214
215		vlen = extattr_get_file(from, namespace, aname, NULL, 0);
216		if (vlen == -1)
217			goto out;
218
219		if (vlen > maxvlen) {
220			if ((aval = realloc(aval, (size_t)vlen)) == NULL)
221				goto out;
222			maxvlen = vlen;
223		}
224
225		if ((vlen = extattr_get_file(from, namespace, aname,							     aval, (size_t)vlen)) == -1)
226			goto out;
227
228		if (extattr_set_file(to, namespace, aname,
229				     aval, (size_t)vlen) != vlen)
230			goto out;
231	}
232
233	error = 0;
234out:
235	if (aval != NULL)
236		free(aval);
237
238	if (alist != NULL)
239		free(alist);
240
241	return error;
242}
243
244int
245extattr_copy_link(const char *from, const char *to, int namespace)
246{
247	ssize_t llen, vlen, maxvlen;
248	size_t alen;
249	void *alist = NULL;
250	void *aval = NULL;
251	int i;
252	int error = -1;
253
254	llen = extattr_list_link(from, namespace, NULL, 0);
255	if (llen == -1) {
256		/* Silently ignore when EA are not supported */
257		if (errno == EOPNOTSUPP)
258			error = 0;
259		goto out;
260	}
261
262	if (llen == 0) {
263		error = 0;
264		goto out;
265	}
266
267	if ((alist = malloc((size_t)llen)) == NULL)
268		goto out;
269
270	llen = extattr_list_link(from, namespace, alist, (size_t)llen);
271	if (llen == -1)
272		goto out;
273
274	maxvlen = 1024;
275	if ((aval = malloc((size_t)maxvlen)) == NULL)
276		goto out;
277
278	for (i = 0; i < llen; i += alen + 1) {
279		char aname[NAME_MAX + 1];
280		char *ap;
281
282		alen = ((uint8_t *)alist)[i];
283		ap = ((char *)alist) + i + 1;
284		(void)memcpy(aname, ap, alen);
285		aname[alen] = '\0';
286
287		vlen = extattr_get_link(from, namespace, aname, NULL, 0);
288		if (vlen == -1)
289			goto out;
290
291		if (vlen > maxvlen) {
292			if ((aval = realloc(aval, (size_t)vlen)) == NULL)
293				goto out;
294			maxvlen = vlen;
295		}
296
297		if ((vlen = extattr_get_link(from, namespace, aname,
298					     aval, (size_t)vlen)) == -1)
299			goto out;
300
301		if (extattr_set_link(to, namespace, aname,
302				     aval, (size_t)vlen) != vlen)
303			goto out;
304	}
305
306	error = 0;
307out:
308	if (aval != NULL)
309		free(aval);
310
311	if (alist != NULL)
312		free(alist);
313
314	return error;
315}
316
317static int
318extattr_namespace_access(int namespace, int mode)
319{
320	switch (namespace) {
321	case EXTATTR_NAMESPACE_SYSTEM:
322		if ((mode & (R_OK|W_OK)) && getuid() != 0)
323			return -1;
324		break;
325	default:
326		break;
327	}
328
329	return 0;
330}
331
332int
333fcpxattr(int from_fd, int to_fd)
334{
335	const int *ns;
336	int error;
337
338	for (ns = extattr_namespaces; *ns; ns++) {
339		if (extattr_namespace_access(*ns, R_OK|W_OK) != 0)
340			continue;
341
342		if ((error = extattr_copy_fd(from_fd, to_fd, *ns)) != 0)
343			return error;
344	}
345
346	return 0;
347}
348
349int
350cpxattr(const char *from, const char *to)
351{
352	const int *ns;
353	int error;
354
355	for (ns = extattr_namespaces; *ns; ns++) {
356		if (extattr_namespace_access(*ns, R_OK|W_OK) != 0)
357			continue;
358
359		if ((error = extattr_copy_file(from, to, *ns)) != 0)
360			return error;
361	}
362
363	return 0;
364}
365
366int
367lcpxattr(const char *from, const char *to)
368{
369	const int *ns;
370	int error;
371
372	for (ns = extattr_namespaces; *ns; ns++) {
373		if (extattr_namespace_access(*ns, R_OK|W_OK) != 0)
374			continue;
375
376		if ((error = extattr_copy_link(from, to, *ns)) != 0)
377			return error;
378	}
379
380	return 0;
381}
382