Line data Source code
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
23 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 23 : entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
39 99 : 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 61 : 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 61 : if(tag!=ACL_USER_OBJ
52 61 : && tag!=ACL_GROUP_OBJ
53 23 : && tag!=ACL_OTHER)
54 : return 0;
55 53 : entry_available=acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
56 : }
57 : #endif
58 : return 1;
59 : }
60 :
61 : static int default_acl_contains_something(acl_t acl)
62 : {
63 : acl_entry_t ace;
64 11 : return acl_get_entry(acl, ACL_FIRST_ENTRY, &ace)==1;
65 : }
66 :
67 34 : static acl_t acl_contains_something(const char *path, int acl_type)
68 : {
69 34 : acl_t acl=NULL;
70 34 : if(!(acl=acl_get_file(path, acl_type)))
71 : return NULL;
72 34 : switch(acl_type)
73 : {
74 : case ACL_TYPE_ACCESS:
75 23 : if(acl_is_trivial(acl))
76 : goto nothing;
77 : break;
78 : case ACL_TYPE_DEFAULT:
79 11 : if(!default_acl_contains_something(acl))
80 : goto nothing;
81 : break;
82 : }
83 12 : return acl;
84 : nothing:
85 22 : acl_free(acl);
86 22 : return NULL;
87 : }
88 :
89 13 : int has_acl(const char *path, enum cmd cmd)
90 : {
91 13 : acl_t acl=NULL;
92 13 : if((acl=acl_contains_something(path, ACL_TYPE_ACCESS)))
93 : {
94 3 : acl_free(acl);
95 3 : return 1;
96 : }
97 10 : if(cmd==CMD_DIRECTORY
98 5 : && (acl=acl_contains_something(path, ACL_TYPE_DEFAULT)))
99 : {
100 1 : acl_free(acl);
101 1 : return 1;
102 : }
103 : return 0;
104 : }
105 :
106 8 : 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 8 : int ret=0;
110 8 : char pre[10]="";
111 8 : char *tmp=NULL;
112 8 : ssize_t tlen=0;
113 8 : char *ourtext=NULL;
114 8 : char *oldtext=*acltext;
115 8 : ssize_t maxlen=0xFFFFFFFF/2;
116 :
117 8 : if(!(tmp=acl_to_text(acl, NULL)))
118 : {
119 0 : logw(asfd, cntr, "could not get ACL text of '%s'\n", path);
120 0 : goto end; // carry on
121 : }
122 :
123 8 : tlen=strlen(tmp);
124 :
125 8 : if(tlen>maxlen)
126 : {
127 0 : logw(asfd, cntr, "ACL of '%s' too long: %zd\n", path, tlen);
128 0 : goto end; // carry on
129 : }
130 :
131 8 : snprintf(pre, sizeof(pre), "%c%08X", type, (unsigned int)tlen);
132 8 : if(!(ourtext=prepend(pre, tmp))
133 8 : || !(*acltext=prepend_len(oldtext,
134 8 : *alen, ourtext, tlen+9, "", 0, alen)))
135 : ret=-1;
136 8 : free_w(&oldtext);
137 : end:
138 8 : if(tmp) acl_free(tmp);
139 8 : free_w(&ourtext);
140 8 : return ret;
141 : }
142 :
143 10 : int get_acl(struct asfd *asfd, const char *path, int isdir,
144 : char **acltext, size_t *alen, struct cntr *cntr)
145 : {
146 10 : int ret=-1;
147 10 : acl_t acl=NULL;
148 :
149 10 : if((acl=acl_contains_something(path, ACL_TYPE_ACCESS)))
150 : {
151 5 : if(get_acl_string(asfd, acl,
152 : acltext, alen, path, META_ACCESS_ACL, cntr))
153 : goto end;
154 : }
155 :
156 10 : if(isdir)
157 : {
158 6 : if(acl) acl_free(acl);
159 6 : if((acl=acl_contains_something(path, ACL_TYPE_DEFAULT)))
160 : {
161 3 : 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 10 : if(acl) acl_free(acl);
169 10 : return ret;
170 : }
171 :
172 10 : 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 10 : int ret=-1;
177 10 : if(!(acl=acl_from_text(acltext)))
178 : {
179 1 : logp("acl_from_text error on %s (%s): %s\n",
180 1 : path, acltext, strerror(errno));
181 1 : logw(asfd, cntr, "acl_from_text error on %s (%s): %s\n",
182 : path, acltext, strerror(errno));
183 1 : goto end;
184 : }
185 9 : if(acl_valid(acl))
186 : {
187 0 : logp("acl_valid error on %s: %s", path, strerror(errno));
188 0 : logw(asfd, cntr, "acl_valid error on %s: %s\n",
189 : path, strerror(errno));
190 0 : goto end;
191 : }
192 9 : if(acl_set_file(path, acltype, acl))
193 : {
194 1 : logp("acl set error on %s: %s", path, strerror(errno));
195 1 : logw(asfd, cntr, "acl set error on %s: %s\n",
196 : path, strerror(errno));
197 1 : goto end;
198 : }
199 : ret=0;
200 : end:
201 10 : if(acl) acl_free(acl);
202 10 : return ret;
203 : }
204 :
205 11 : int set_acl(struct asfd *asfd, const char *path,
206 : const char *acltext, char metacmd, struct cntr *cntr)
207 : {
208 11 : switch(metacmd)
209 : {
210 : case META_ACCESS_ACL:
211 5 : return do_set_acl(asfd, path,
212 : acltext, ACL_TYPE_ACCESS, cntr);
213 : case META_DEFAULT_ACL:
214 5 : return do_set_acl(asfd, path,
215 : acltext, ACL_TYPE_DEFAULT, cntr);
216 : default:
217 1 : logp("unknown acl type: %c\n", metacmd);
218 1 : logw(asfd, cntr, "unknown acl type: %c\n", metacmd);
219 1 : return -1;
220 : }
221 : }
222 :
223 : #endif
224 : #endif
|