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