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