1 #include "../burp.h"
2 #include "../alloc.h"
3 #include "../cmd.h"
4 #include "../log.h"
5 #include "../prepend.h"
6 #include "../sbuf.h"
7 #include "acl.h"
8 #include "extrameta.h"
9 
10 #ifdef HAVE_ACL
11 #if defined(HAVE_LINUX_OS) || \
12     defined(HAVE_FREEBSD_OS) || \
13     defined(HAVE_NETBSD_OS)
14 #include "sys/acl.h"
15 
16 /* Linux can do shorter ACLs */
17 #if defined(HAVE_LINUX_OS)
18 #include <acl/libacl.h>
19 #define acl_to_text(acl,len)	    (acl_to_any_text((acl), NULL, ',', TEXT_ABBREVIATE|TEXT_NUMERIC_IDS))
20 #endif
21 
22 // section of acl_is_trivial copied from bacula
acl_is_trivial(acl_t acl)23 static int acl_is_trivial(acl_t acl)
24 {
25 #if defined(HAVE_LINUX_OS) \
26  || defined(HAVE_FREEBSD_OS) \
27  || defined(HAVE_NETBSD_OS)
28 	/*
29 	 * acl is trivial if it has only the following entries:
30 	 * "user::",
31 	 * "group::",
32 	 * "other::"
33 	 */
34 	acl_entry_t ace;
35 	acl_tag_t tag;
36 	int entry_available;
37 
38 	entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
39 	while(entry_available==1)
40 	{
41 		/*
42 		 * Get the tag type of this acl entry.
43 		 * If we fail to get the tagtype we call the acl non-trivial.
44 		 */
45 		if (acl_get_tag_type(ace, &tag) < 0)
46 			return 0;
47 		/*
48 		 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ
49 		 * or ACL_OTHER breaks the spell.
50 		 */
51 		if(tag!=ACL_USER_OBJ
52 		  && tag!=ACL_GROUP_OBJ
53 		  && tag!=ACL_OTHER)
54 			return 0;
55 		entry_available=acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
56 	}
57 #endif
58 	return 1;
59 }
60 
default_acl_contains_something(acl_t acl)61 static int default_acl_contains_something(acl_t acl)
62 {
63 	acl_entry_t ace;
64 	return acl_get_entry(acl, ACL_FIRST_ENTRY, &ace)==1;
65 }
66 
acl_contains_something(const char * path,int acl_type)67 static acl_t acl_contains_something(const char *path, int acl_type)
68 {
69 	acl_t acl=NULL;
70 	if(!(acl=acl_get_file(path, acl_type)))
71 		return NULL;
72 	switch(acl_type)
73 	{
74 		case ACL_TYPE_ACCESS:
75 			if(acl_is_trivial(acl))
76 				goto nothing;
77 			break;
78 		case ACL_TYPE_DEFAULT:
79 			if(!default_acl_contains_something(acl))
80 				goto nothing;
81 			break;
82 	}
83 	return acl;
84 nothing:
85 	acl_free(acl);
86 	return NULL;
87 }
88 
has_acl(const char * path,enum cmd cmd)89 int has_acl(const char *path, enum cmd cmd)
90 {
91 	acl_t acl=NULL;
92 	if((acl=acl_contains_something(path, ACL_TYPE_ACCESS)))
93 	{
94 		acl_free(acl);
95 		return 1;
96 	}
97 	if(cmd==CMD_DIRECTORY
98 	    && (acl=acl_contains_something(path, ACL_TYPE_DEFAULT)))
99 	{
100 		acl_free(acl);
101 		return 1;
102 	}
103 	return 0;
104 }
105 
get_acl_string(struct asfd * asfd,acl_t acl,char ** acltext,size_t * alen,const char * path,char type,struct cntr * cntr)106 static int get_acl_string(struct asfd *asfd, acl_t acl, char **acltext,
107 	size_t *alen, const char *path, char type, struct cntr *cntr)
108 {
109 	int ret=0;
110 	char pre[10]="";
111 	char *tmp=NULL;
112 	uint32_t tlen=0;
113 	char *ourtext=NULL;
114 	char *oldtext=*acltext;
115 	uint32_t maxlen=0xFFFFFFFF/2;
116 
117 	if(!(tmp=acl_to_text(acl, NULL)))
118 	{
119 		logw(asfd, cntr, "could not get ACL text of '%s'\n", path);
120 		goto end; // carry on
121 	}
122 
123 	tlen=(uint32_t)strlen(tmp);
124 
125 	if(tlen>maxlen)
126 	{
127 		logw(asfd, cntr, "ACL of '%s' too long: %d\n", path, tlen);
128 		goto end; // carry on
129 	}
130 
131 	snprintf(pre, sizeof(pre), "%c%08X", type, tlen);
132 	if(!(ourtext=prepend(pre, tmp))
133 	  || !(*acltext=prepend_len(oldtext,
134 		*alen, ourtext, tlen+9, "", 0, alen)))
135 			ret=-1;
136 	free_w(&oldtext);
137 end:
138 	if(tmp) acl_free(tmp);
139 	free_w(&ourtext);
140 	return ret;
141 }
142 
get_acl(struct asfd * asfd,const char * path,int isdir,char ** acltext,size_t * alen,struct cntr * cntr)143 int get_acl(struct asfd *asfd, const char *path, int isdir,
144 	char **acltext, size_t *alen, struct cntr *cntr)
145 {
146 	int ret=-1;
147 	acl_t acl=NULL;
148 
149 	if((acl=acl_contains_something(path, ACL_TYPE_ACCESS)))
150 	{
151 		if(get_acl_string(asfd, acl,
152 			acltext, alen, path, META_ACCESS_ACL, cntr))
153 				goto end;
154 	}
155 
156 	if(isdir)
157 	{
158 		if(acl) acl_free(acl);
159 		if((acl=acl_contains_something(path, ACL_TYPE_DEFAULT)))
160 		{
161 			if(get_acl_string(asfd, acl,
162 				acltext, alen, path, META_DEFAULT_ACL, cntr))
163 					goto end;
164 		}
165 	}
166 	ret=0;
167 end:
168 	if(acl) acl_free(acl);
169 	return ret;
170 }
171 
do_set_acl(struct asfd * asfd,const char * path,const char * acltext,int acltype,struct cntr * cntr)172 static int do_set_acl(struct asfd *asfd, const char *path,
173 	const char *acltext, int acltype, struct cntr *cntr)
174 {
175 	acl_t acl;
176 	int ret=-1;
177 	if(!(acl=acl_from_text(acltext)))
178 	{
179 		logp("acl_from_text error on %s (%s): %s\n",
180 			path, acltext, strerror(errno));
181 		logw(asfd, cntr, "acl_from_text error on %s (%s): %s\n",
182 			path, acltext, strerror(errno));
183 		goto end;
184 	}
185 	if(acl_valid(acl))
186 	{
187 		logp("acl_valid error on %s: %s", path, strerror(errno));
188 		logw(asfd, cntr, "acl_valid error on %s: %s\n",
189 			path, strerror(errno));
190 		goto end;
191 	}
192 	if(acl_set_file(path, acltype, acl))
193 	{
194 		logp("acl set error on %s: %s", path, strerror(errno));
195 		logw(asfd, cntr, "acl set error on %s: %s\n",
196 			path, strerror(errno));
197 		goto end;
198 	}
199 	ret=0;
200 end:
201 	if(acl) acl_free(acl);
202 	return ret;
203 }
204 
set_acl(struct asfd * asfd,const char * path,const char * acltext,char metacmd,struct cntr * cntr)205 int set_acl(struct asfd *asfd, const char *path,
206 	const char *acltext, char metacmd, struct cntr *cntr)
207 {
208 	switch(metacmd)
209 	{
210 		case META_ACCESS_ACL:
211 			return do_set_acl(asfd, path,
212 				acltext, ACL_TYPE_ACCESS, cntr);
213 		case META_DEFAULT_ACL:
214 			return do_set_acl(asfd, path,
215 				acltext, ACL_TYPE_DEFAULT, cntr);
216 		default:
217 			logp("unknown acl type: %c\n", metacmd);
218 			logw(asfd, cntr, "unknown acl type: %c\n", metacmd);
219 			return -1;
220 	}
221 }
222 
223 #endif
224 #endif
225