1*7ab45b5bSmaya /* $NetBSD: extattr.c,v 1.5 2017/03/09 11:39:41 maya Exp $ */
2c165c2b3Sthorpej
3c165c2b3Sthorpej /*-
4c165c2b3Sthorpej * Copyright (c) 2001 Robert N. M. Watson
5c165c2b3Sthorpej * All rights reserved.
6c165c2b3Sthorpej *
7c165c2b3Sthorpej * Redistribution and use in source and binary forms, with or without
8c165c2b3Sthorpej * modification, are permitted provided that the following conditions
9c165c2b3Sthorpej * are met:
10c165c2b3Sthorpej * 1. Redistributions of source code must retain the above copyright
11c165c2b3Sthorpej * notice, this list of conditions and the following disclaimer.
12c165c2b3Sthorpej * 2. Redistributions in binary form must reproduce the above copyright
13c165c2b3Sthorpej * notice, this list of conditions and the following disclaimer in the
14c165c2b3Sthorpej * documentation and/or other materials provided with the distribution.
15c165c2b3Sthorpej *
16c165c2b3Sthorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17c165c2b3Sthorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18c165c2b3Sthorpej * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19c165c2b3Sthorpej * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20c165c2b3Sthorpej * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21c165c2b3Sthorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22c165c2b3Sthorpej * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23c165c2b3Sthorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24c165c2b3Sthorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25c165c2b3Sthorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26c165c2b3Sthorpej * SUCH DAMAGE.
27c165c2b3Sthorpej */
28c165c2b3Sthorpej
29c165c2b3Sthorpej /*
30c165c2b3Sthorpej * TrustedBSD: Utility functions for extended attributes.
31c165c2b3Sthorpej */
32c165c2b3Sthorpej
33c165c2b3Sthorpej #include <sys/cdefs.h>
34c165c2b3Sthorpej #if defined(LIBC_SCCS) && !defined(lint)
35*7ab45b5bSmaya __RCSID("$NetBSD: extattr.c,v 1.5 2017/03/09 11:39:41 maya Exp $");
36c165c2b3Sthorpej #endif /* LIBC_SCCS and not lint */
37c165c2b3Sthorpej
38fd5cb0acSkleink #include "namespace.h"
39c165c2b3Sthorpej #include <sys/types.h>
4032c00d62Smanu #include <sys/param.h>
41c165c2b3Sthorpej #include <sys/extattr.h>
42c165c2b3Sthorpej
43c165c2b3Sthorpej #include <errno.h>
4432c00d62Smanu #include <unistd.h>
4532c00d62Smanu #include <stdlib.h>
46c165c2b3Sthorpej #include <string.h>
47c165c2b3Sthorpej
4832c00d62Smanu const int extattr_namespaces[] = {
4932c00d62Smanu EXTATTR_NAMESPACE_USER,
5032c00d62Smanu EXTATTR_NAMESPACE_SYSTEM,
5132c00d62Smanu 0,
5232c00d62Smanu };
5332c00d62Smanu
54c165c2b3Sthorpej int
extattr_namespace_to_string(int attrnamespace,char ** string)55c165c2b3Sthorpej extattr_namespace_to_string(int attrnamespace, char **string)
56c165c2b3Sthorpej {
57c165c2b3Sthorpej
58c165c2b3Sthorpej switch(attrnamespace) {
59c165c2b3Sthorpej case EXTATTR_NAMESPACE_USER:
60c165c2b3Sthorpej if (string != NULL) {
61c165c2b3Sthorpej if ((*string =
62c165c2b3Sthorpej strdup(EXTATTR_NAMESPACE_USER_STRING)) == NULL)
63c165c2b3Sthorpej return (-1);
64c165c2b3Sthorpej }
65c165c2b3Sthorpej return (0);
66c165c2b3Sthorpej
67c165c2b3Sthorpej case EXTATTR_NAMESPACE_SYSTEM:
68c165c2b3Sthorpej if (string != NULL)
69c165c2b3Sthorpej if ((*string =
70c165c2b3Sthorpej strdup(EXTATTR_NAMESPACE_SYSTEM_STRING)) == NULL)
71c165c2b3Sthorpej return (-1);
72c165c2b3Sthorpej return (0);
73c165c2b3Sthorpej
74c165c2b3Sthorpej default:
75c165c2b3Sthorpej errno = EINVAL;
76c165c2b3Sthorpej return (-1);
77c165c2b3Sthorpej }
78c165c2b3Sthorpej }
79c165c2b3Sthorpej
80c165c2b3Sthorpej int
extattr_string_to_namespace(const char * string,int * attrnamespace)81c165c2b3Sthorpej extattr_string_to_namespace(const char *string, int *attrnamespace)
82c165c2b3Sthorpej {
83c165c2b3Sthorpej
84c165c2b3Sthorpej if (strcmp(string, EXTATTR_NAMESPACE_USER_STRING) == 0) {
85c165c2b3Sthorpej if (attrnamespace != NULL)
86c165c2b3Sthorpej *attrnamespace = EXTATTR_NAMESPACE_USER;
87c165c2b3Sthorpej return (0);
88c165c2b3Sthorpej } else if (strcmp(string, EXTATTR_NAMESPACE_SYSTEM_STRING) == 0) {
89c165c2b3Sthorpej if (attrnamespace != NULL)
90c165c2b3Sthorpej *attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
91c165c2b3Sthorpej return (0);
92c165c2b3Sthorpej } else {
93c165c2b3Sthorpej errno = EINVAL;
94c165c2b3Sthorpej return (-1);
95c165c2b3Sthorpej }
96c165c2b3Sthorpej }
9732c00d62Smanu
9832c00d62Smanu
9932c00d62Smanu int
extattr_copy_fd(int from_fd,int to_fd,int namespace)10032c00d62Smanu extattr_copy_fd(int from_fd, int to_fd, int namespace)
10132c00d62Smanu {
10232c00d62Smanu ssize_t llen, vlen, maxvlen;
10332c00d62Smanu size_t alen;
10432c00d62Smanu void *alist = NULL;
10532c00d62Smanu void *aval = NULL;
106c5e820caSchristos size_t i;
10732c00d62Smanu int error = -1;
10832c00d62Smanu
10932c00d62Smanu llen = extattr_list_fd(from_fd, namespace, NULL, 0);
11032c00d62Smanu if (llen == -1) {
11132c00d62Smanu /* Silently ignore when EA are not supported */
11232c00d62Smanu if (errno == EOPNOTSUPP)
11332c00d62Smanu error = 0;
11432c00d62Smanu goto out;
11532c00d62Smanu }
11632c00d62Smanu
11732c00d62Smanu if (llen == 0) {
11832c00d62Smanu error = 0;
11932c00d62Smanu goto out;
12032c00d62Smanu }
12132c00d62Smanu
12232c00d62Smanu if ((alist = malloc((size_t)llen)) == NULL)
12332c00d62Smanu goto out;
12432c00d62Smanu
12532c00d62Smanu llen = extattr_list_fd(from_fd, namespace, alist, (size_t)llen);
12632c00d62Smanu if (llen == -1)
12732c00d62Smanu goto out;
12832c00d62Smanu
12932c00d62Smanu maxvlen = 1024;
13032c00d62Smanu if ((aval = malloc((size_t)maxvlen)) == NULL)
13132c00d62Smanu goto out;
13232c00d62Smanu
133c5e820caSchristos for (i = 0; i < (size_t)llen; i += alen + 1) {
13432c00d62Smanu char aname[NAME_MAX + 1];
13532c00d62Smanu char *ap;
13632c00d62Smanu
13732c00d62Smanu alen = ((uint8_t *)alist)[i];
13832c00d62Smanu ap = ((char *)alist) + i + 1;
13932c00d62Smanu (void)memcpy(aname, ap, alen);
14032c00d62Smanu aname[alen] = '\0';
14132c00d62Smanu
14232c00d62Smanu vlen = extattr_get_fd(from_fd, namespace, aname, NULL, 0);
14332c00d62Smanu if (vlen == -1)
14432c00d62Smanu goto out;
14532c00d62Smanu
14632c00d62Smanu if (vlen > maxvlen) {
14732c00d62Smanu if ((aval = realloc(aval, (size_t)vlen)) == NULL)
14832c00d62Smanu goto out;
14932c00d62Smanu maxvlen = vlen;
15032c00d62Smanu }
15132c00d62Smanu
15232c00d62Smanu if ((vlen = extattr_get_fd(from_fd, namespace, aname,
15332c00d62Smanu aval, (size_t)vlen)) == -1)
15432c00d62Smanu goto out;
15532c00d62Smanu
15632c00d62Smanu if (extattr_set_fd(to_fd, namespace, aname,
15732c00d62Smanu aval, (size_t)vlen) != vlen)
15832c00d62Smanu goto out;
15932c00d62Smanu }
16032c00d62Smanu
16132c00d62Smanu error = 0;
16232c00d62Smanu out:
16332c00d62Smanu free(aval);
16432c00d62Smanu free(alist);
16532c00d62Smanu
16632c00d62Smanu return error;
16732c00d62Smanu }
16832c00d62Smanu
16932c00d62Smanu int
extattr_copy_file(const char * from,const char * to,int namespace)17032c00d62Smanu extattr_copy_file(const char *from, const char *to, int namespace)
17132c00d62Smanu {
17232c00d62Smanu ssize_t llen, vlen, maxvlen;
17332c00d62Smanu size_t alen;
17432c00d62Smanu void *alist = NULL;
17532c00d62Smanu void *aval = NULL;
176c5e820caSchristos size_t i;
17732c00d62Smanu int error = -1;
17832c00d62Smanu
17932c00d62Smanu llen = extattr_list_file(from, namespace, NULL, 0);
18032c00d62Smanu if (llen == -1) {
18132c00d62Smanu /* Silently ignore when EA are not supported */
18232c00d62Smanu if (errno == EOPNOTSUPP)
18332c00d62Smanu error = 0;
18432c00d62Smanu goto out;
18532c00d62Smanu }
18632c00d62Smanu
18732c00d62Smanu if (llen == 0) {
18832c00d62Smanu error = 0;
18932c00d62Smanu goto out;
19032c00d62Smanu }
19132c00d62Smanu
19232c00d62Smanu if ((alist = malloc((size_t)llen)) == NULL)
19332c00d62Smanu goto out;
19432c00d62Smanu
19532c00d62Smanu llen = extattr_list_file(from, namespace, alist, (size_t)llen);
19632c00d62Smanu if (llen == -1)
19732c00d62Smanu goto out;
19832c00d62Smanu
19932c00d62Smanu maxvlen = 1024;
20032c00d62Smanu if ((aval = malloc((size_t)maxvlen)) == NULL)
20132c00d62Smanu goto out;
20232c00d62Smanu
203c5e820caSchristos for (i = 0; i < (size_t)llen; i += alen + 1) {
20432c00d62Smanu char aname[NAME_MAX + 1];
20532c00d62Smanu char *ap;
20632c00d62Smanu
20732c00d62Smanu alen = ((uint8_t *)alist)[i];
20832c00d62Smanu ap = ((char *)alist) + i + 1;
20932c00d62Smanu (void)memcpy(aname, ap, alen);
21032c00d62Smanu aname[alen] = '\0';
21132c00d62Smanu
21232c00d62Smanu vlen = extattr_get_file(from, namespace, aname, NULL, 0);
21332c00d62Smanu if (vlen == -1)
21432c00d62Smanu goto out;
21532c00d62Smanu
21632c00d62Smanu if (vlen > maxvlen) {
21732c00d62Smanu if ((aval = realloc(aval, (size_t)vlen)) == NULL)
21832c00d62Smanu goto out;
21932c00d62Smanu maxvlen = vlen;
22032c00d62Smanu }
22132c00d62Smanu
222*7ab45b5bSmaya if ((vlen = extattr_get_file(from, namespace, aname,
223*7ab45b5bSmaya aval, (size_t)vlen)) == -1)
22432c00d62Smanu goto out;
22532c00d62Smanu
22632c00d62Smanu if (extattr_set_file(to, namespace, aname,
22732c00d62Smanu aval, (size_t)vlen) != vlen)
22832c00d62Smanu goto out;
22932c00d62Smanu }
23032c00d62Smanu
23132c00d62Smanu error = 0;
23232c00d62Smanu out:
23332c00d62Smanu free(aval);
23432c00d62Smanu free(alist);
23532c00d62Smanu
23632c00d62Smanu return error;
23732c00d62Smanu }
23832c00d62Smanu
23932c00d62Smanu int
extattr_copy_link(const char * from,const char * to,int namespace)24032c00d62Smanu extattr_copy_link(const char *from, const char *to, int namespace)
24132c00d62Smanu {
24232c00d62Smanu ssize_t llen, vlen, maxvlen;
24332c00d62Smanu size_t alen;
24432c00d62Smanu void *alist = NULL;
24532c00d62Smanu void *aval = NULL;
246c5e820caSchristos size_t i;
24732c00d62Smanu int error = -1;
24832c00d62Smanu
24932c00d62Smanu llen = extattr_list_link(from, namespace, NULL, 0);
25032c00d62Smanu if (llen == -1) {
25132c00d62Smanu /* Silently ignore when EA are not supported */
25232c00d62Smanu if (errno == EOPNOTSUPP)
25332c00d62Smanu error = 0;
25432c00d62Smanu goto out;
25532c00d62Smanu }
25632c00d62Smanu
25732c00d62Smanu if (llen == 0) {
25832c00d62Smanu error = 0;
25932c00d62Smanu goto out;
26032c00d62Smanu }
26132c00d62Smanu
26232c00d62Smanu if ((alist = malloc((size_t)llen)) == NULL)
26332c00d62Smanu goto out;
26432c00d62Smanu
26532c00d62Smanu llen = extattr_list_link(from, namespace, alist, (size_t)llen);
26632c00d62Smanu if (llen == -1)
26732c00d62Smanu goto out;
26832c00d62Smanu
26932c00d62Smanu maxvlen = 1024;
27032c00d62Smanu if ((aval = malloc((size_t)maxvlen)) == NULL)
27132c00d62Smanu goto out;
27232c00d62Smanu
273c5e820caSchristos for (i = 0; i < (size_t)llen; i += alen + 1) {
27432c00d62Smanu char aname[NAME_MAX + 1];
27532c00d62Smanu char *ap;
27632c00d62Smanu
27732c00d62Smanu alen = ((uint8_t *)alist)[i];
27832c00d62Smanu ap = ((char *)alist) + i + 1;
27932c00d62Smanu (void)memcpy(aname, ap, alen);
28032c00d62Smanu aname[alen] = '\0';
28132c00d62Smanu
28232c00d62Smanu vlen = extattr_get_link(from, namespace, aname, NULL, 0);
28332c00d62Smanu if (vlen == -1)
28432c00d62Smanu goto out;
28532c00d62Smanu
28632c00d62Smanu if (vlen > maxvlen) {
28732c00d62Smanu if ((aval = realloc(aval, (size_t)vlen)) == NULL)
28832c00d62Smanu goto out;
28932c00d62Smanu maxvlen = vlen;
29032c00d62Smanu }
29132c00d62Smanu
29232c00d62Smanu if ((vlen = extattr_get_link(from, namespace, aname,
29332c00d62Smanu aval, (size_t)vlen)) == -1)
29432c00d62Smanu goto out;
29532c00d62Smanu
29632c00d62Smanu if (extattr_set_link(to, namespace, aname,
29732c00d62Smanu aval, (size_t)vlen) != vlen)
29832c00d62Smanu goto out;
29932c00d62Smanu }
30032c00d62Smanu
30132c00d62Smanu error = 0;
30232c00d62Smanu out:
30332c00d62Smanu free(aval);
30432c00d62Smanu free(alist);
30532c00d62Smanu
30632c00d62Smanu return error;
30732c00d62Smanu }
30832c00d62Smanu
30932c00d62Smanu static int
extattr_namespace_access(int namespace,int mode)31032c00d62Smanu extattr_namespace_access(int namespace, int mode)
31132c00d62Smanu {
31232c00d62Smanu switch (namespace) {
31332c00d62Smanu case EXTATTR_NAMESPACE_SYSTEM:
31432c00d62Smanu if ((mode & (R_OK|W_OK)) && getuid() != 0)
31532c00d62Smanu return -1;
31632c00d62Smanu break;
31732c00d62Smanu default:
31832c00d62Smanu break;
31932c00d62Smanu }
32032c00d62Smanu
32132c00d62Smanu return 0;
32232c00d62Smanu }
32332c00d62Smanu
32432c00d62Smanu int
fcpxattr(int from_fd,int to_fd)32532c00d62Smanu fcpxattr(int from_fd, int to_fd)
32632c00d62Smanu {
32732c00d62Smanu const int *ns;
32832c00d62Smanu int error;
32932c00d62Smanu
33032c00d62Smanu for (ns = extattr_namespaces; *ns; ns++) {
33132c00d62Smanu if (extattr_namespace_access(*ns, R_OK|W_OK) != 0)
33232c00d62Smanu continue;
33332c00d62Smanu
33432c00d62Smanu if ((error = extattr_copy_fd(from_fd, to_fd, *ns)) != 0)
33532c00d62Smanu return error;
33632c00d62Smanu }
33732c00d62Smanu
33832c00d62Smanu return 0;
33932c00d62Smanu }
34032c00d62Smanu
34132c00d62Smanu int
cpxattr(const char * from,const char * to)34232c00d62Smanu cpxattr(const char *from, const char *to)
34332c00d62Smanu {
34432c00d62Smanu const int *ns;
34532c00d62Smanu int error;
34632c00d62Smanu
34732c00d62Smanu for (ns = extattr_namespaces; *ns; ns++) {
34832c00d62Smanu if (extattr_namespace_access(*ns, R_OK|W_OK) != 0)
34932c00d62Smanu continue;
35032c00d62Smanu
35132c00d62Smanu if ((error = extattr_copy_file(from, to, *ns)) != 0)
35232c00d62Smanu return error;
35332c00d62Smanu }
35432c00d62Smanu
35532c00d62Smanu return 0;
35632c00d62Smanu }
35732c00d62Smanu
35832c00d62Smanu int
lcpxattr(const char * from,const char * to)35932c00d62Smanu lcpxattr(const char *from, const char *to)
36032c00d62Smanu {
36132c00d62Smanu const int *ns;
36232c00d62Smanu int error;
36332c00d62Smanu
36432c00d62Smanu for (ns = extattr_namespaces; *ns; ns++) {
36532c00d62Smanu if (extattr_namespace_access(*ns, R_OK|W_OK) != 0)
36632c00d62Smanu continue;
36732c00d62Smanu
36832c00d62Smanu if ((error = extattr_copy_link(from, to, *ns)) != 0)
36932c00d62Smanu return error;
37032c00d62Smanu }
37132c00d62Smanu
37232c00d62Smanu return 0;
37332c00d62Smanu }
374