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 0 : 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 0 : entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
39 0 : 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 0 : if (acl_get_tag_type(ace, &tag) < 0)
46 : return true;
47 : /*
48 : * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ
49 : * or ACL_OTHER breaks the spell.
50 : */
51 0 : if(tag!=ACL_USER_OBJ
52 0 : && tag!=ACL_GROUP_OBJ
53 0 : && tag!=ACL_OTHER)
54 : return 0;
55 0 : entry_available=acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
56 : }
57 : #endif
58 : return 1;
59 : }
60 :
61 0 : static acl_t acl_contains_something(const char *path, int acl_type)
62 : {
63 0 : acl_t acl=NULL;
64 0 : if(!(acl=acl_get_file(path, acl_type))) return NULL;
65 0 : if(!acl_is_trivial(acl)) return acl;
66 0 : acl_free(acl);
67 0 : return NULL;
68 : }
69 :
70 0 : int has_acl(const char *path, enum cmd cmd)
71 : {
72 0 : acl_t acl=NULL;
73 0 : if(!(acl=acl_contains_something(path, ACL_TYPE_ACCESS))
74 0 : || (cmd==CMD_DIRECTORY
75 0 : && !(acl=acl_contains_something(path, ACL_TYPE_DEFAULT))))
76 : return 0;
77 0 : acl_free(acl);
78 0 : return 1;
79 : }
80 :
81 0 : static int get_acl_string(struct asfd *asfd, acl_t acl, char **acltext,
82 : size_t *alen, const char *path, char type, struct cntr *cntr)
83 : {
84 0 : int ret=0;
85 0 : char pre[10]="";
86 0 : char *tmp=NULL;
87 0 : ssize_t tlen=0;
88 0 : char *ourtext=NULL;
89 0 : ssize_t maxlen=0xFFFFFFFF/2;
90 :
91 0 : if(!(tmp=acl_to_text(acl, NULL)))
92 : {
93 0 : logw(asfd, cntr, "could not get ACL text of '%s'\n", path);
94 0 : goto end; // carry on
95 : }
96 :
97 0 : tlen=strlen(tmp);
98 :
99 0 : if(tlen>maxlen)
100 : {
101 0 : logw(asfd, cntr, "ACL of '%s' too long: %zd\n", path, tlen);
102 0 : goto end; // carry on
103 : }
104 :
105 0 : snprintf(pre, sizeof(pre), "%c%08X", type, (unsigned int)tlen);
106 0 : if(!(ourtext=prepend(pre, tmp))
107 0 : || !(*acltext=prepend_len(*acltext,
108 0 : *alen, ourtext, tlen+9, "", 0, alen)))
109 0 : ret=-1;
110 : end:
111 0 : free_w(&tmp);
112 0 : free_w(&ourtext);
113 0 : return ret;
114 : }
115 :
116 0 : int get_acl(struct asfd *asfd, struct sbuf *sb,
117 : char **acltext, size_t *alen, struct cntr *cntr)
118 : {
119 0 : acl_t acl=NULL;
120 0 : const char *path=sb->path.buf;
121 :
122 0 : if((acl=acl_contains_something(path, ACL_TYPE_ACCESS)))
123 : {
124 0 : if(get_acl_string(asfd, acl,
125 0 : acltext, alen, path, META_ACCESS_ACL, cntr))
126 : {
127 0 : acl_free(acl);
128 0 : return -1;
129 : }
130 0 : acl_free(acl);
131 : }
132 :
133 0 : if(S_ISDIR(sb->statp.st_mode))
134 : {
135 0 : if((acl=acl_contains_something(path, ACL_TYPE_DEFAULT)))
136 : {
137 0 : if(get_acl_string(asfd, acl,
138 0 : acltext, alen, path, META_DEFAULT_ACL, cntr))
139 : {
140 0 : acl_free(acl);
141 0 : return -1;
142 : }
143 0 : acl_free(acl);
144 : }
145 : }
146 : return 0;
147 : }
148 :
149 0 : static int do_set_acl(struct asfd *asfd, const char *path,
150 : const char *acltext, size_t alen,
151 : int acltype, struct cntr *cntr)
152 : {
153 : acl_t acl;
154 0 : int ret=-1;
155 0 : if(!(acl=acl_from_text(acltext)))
156 : {
157 : logp("acl_from_text error on %s (%s): %s\n",
158 0 : path, acltext, strerror(errno));
159 : logw(asfd, cntr, "acl_from_text error on %s (%s): %s\n",
160 0 : path, acltext, strerror(errno));
161 : goto end;
162 : }
163 : //#ifndef HAVE_FREEBSD_OS // Bacula says that acl_valid fails on valid input
164 : // on freebsd. It works OK for me on FreeBSD 8.2.
165 0 : if(acl_valid(acl))
166 : {
167 0 : logp("acl_valid error on %s: %s", path, strerror(errno));
168 : logw(asfd, cntr, "acl_valid error on %s: %s\n",
169 0 : path, strerror(errno));
170 : goto end;
171 : }
172 : //#endif
173 0 : if(acl_set_file(path, acltype, acl))
174 : {
175 0 : logp("acl set error on %s: %s", path, strerror(errno));
176 : logw(asfd, cntr, "acl set error on %s: %s\n",
177 0 : path, strerror(errno));
178 : goto end;
179 : }
180 : ret=0;
181 : end:
182 0 : if(acl) acl_free(acl);
183 0 : return ret;
184 : }
185 :
186 0 : int set_acl(struct asfd *asfd, const char *path, struct sbuf *sb,
187 : const char *acltext, size_t alen, char metacmd, struct cntr *cntr)
188 : {
189 0 : switch(metacmd)
190 : {
191 : case META_ACCESS_ACL:
192 : return do_set_acl(asfd, path,
193 0 : acltext, alen, ACL_TYPE_ACCESS, cntr);
194 : case META_DEFAULT_ACL:
195 : return do_set_acl(asfd, path,
196 0 : acltext, alen, ACL_TYPE_DEFAULT, cntr);
197 : default:
198 0 : logp("unknown acl type: %c\n", metacmd);
199 0 : logw(asfd, cntr, "unknown acl type: %c\n", metacmd);
200 : break;
201 : }
202 0 : return -1;
203 : }
204 :
205 : #endif // LINUX | BSD
206 : #endif // HAVE_ACL
|