xref: /netbsd-src/lib/libc/gen/extattr.c (revision 7ab45b5b71e0db9b3934ed389fb84b81ca5013a6)
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