1 /*	$NetBSD: extattr.c,v 1.4 2012/03/13 21:13:34 christos 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.4 2012/03/13 21:13:34 christos 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 
48 const int extattr_namespaces[] = {
49 	EXTATTR_NAMESPACE_USER,
50 	EXTATTR_NAMESPACE_SYSTEM,
51 	0,
52 };
53 
54 int
extattr_namespace_to_string(int attrnamespace,char ** string)55 extattr_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 
80 int
extattr_string_to_namespace(const char * string,int * attrnamespace)81 extattr_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 
99 int
extattr_copy_fd(int from_fd,int to_fd,int namespace)100 extattr_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;
162 out:
163 	if (aval != NULL)
164 		free(aval);
165 
166 	if (alist != NULL)
167 		free(alist);
168 
169 	return error;
170 }
171 
172 int
extattr_copy_file(const char * from,const char * to,int namespace)173 extattr_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 	size_t 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 < (size_t)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;
234 out:
235 	if (aval != NULL)
236 		free(aval);
237 
238 	if (alist != NULL)
239 		free(alist);
240 
241 	return error;
242 }
243 
244 int
extattr_copy_link(const char * from,const char * to,int namespace)245 extattr_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 	size_t 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 < (size_t)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;
307 out:
308 	if (aval != NULL)
309 		free(aval);
310 
311 	if (alist != NULL)
312 		free(alist);
313 
314 	return error;
315 }
316 
317 static int
extattr_namespace_access(int namespace,int mode)318 extattr_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 
332 int
fcpxattr(int from_fd,int to_fd)333 fcpxattr(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 
349 int
cpxattr(const char * from,const char * to)350 cpxattr(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 
366 int
lcpxattr(const char * from,const char * to)367 lcpxattr(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