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
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 free(aval);
164 free(alist);
165
166 return error;
167 }
168
169 int
extattr_copy_file(const char * from,const char * to,int namespace)170 extattr_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;
232 out:
233 free(aval);
234 free(alist);
235
236 return error;
237 }
238
239 int
extattr_copy_link(const char * from,const char * to,int namespace)240 extattr_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;
302 out:
303 free(aval);
304 free(alist);
305
306 return error;
307 }
308
309 static int
extattr_namespace_access(int namespace,int mode)310 extattr_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
324 int
fcpxattr(int from_fd,int to_fd)325 fcpxattr(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
341 int
cpxattr(const char * from,const char * to)342 cpxattr(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
358 int
lcpxattr(const char * from,const char * to)359 lcpxattr(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