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