1#include <unistd.h>
2#include <fcntl.h>
3#include <string.h>
4#include <stdlib.h>
5#include <errno.h>
6#include <stdio.h>
7#include <sys/xattr.h>
8#include "selinux_internal.h"
9#include "policy.h"
10
11static ssize_t fgetxattr_wrapper(int fd, const char *name, void *value, size_t size) {
12	char buf[40];
13	int fd_flag, saved_errno = errno;
14	ssize_t ret;
15
16	ret = fgetxattr(fd, name, value, size);
17	if (ret != -1 || errno != EBADF)
18		return ret;
19
20	/* Emulate O_PATH support */
21	fd_flag = fcntl(fd, F_GETFL);
22	if (fd_flag == -1 || (fd_flag & O_PATH) == 0) {
23		errno = EBADF;
24		return -1;
25	}
26
27	snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
28	errno = saved_errno;
29	ret = getxattr(buf, name, value, size);
30	if (ret < 0 && errno == ENOENT)
31		errno = EBADF;
32	return ret;
33}
34
35int fgetfilecon_raw(int fd, char ** context)
36{
37	char *buf;
38	ssize_t size;
39	ssize_t ret;
40
41	size = INITCONTEXTLEN + 1;
42	buf = malloc(size);
43	if (!buf)
44		return -1;
45	memset(buf, 0, size);
46
47	ret = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, buf, size - 1);
48	if (ret < 0 && errno == ERANGE) {
49		char *newbuf;
50
51		size = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, NULL, 0);
52		if (size < 0)
53			goto out;
54
55		size++;
56		newbuf = realloc(buf, size);
57		if (!newbuf)
58			goto out;
59
60		buf = newbuf;
61		memset(buf, 0, size);
62		ret = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, buf, size - 1);
63	}
64      out:
65	if (ret == 0) {
66		/* Re-map empty attribute values to errors. */
67		errno = ENOTSUP;
68		ret = -1;
69	}
70	if (ret < 0)
71		free(buf);
72	else
73		*context = buf;
74	return ret;
75}
76
77
78int fgetfilecon(int fd, char ** context)
79{
80	char * rcontext = NULL;
81	int ret;
82
83	*context = NULL;
84
85	ret = fgetfilecon_raw(fd, &rcontext);
86
87	if (ret > 0) {
88		ret = selinux_raw_to_trans_context(rcontext, context);
89		freecon(rcontext);
90	}
91
92	if (ret >= 0 && *context)
93		return strlen(*context) + 1;
94
95	return ret;
96}
97