1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /**
20 * Major refactoring of ACL code written by:
21 *
22 * Radosław Korzeniewski, MMXVI
23 * radoslaw@korzeniewski.net, radekk@inteos.pl
24 * Inteos Sp. z o.o. http://www.inteos.pl/
25 *
26 */
27
28 #include "bacula.h"
29 #include "filed.h"
30 #include "bacl_solaris.h"
31
32 #if defined(HAVE_SUN_OS)
33
34 /* check if ACL support is enabled */
35 #if defined(HAVE_ACL)
36
37 /*
38 * Define the supported ACL streams for this OS
39 */
40 static const int os_acl_streams[] = {
41 STREAM_XACL_SOLARIS_POSIX,
42 STREAM_XACL_SOLARIS_NFS4,
43 0
44 };
45
46 static const int os_default_acl_streams[] = {
47 0
48 };
49
50 /*
51 * OS specific constructor
52 */
BACL_Solaris()53 BACL_Solaris::BACL_Solaris(){
54
55 set_acl_streams(os_acl_streams, os_default_acl_streams);
56 cache = NULL;
57 };
58
59 /*
60 * OS specific destructor
61 */
~BACL_Solaris()62 BACL_Solaris::~BACL_Solaris(){};
63
64 /*
65 * Checks if ACL's are available for a specified file
66 *
67 * in:
68 * jcr - Job Control Record
69 * name - specifies the system variable to be queried
70 * out:
71 * bRC_BACL_ok - check successful, lets setup bacltype variable
72 * bRC_BACL_error - in case of error
73 * bRC_BACL_skip - you should skip all other routine
74 */
check_bacltype(JCR * jcr,int name)75 bRC_BACL BACL_Solaris::check_bacltype (JCR *jcr, int name){
76
77 int rc = 0;
78
79 rc = pathconf(jcr->last_fname, name);
80 switch (rc){
81 case -1: {
82 /* some error check why */
83 berrno be;
84 if (errno == ENOENT){
85 /* file does not exist skip it */
86 return bRC_BACL_skip;
87 } else {
88 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
89 Dmsg2(100, "pathconf error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
90 return bRC_BACL_error;
91 }
92 }
93 case 0:
94 /* No support for ACLs */
95 clear_flag(BACL_FLAG_NATIVE);
96 set_content(NULL);
97 return bRC_BACL_skip;
98 default:
99 break;
100 }
101 return bRC_BACL_ok;
102 };
103
104 /*
105 * Perform OS specific ACL backup
106 *
107 * in/out - check API at bacl.h
108 */
os_backup_acl(JCR * jcr,FF_PKT * ff_pkt)109 bRC_BACL BACL_Solaris::os_backup_acl (JCR *jcr, FF_PKT *ff_pkt){
110
111 bRC_BACL rc;
112 int stream;
113
114 /*
115 * See if filesystem supports acls.
116 */
117 rc = check_bacltype(jcr, _PC_ACL_ENABLED);
118 switch (rc){
119 case bRC_BACL_ok:
120 break;
121 case bRC_BACL_skip:
122 return bRC_BACL_ok;
123 default:
124 /* errors */
125 return rc;
126 }
127
128 rc = os_get_acl(jcr, &stream);
129 switch (rc){
130 case bRC_BACL_ok:
131 if (get_content_len() > 0){
132 if (send_acl_stream(jcr, stream) == bRC_BACL_fatal){
133 return bRC_BACL_fatal;
134 }
135 }
136 break;
137 default:
138 return rc;
139 }
140
141 return bRC_BACL_ok;
142 };
143
144 /*
145 * Perform OS specific ACL restore
146 *
147 * in/out - check API at bacl.h
148 */
os_restore_acl(JCR * jcr,int stream,char * content,uint32_t length)149 bRC_BACL BACL_Solaris::os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length){
150
151 int aclrc = 0;
152
153 switch (stream){
154 case STREAM_UNIX_ACCESS_ACL:
155 case STREAM_XACL_SOLARIS_POSIX:
156 case STREAM_XACL_SOLARIS_NFS4:
157 aclrc = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
158 break;
159 default:
160 return bRC_BACL_error;
161 }
162
163 switch (aclrc){
164 case -1: {
165 berrno be;
166
167 switch (errno){
168 case ENOENT:
169 return bRC_BACL_ok;
170 default:
171 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
172 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
173 return bRC_BACL_error;
174 }
175 }
176 case 0:
177 clear_flag(BACL_FLAG_NATIVE);
178 Mmsg(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"), jcr->last_fname);
179 return bRC_BACL_error;
180 default:
181 break;
182 }
183
184 Dmsg2(400, "restore acl stream %i on file: %s\n", stream, jcr->last_fname);
185 switch (stream){
186 case STREAM_XACL_SOLARIS_POSIX:
187 if ((aclrc & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0){
188 Mmsg(jcr->errmsg, _("Trying to restore POSIX acl on file \"%s\" on filesystem without aclent acl support\n"), jcr->last_fname);
189 return bRC_BACL_error;
190 }
191 break;
192 case STREAM_XACL_SOLARIS_NFS4:
193 if ((aclrc & _ACL_ACE_ENABLED) == 0){
194 Mmsg(jcr->errmsg, _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without ace acl support\n"), jcr->last_fname);
195 return bRC_BACL_error;
196 }
197 break;
198 default:
199 break;
200 }
201
202 return os_set_acl(jcr, stream, content, length);
203 };
204
205 /*
206 * Low level OS specific runtime to get ACL data from file. The ACL data is set in internal content buffer
207 *
208 * in/out - check API at bacl.h
209 */
os_get_acl(JCR * jcr,int * stream)210 bRC_BACL BACL_Solaris::os_get_acl(JCR *jcr, int *stream){
211
212 int flags;
213 acl_t *aclp;
214 char *acl_text;
215 bRC_BACL rc = bRC_BACL_ok;
216
217 if (!stream){
218 return bRC_BACL_fatal;
219 }
220
221 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0){
222 /* we've got some error */
223 berrno be;
224 switch (errno){
225 case ENOENT:
226 /* file does not exist */
227 return bRC_BACL_ok;
228 default:
229 Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"), jcr->last_fname, acl_strerror(errno));
230 Dmsg2(100, "acl_get error file=%s ERR=%s\n", jcr->last_fname, acl_strerror(errno));
231 return bRC_BACL_error;
232 }
233 }
234
235 if (!aclp){
236 /*
237 * The ACLs simply reflect the (already known) standard permissions
238 * So we don't send an ACL stream to the SD.
239 */
240 set_content(NULL);
241 return bRC_BACL_ok;
242 }
243
244 #if defined(ACL_SID_FMT)
245 /* new format flag added in newer Solaris versions */
246 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
247 #else
248 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
249 #endif /* ACL_SID_FMT */
250
251 if ((acl_text = acl_totext(aclp, flags)) != NULL){
252 set_content(acl_text);
253 switch (acl_type(aclp)){
254 case ACLENT_T:
255 *stream = STREAM_XACL_SOLARIS_POSIX;
256 Dmsg1(500, "found acl SOLARIS_POSIX: %s\n", acl_text);
257 break;
258 case ACE_T:
259 *stream = STREAM_XACL_SOLARIS_NFS4;
260 Dmsg1(500, "found acl SOLARIS_NFS4: %s\n", acl_text);
261 break;
262 default:
263 rc = bRC_BACL_error;
264 break;
265 }
266 actuallyfree(acl_text);
267 acl_free(aclp);
268 }
269 return rc;
270 };
271
272 /*
273 * Low level OS specific runtime to set ACL data on file
274 *
275 * in/out - check API at bacl.h
276 */
os_set_acl(JCR * jcr,int stream,char * content,uint32_t length)277 bRC_BACL BACL_Solaris::os_set_acl(JCR *jcr, int stream, char *content, uint32_t length){
278
279 int rc;
280 acl_t *aclp;
281
282 if ((rc = acl_fromtext(content, &aclp)) != 0){
283 Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"), jcr->last_fname, acl_strerror(rc));
284 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, acl_strerror(rc));
285 return bRC_BACL_error;
286 }
287
288 switch (stream){
289 case STREAM_XACL_SOLARIS_POSIX:
290 if (acl_type(aclp) != ACLENT_T){
291 Mmsg(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"), jcr->last_fname);
292 return bRC_BACL_error;
293 }
294 break;
295 case STREAM_XACL_SOLARIS_NFS4:
296 if (acl_type(aclp) != ACE_T){
297 Mmsg(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"), jcr->last_fname);
298 return bRC_BACL_error;
299 }
300 break;
301 default:
302 break;
303 }
304
305 if ((rc = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK){
306 switch (errno){
307 case ENOENT:
308 acl_free(aclp);
309 return bRC_BACL_ok;
310 default:
311 Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"), jcr->last_fname, acl_strerror(rc));
312 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, acl_strerror(rc));
313 acl_free(aclp);
314 return bRC_BACL_error;
315 }
316 }
317
318 acl_free(aclp);
319 return bRC_BACL_ok;
320 };
321
322 #endif /* HAVE_ACL */
323
324 #endif /* HAVE_SUN_OS */
325