/src/samba/source3/modules/vfs_acl_common.c
Line | Count | Source |
1 | | /* |
2 | | * Store Windows ACLs in data store - common functions. |
3 | | * #included into modules/vfs_acl_xattr.c and modules/vfs_acl_tdb.c |
4 | | * |
5 | | * Copyright (C) Volker Lendecke, 2008 |
6 | | * Copyright (C) Jeremy Allison, 2009 |
7 | | * Copyright (C) Ralph Böhme, 2016 |
8 | | * |
9 | | * This program is free software; you can redistribute it and/or modify |
10 | | * it under the terms of the GNU General Public License as published by |
11 | | * the Free Software Foundation; either version 3 of the License, or |
12 | | * (at your option) any later version. |
13 | | * |
14 | | * This program is distributed in the hope that it will be useful, |
15 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | * GNU General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU General Public License |
20 | | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
21 | | */ |
22 | | |
23 | | #include "includes.h" |
24 | | #include "vfs_acl_common.h" |
25 | | #include "smbd/smbd.h" |
26 | | #include "system/filesys.h" |
27 | | #include "librpc/gen_ndr/ndr_xattr.h" |
28 | | #include "../libcli/security/security.h" |
29 | | #include "../librpc/gen_ndr/ndr_security.h" |
30 | | #include "../lib/util/bitmap.h" |
31 | | #include "passdb/lookup_sid.h" |
32 | | |
33 | | #include <gnutls/gnutls.h> |
34 | | #include <gnutls/crypto.h> |
35 | | |
36 | | static NTSTATUS create_acl_blob(const struct security_descriptor *psd, |
37 | | DATA_BLOB *pblob, |
38 | | uint16_t hash_type, |
39 | | uint8_t hash[XATTR_SD_HASH_SIZE]); |
40 | | |
41 | | #define HASH_SECURITY_INFO (SECINFO_OWNER | \ |
42 | | SECINFO_GROUP | \ |
43 | | SECINFO_DACL | \ |
44 | | SECINFO_SACL) |
45 | | |
46 | | bool init_acl_common_config(vfs_handle_struct *handle, |
47 | | const char *module_name) |
48 | 0 | { |
49 | 0 | struct acl_common_config *config = NULL; |
50 | 0 | const struct enum_list *default_acl_style_list = NULL; |
51 | |
|
52 | 0 | default_acl_style_list = get_default_acl_style_list(); |
53 | |
|
54 | 0 | config = talloc_zero(handle->conn, struct acl_common_config); |
55 | 0 | if (config == NULL) { |
56 | 0 | DBG_ERR("talloc_zero() failed\n"); |
57 | 0 | errno = ENOMEM; |
58 | 0 | return false; |
59 | 0 | } |
60 | | |
61 | 0 | config->ignore_system_acls = lp_parm_bool(SNUM(handle->conn), |
62 | 0 | module_name, |
63 | 0 | "ignore system acls", |
64 | 0 | false); |
65 | 0 | config->default_acl_style = lp_parm_enum(SNUM(handle->conn), |
66 | 0 | module_name, |
67 | 0 | "default acl style", |
68 | 0 | default_acl_style_list, |
69 | 0 | DEFAULT_ACL_POSIX); |
70 | |
|
71 | 0 | SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, |
72 | 0 | struct acl_common_config, |
73 | 0 | return false); |
74 | |
|
75 | 0 | return true; |
76 | 0 | } |
77 | | |
78 | | |
79 | | /******************************************************************* |
80 | | Hash a security descriptor. |
81 | | *******************************************************************/ |
82 | | |
83 | | static NTSTATUS hash_blob_sha256(DATA_BLOB blob, |
84 | | uint8_t *hash) |
85 | 0 | { |
86 | 0 | int rc; |
87 | |
|
88 | 0 | ZERO_ARRAY_LEN(hash, XATTR_SD_HASH_SIZE); |
89 | |
|
90 | 0 | rc = gnutls_hash_fast(GNUTLS_DIG_SHA256, |
91 | 0 | blob.data, |
92 | 0 | blob.length, |
93 | 0 | hash); |
94 | 0 | if (rc < 0) { |
95 | 0 | return NT_STATUS_INTERNAL_ERROR; |
96 | 0 | } |
97 | | |
98 | 0 | return NT_STATUS_OK; |
99 | 0 | } |
100 | | |
101 | | /******************************************************************* |
102 | | Hash a security descriptor. |
103 | | *******************************************************************/ |
104 | | |
105 | | static NTSTATUS hash_sd_sha256(struct security_descriptor *psd, |
106 | | uint8_t *hash) |
107 | 0 | { |
108 | 0 | DATA_BLOB blob; |
109 | 0 | NTSTATUS status; |
110 | |
|
111 | 0 | memset(hash, '\0', XATTR_SD_HASH_SIZE); |
112 | 0 | status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash); |
113 | 0 | if (!NT_STATUS_IS_OK(status)) { |
114 | 0 | return status; |
115 | 0 | } |
116 | 0 | return hash_blob_sha256(blob, hash); |
117 | 0 | } |
118 | | |
119 | | /******************************************************************* |
120 | | Parse out a struct security_descriptor from a DATA_BLOB. |
121 | | *******************************************************************/ |
122 | | |
123 | | static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob, |
124 | | TALLOC_CTX *mem_ctx, |
125 | | struct security_descriptor **ppdesc, |
126 | | uint16_t *p_hash_type, |
127 | | uint16_t *p_version, |
128 | | uint8_t hash[XATTR_SD_HASH_SIZE], |
129 | | uint8_t sys_acl_hash[XATTR_SD_HASH_SIZE]) |
130 | 0 | { |
131 | 0 | struct xattr_NTACL xacl; |
132 | 0 | enum ndr_err_code ndr_err; |
133 | 0 | size_t sd_size; |
134 | 0 | TALLOC_CTX *frame = talloc_stackframe(); |
135 | |
|
136 | 0 | ndr_err = ndr_pull_struct_blob(pblob, frame, &xacl, |
137 | 0 | (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL); |
138 | |
|
139 | 0 | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
140 | 0 | DBG_INFO("ndr_pull_xattr_NTACL failed: %s\n", |
141 | 0 | ndr_errstr(ndr_err)); |
142 | 0 | TALLOC_FREE(frame); |
143 | 0 | return ndr_map_error2ntstatus(ndr_err); |
144 | 0 | } |
145 | | |
146 | 0 | *p_version = xacl.version; |
147 | |
|
148 | 0 | switch (xacl.version) { |
149 | 0 | case 1: |
150 | 0 | *ppdesc = make_sec_desc(mem_ctx, SD_REVISION, |
151 | 0 | xacl.info.sd->type | SEC_DESC_SELF_RELATIVE, |
152 | 0 | xacl.info.sd->owner_sid, |
153 | 0 | xacl.info.sd->group_sid, |
154 | 0 | xacl.info.sd->sacl, |
155 | 0 | xacl.info.sd->dacl, |
156 | 0 | &sd_size); |
157 | | /* No hash - null out. */ |
158 | 0 | *p_hash_type = XATTR_SD_HASH_TYPE_NONE; |
159 | 0 | memset(hash, '\0', XATTR_SD_HASH_SIZE); |
160 | 0 | break; |
161 | 0 | case 2: |
162 | 0 | *ppdesc = make_sec_desc(mem_ctx, SD_REVISION, |
163 | 0 | xacl.info.sd_hs2->sd->type | SEC_DESC_SELF_RELATIVE, |
164 | 0 | xacl.info.sd_hs2->sd->owner_sid, |
165 | 0 | xacl.info.sd_hs2->sd->group_sid, |
166 | 0 | xacl.info.sd_hs2->sd->sacl, |
167 | 0 | xacl.info.sd_hs2->sd->dacl, |
168 | 0 | &sd_size); |
169 | | /* No hash - null out. */ |
170 | 0 | *p_hash_type = XATTR_SD_HASH_TYPE_NONE; |
171 | 0 | memset(hash, '\0', XATTR_SD_HASH_SIZE); |
172 | 0 | break; |
173 | 0 | case 3: |
174 | 0 | *ppdesc = make_sec_desc(mem_ctx, SD_REVISION, |
175 | 0 | xacl.info.sd_hs3->sd->type | SEC_DESC_SELF_RELATIVE, |
176 | 0 | xacl.info.sd_hs3->sd->owner_sid, |
177 | 0 | xacl.info.sd_hs3->sd->group_sid, |
178 | 0 | xacl.info.sd_hs3->sd->sacl, |
179 | 0 | xacl.info.sd_hs3->sd->dacl, |
180 | 0 | &sd_size); |
181 | 0 | *p_hash_type = xacl.info.sd_hs3->hash_type; |
182 | | /* Current version 3 (if no sys acl hash available). */ |
183 | 0 | memcpy(hash, xacl.info.sd_hs3->hash, XATTR_SD_HASH_SIZE); |
184 | 0 | break; |
185 | 0 | case 4: |
186 | 0 | *ppdesc = make_sec_desc(mem_ctx, SD_REVISION, |
187 | 0 | xacl.info.sd_hs4->sd->type | SEC_DESC_SELF_RELATIVE, |
188 | 0 | xacl.info.sd_hs4->sd->owner_sid, |
189 | 0 | xacl.info.sd_hs4->sd->group_sid, |
190 | 0 | xacl.info.sd_hs4->sd->sacl, |
191 | 0 | xacl.info.sd_hs4->sd->dacl, |
192 | 0 | &sd_size); |
193 | 0 | *p_hash_type = xacl.info.sd_hs4->hash_type; |
194 | | /* Current version 4. */ |
195 | 0 | memcpy(hash, xacl.info.sd_hs4->hash, XATTR_SD_HASH_SIZE); |
196 | 0 | memcpy(sys_acl_hash, xacl.info.sd_hs4->sys_acl_hash, XATTR_SD_HASH_SIZE); |
197 | 0 | break; |
198 | 0 | default: |
199 | 0 | TALLOC_FREE(frame); |
200 | 0 | return NT_STATUS_REVISION_MISMATCH; |
201 | 0 | } |
202 | | |
203 | 0 | TALLOC_FREE(frame); |
204 | |
|
205 | 0 | return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY; |
206 | 0 | } |
207 | | |
208 | | /******************************************************************* |
209 | | Create a DATA_BLOB from a hash of the security descriptor storead at |
210 | | the system layer and the NT ACL we wish to preserve |
211 | | *******************************************************************/ |
212 | | |
213 | | static NTSTATUS create_acl_blob(const struct security_descriptor *psd, |
214 | | DATA_BLOB *pblob, |
215 | | uint16_t hash_type, |
216 | | uint8_t hash[XATTR_SD_HASH_SIZE]) |
217 | 0 | { |
218 | 0 | struct xattr_NTACL xacl; |
219 | 0 | struct security_descriptor_hash_v3 sd_hs3; |
220 | 0 | enum ndr_err_code ndr_err; |
221 | 0 | TALLOC_CTX *ctx = talloc_tos(); |
222 | |
|
223 | 0 | ZERO_STRUCT(xacl); |
224 | 0 | ZERO_STRUCT(sd_hs3); |
225 | |
|
226 | 0 | xacl.version = 3; |
227 | 0 | xacl.info.sd_hs3 = &sd_hs3; |
228 | 0 | xacl.info.sd_hs3->sd = discard_const_p(struct security_descriptor, psd); |
229 | 0 | xacl.info.sd_hs3->hash_type = hash_type; |
230 | 0 | memcpy(&xacl.info.sd_hs3->hash[0], hash, XATTR_SD_HASH_SIZE); |
231 | |
|
232 | 0 | ndr_err = ndr_push_struct_blob( |
233 | 0 | pblob, ctx, &xacl, |
234 | 0 | (ndr_push_flags_fn_t)ndr_push_xattr_NTACL); |
235 | |
|
236 | 0 | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
237 | 0 | DBG_INFO("ndr_push_xattr_NTACL failed: %s\n", |
238 | 0 | ndr_errstr(ndr_err)); |
239 | 0 | return ndr_map_error2ntstatus(ndr_err); |
240 | 0 | } |
241 | | |
242 | 0 | return NT_STATUS_OK; |
243 | 0 | } |
244 | | |
245 | | /******************************************************************* |
246 | | Create a DATA_BLOB from a hash of the security descriptors |
247 | | (system and NT) stored at the system layer and the NT ACL we wish |
248 | | to preserve. |
249 | | *******************************************************************/ |
250 | | |
251 | | static NTSTATUS create_sys_acl_blob(const struct security_descriptor *psd, |
252 | | DATA_BLOB *pblob, |
253 | | uint16_t hash_type, |
254 | | uint8_t hash[XATTR_SD_HASH_SIZE], |
255 | | const char *description, |
256 | | uint8_t sys_acl_hash[XATTR_SD_HASH_SIZE]) |
257 | 0 | { |
258 | 0 | struct xattr_NTACL xacl; |
259 | 0 | struct security_descriptor_hash_v4 sd_hs4; |
260 | 0 | enum ndr_err_code ndr_err; |
261 | 0 | TALLOC_CTX *ctx = talloc_tos(); |
262 | |
|
263 | 0 | ZERO_STRUCT(xacl); |
264 | 0 | ZERO_STRUCT(sd_hs4); |
265 | |
|
266 | 0 | xacl.version = 4; |
267 | 0 | xacl.info.sd_hs4 = &sd_hs4; |
268 | 0 | xacl.info.sd_hs4->sd = discard_const_p(struct security_descriptor, psd); |
269 | 0 | xacl.info.sd_hs4->hash_type = hash_type; |
270 | 0 | memcpy(&xacl.info.sd_hs4->hash[0], hash, XATTR_SD_HASH_SIZE); |
271 | 0 | xacl.info.sd_hs4->description = description; |
272 | 0 | memcpy(&xacl.info.sd_hs4->sys_acl_hash[0], sys_acl_hash, XATTR_SD_HASH_SIZE); |
273 | |
|
274 | 0 | ndr_err = ndr_push_struct_blob( |
275 | 0 | pblob, ctx, &xacl, |
276 | 0 | (ndr_push_flags_fn_t)ndr_push_xattr_NTACL); |
277 | |
|
278 | 0 | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
279 | 0 | DBG_INFO("ndr_push_xattr_NTACL failed: %s\n", |
280 | 0 | ndr_errstr(ndr_err)); |
281 | 0 | return ndr_map_error2ntstatus(ndr_err); |
282 | 0 | } |
283 | | |
284 | 0 | return NT_STATUS_OK; |
285 | 0 | } |
286 | | |
287 | | /******************************************************************* |
288 | | Add in 3 inheritable components for a non-inheritable directory ACL. |
289 | | CREATOR_OWNER/CREATOR_GROUP/WORLD. |
290 | | *******************************************************************/ |
291 | | |
292 | | static NTSTATUS add_directory_inheritable_components(vfs_handle_struct *handle, |
293 | | const char *name, |
294 | | SMB_STRUCT_STAT *psbuf, |
295 | | struct security_descriptor *psd) |
296 | 0 | { |
297 | 0 | struct connection_struct *conn = handle->conn; |
298 | 0 | int num_aces = (psd->dacl ? psd->dacl->num_aces : 0); |
299 | 0 | struct smb_filename smb_fname; |
300 | 0 | enum security_ace_type acltype; |
301 | 0 | uint32_t access_mask; |
302 | 0 | mode_t dir_mode; |
303 | 0 | mode_t file_mode; |
304 | 0 | mode_t mode; |
305 | 0 | struct security_ace *new_ace_list; |
306 | |
|
307 | 0 | if (psd->dacl) { |
308 | 0 | new_ace_list = talloc_zero_array(psd->dacl, |
309 | 0 | struct security_ace, |
310 | 0 | num_aces + 3); |
311 | 0 | } else { |
312 | | /* |
313 | | * make_sec_acl() at the bottom of this function |
314 | | * duplicates new_ace_list |
315 | | */ |
316 | 0 | new_ace_list = talloc_zero_array(talloc_tos(), |
317 | 0 | struct security_ace, |
318 | 0 | num_aces + 3); |
319 | 0 | } |
320 | |
|
321 | 0 | if (new_ace_list == NULL) { |
322 | 0 | return NT_STATUS_NO_MEMORY; |
323 | 0 | } |
324 | | |
325 | | /* Fake a quick smb_filename. */ |
326 | 0 | ZERO_STRUCT(smb_fname); |
327 | 0 | smb_fname.st = *psbuf; |
328 | 0 | smb_fname.base_name = discard_const_p(char, name); |
329 | |
|
330 | 0 | dir_mode = unix_mode(conn, |
331 | 0 | FILE_ATTRIBUTE_DIRECTORY, &smb_fname, NULL); |
332 | 0 | file_mode = unix_mode(conn, |
333 | 0 | FILE_ATTRIBUTE_ARCHIVE, &smb_fname, NULL); |
334 | |
|
335 | 0 | mode = dir_mode | file_mode; |
336 | |
|
337 | 0 | DBG_DEBUG("directory %s, mode = 0%o\n", name, (unsigned int)mode); |
338 | |
|
339 | 0 | if (num_aces) { |
340 | 0 | memcpy(new_ace_list, psd->dacl->aces, |
341 | 0 | num_aces * sizeof(struct security_ace)); |
342 | 0 | } |
343 | 0 | access_mask = map_canon_ace_perms(SNUM(conn), &acltype, |
344 | 0 | mode & 0700, false); |
345 | |
|
346 | 0 | init_sec_ace(&new_ace_list[num_aces], |
347 | 0 | &global_sid_Creator_Owner, |
348 | 0 | acltype, |
349 | 0 | access_mask, |
350 | 0 | SEC_ACE_FLAG_CONTAINER_INHERIT| |
351 | 0 | SEC_ACE_FLAG_OBJECT_INHERIT| |
352 | 0 | SEC_ACE_FLAG_INHERIT_ONLY); |
353 | 0 | access_mask = map_canon_ace_perms(SNUM(conn), &acltype, |
354 | 0 | (mode << 3) & 0700, false); |
355 | 0 | init_sec_ace(&new_ace_list[num_aces+1], |
356 | 0 | &global_sid_Creator_Group, |
357 | 0 | acltype, |
358 | 0 | access_mask, |
359 | 0 | SEC_ACE_FLAG_CONTAINER_INHERIT| |
360 | 0 | SEC_ACE_FLAG_OBJECT_INHERIT| |
361 | 0 | SEC_ACE_FLAG_INHERIT_ONLY); |
362 | 0 | access_mask = map_canon_ace_perms(SNUM(conn), &acltype, |
363 | 0 | (mode << 6) & 0700, false); |
364 | 0 | init_sec_ace(&new_ace_list[num_aces+2], |
365 | 0 | &global_sid_World, |
366 | 0 | acltype, |
367 | 0 | access_mask, |
368 | 0 | SEC_ACE_FLAG_CONTAINER_INHERIT| |
369 | 0 | SEC_ACE_FLAG_OBJECT_INHERIT| |
370 | 0 | SEC_ACE_FLAG_INHERIT_ONLY); |
371 | 0 | if (psd->dacl) { |
372 | 0 | psd->dacl->aces = new_ace_list; |
373 | 0 | psd->dacl->num_aces += 3; |
374 | 0 | psd->dacl->size += new_ace_list[num_aces].size + |
375 | 0 | new_ace_list[num_aces+1].size + |
376 | 0 | new_ace_list[num_aces+2].size; |
377 | 0 | } else { |
378 | 0 | psd->dacl = make_sec_acl(psd, |
379 | 0 | NT4_ACL_REVISION, |
380 | 0 | 3, |
381 | 0 | new_ace_list); |
382 | 0 | if (psd->dacl == NULL) { |
383 | 0 | return NT_STATUS_NO_MEMORY; |
384 | 0 | } |
385 | 0 | } |
386 | 0 | return NT_STATUS_OK; |
387 | 0 | } |
388 | | |
389 | | /** |
390 | | * Validate an ACL blob |
391 | | * |
392 | | * This validates an ACL blob against the underlying filesystem ACL. If this |
393 | | * function returns NT_STATUS_OK ppsd can be |
394 | | * |
395 | | * 1. the ACL from the blob (psd_from_fs=false), or |
396 | | * 2. the ACL from the fs (psd_from_fs=true), or |
397 | | * 3. NULL (!) |
398 | | * |
399 | | * If the return value is anything else then NT_STATUS_OK, ppsd is set to NULL |
400 | | * and psd_from_fs set to false. |
401 | | * |
402 | | * Returning the underlying filesystem ACL in case no. 2 is really just an |
403 | | * optimisation, because some validations have to fetch the filesystem ACL as |
404 | | * part of the validation, so we already have it available and callers might |
405 | | * need it as well. |
406 | | **/ |
407 | | static NTSTATUS validate_nt_acl_blob(TALLOC_CTX *mem_ctx, |
408 | | vfs_handle_struct *handle, |
409 | | struct files_struct *fsp, |
410 | | const struct smb_filename *smb_fname, |
411 | | const DATA_BLOB *blob, |
412 | | struct security_descriptor **ppsd, |
413 | | bool *psd_is_from_fs) |
414 | 0 | { |
415 | 0 | NTSTATUS status; |
416 | 0 | uint16_t hash_type = XATTR_SD_HASH_TYPE_NONE; |
417 | 0 | uint16_t xattr_version = 0; |
418 | 0 | uint8_t hash[XATTR_SD_HASH_SIZE]; |
419 | 0 | uint8_t sys_acl_hash[XATTR_SD_HASH_SIZE]; |
420 | 0 | uint8_t hash_tmp[XATTR_SD_HASH_SIZE]; |
421 | 0 | uint8_t sys_acl_hash_tmp[XATTR_SD_HASH_SIZE]; |
422 | 0 | struct security_descriptor *psd = NULL; |
423 | 0 | struct security_descriptor *psd_blob = NULL; |
424 | 0 | struct security_descriptor *psd_fs = NULL; |
425 | 0 | char *sys_acl_blob_description = NULL; |
426 | 0 | DATA_BLOB sys_acl_blob = { 0 }; |
427 | 0 | struct acl_common_config *config = NULL; |
428 | |
|
429 | 0 | *ppsd = NULL; |
430 | 0 | *psd_is_from_fs = false; |
431 | |
|
432 | 0 | SMB_VFS_HANDLE_GET_DATA(handle, config, |
433 | 0 | struct acl_common_config, |
434 | 0 | return NT_STATUS_UNSUCCESSFUL); |
435 | |
|
436 | 0 | status = parse_acl_blob(blob, |
437 | 0 | mem_ctx, |
438 | 0 | &psd_blob, |
439 | 0 | &hash_type, |
440 | 0 | &xattr_version, |
441 | 0 | &hash[0], |
442 | 0 | &sys_acl_hash[0]); |
443 | 0 | if (!NT_STATUS_IS_OK(status)) { |
444 | 0 | DBG_DEBUG("parse_acl_blob returned %s\n", nt_errstr(status)); |
445 | 0 | goto fail; |
446 | 0 | } |
447 | | |
448 | | /* determine which type of xattr we got */ |
449 | 0 | switch (xattr_version) { |
450 | 0 | case 1: |
451 | 0 | case 2: |
452 | | /* These xattr types are unilateral, they do not |
453 | | * require confirmation of the hash. In particular, |
454 | | * the NTVFS file server uses version 1, but |
455 | | * 'samba-tool ntacl' can set these as well */ |
456 | 0 | *ppsd = psd_blob; |
457 | 0 | return NT_STATUS_OK; |
458 | 0 | case 3: |
459 | 0 | case 4: |
460 | 0 | if (config->ignore_system_acls) { |
461 | 0 | *ppsd = psd_blob; |
462 | 0 | return NT_STATUS_OK; |
463 | 0 | } |
464 | | |
465 | 0 | break; |
466 | 0 | default: |
467 | 0 | DBG_DEBUG("ACL blob revision mismatch (%u) for file %s\n", |
468 | 0 | (unsigned int)hash_type, smb_fname->base_name); |
469 | 0 | TALLOC_FREE(psd_blob); |
470 | 0 | return NT_STATUS_OK; |
471 | 0 | } |
472 | | |
473 | | /* determine which type of xattr we got */ |
474 | 0 | if (hash_type != XATTR_SD_HASH_TYPE_SHA256) { |
475 | 0 | DBG_DEBUG("ACL blob hash type (%u) unexpected for file %s\n", |
476 | 0 | (unsigned int)hash_type, smb_fname->base_name); |
477 | 0 | TALLOC_FREE(psd_blob); |
478 | 0 | return NT_STATUS_OK; |
479 | 0 | } |
480 | | |
481 | | /* determine which type of xattr we got */ |
482 | 0 | switch (xattr_version) { |
483 | 0 | case 4: |
484 | 0 | { |
485 | 0 | int ret; |
486 | | /* Get the full underlying sd, then hash. */ |
487 | 0 | ret = SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle, |
488 | 0 | fsp, |
489 | 0 | mem_ctx, |
490 | 0 | &sys_acl_blob_description, |
491 | 0 | &sys_acl_blob); |
492 | | /* If we fail to get the ACL blob (for some reason) then this |
493 | | * is not fatal, we just work based on the NT ACL only */ |
494 | 0 | if (ret == 0) { |
495 | 0 | status = hash_blob_sha256(sys_acl_blob, sys_acl_hash_tmp); |
496 | 0 | if (!NT_STATUS_IS_OK(status)) { |
497 | 0 | goto fail; |
498 | 0 | } |
499 | | |
500 | 0 | TALLOC_FREE(sys_acl_blob_description); |
501 | 0 | TALLOC_FREE(sys_acl_blob.data); |
502 | |
|
503 | 0 | if (memcmp(&sys_acl_hash[0], &sys_acl_hash_tmp[0], |
504 | 0 | XATTR_SD_HASH_SIZE) == 0) { |
505 | | /* Hash matches, return blob sd. */ |
506 | 0 | DBG_DEBUG("blob hash matches for file %s\n", |
507 | 0 | smb_fname->base_name); |
508 | 0 | *ppsd = psd_blob; |
509 | 0 | return NT_STATUS_OK; |
510 | 0 | } |
511 | 0 | } |
512 | | |
513 | | /* Otherwise, fall though and see if the NT ACL hash matches */ |
514 | 0 | FALL_THROUGH; |
515 | 0 | } |
516 | 0 | case 3: |
517 | | /* Get the full underlying sd for the hash |
518 | | or to return as backup. */ |
519 | 0 | status = SMB_VFS_NEXT_FGET_NT_ACL(handle, |
520 | 0 | fsp, |
521 | 0 | HASH_SECURITY_INFO, |
522 | 0 | mem_ctx, |
523 | 0 | &psd_fs); |
524 | 0 | if (!NT_STATUS_IS_OK(status)) { |
525 | 0 | DBG_DEBUG("get_next_acl for file %s returned %s\n", |
526 | 0 | smb_fname->base_name, nt_errstr(status)); |
527 | 0 | goto fail; |
528 | 0 | } |
529 | | |
530 | 0 | status = hash_sd_sha256(psd_fs, hash_tmp); |
531 | 0 | if (!NT_STATUS_IS_OK(status)) { |
532 | 0 | TALLOC_FREE(psd_blob); |
533 | 0 | *ppsd = psd_fs; |
534 | 0 | *psd_is_from_fs = true; |
535 | 0 | return NT_STATUS_OK; |
536 | 0 | } |
537 | | |
538 | 0 | if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) { |
539 | | /* Hash matches, return blob sd. */ |
540 | 0 | DBG_DEBUG("blob hash matches for file %s\n", |
541 | 0 | smb_fname->base_name); |
542 | 0 | *ppsd = psd_blob; |
543 | 0 | return NT_STATUS_OK; |
544 | 0 | } |
545 | | |
546 | | /* Hash doesn't match, return underlying sd. */ |
547 | 0 | DBG_DEBUG("blob hash does not match for file %s - returning " |
548 | 0 | "file system SD mapping.\n", |
549 | 0 | smb_fname->base_name); |
550 | |
|
551 | 0 | if (DEBUGLEVEL >= 10) { |
552 | 0 | DBG_DEBUG("acl for blob hash for %s is:\n", |
553 | 0 | smb_fname->base_name); |
554 | 0 | NDR_PRINT_DEBUG(security_descriptor, psd_fs); |
555 | 0 | } |
556 | |
|
557 | 0 | TALLOC_FREE(psd_blob); |
558 | 0 | *ppsd = psd_fs; |
559 | 0 | *psd_is_from_fs = true; |
560 | 0 | } |
561 | | |
562 | 0 | return NT_STATUS_OK; |
563 | | |
564 | 0 | fail: |
565 | 0 | TALLOC_FREE(psd); |
566 | 0 | TALLOC_FREE(psd_blob); |
567 | 0 | TALLOC_FREE(psd_fs); |
568 | 0 | TALLOC_FREE(sys_acl_blob_description); |
569 | 0 | TALLOC_FREE(sys_acl_blob.data); |
570 | 0 | return status; |
571 | 0 | } |
572 | | |
573 | | /******************************************************************* |
574 | | Pull a DATA_BLOB from an xattr given an fsp. |
575 | | If the hash doesn't match, or doesn't exist - return the underlying |
576 | | filesystem sd. |
577 | | *******************************************************************/ |
578 | | |
579 | | NTSTATUS fget_nt_acl_common( |
580 | | NTSTATUS (*fget_acl_blob_fn)(TALLOC_CTX *ctx, |
581 | | vfs_handle_struct *handle, |
582 | | files_struct *fsp, |
583 | | DATA_BLOB *pblob), |
584 | | vfs_handle_struct *handle, |
585 | | files_struct *fsp, |
586 | | uint32_t security_info, |
587 | | TALLOC_CTX *mem_ctx, |
588 | | struct security_descriptor **ppdesc) |
589 | 0 | { |
590 | 0 | DATA_BLOB blob = data_blob_null; |
591 | 0 | NTSTATUS status; |
592 | 0 | struct security_descriptor *psd = NULL; |
593 | 0 | const struct smb_filename *smb_fname = fsp->fsp_name; |
594 | 0 | bool psd_is_from_fs = false; |
595 | 0 | struct acl_common_config *config = NULL; |
596 | |
|
597 | 0 | SMB_VFS_HANDLE_GET_DATA(handle, config, |
598 | 0 | struct acl_common_config, |
599 | 0 | return NT_STATUS_UNSUCCESSFUL); |
600 | |
|
601 | 0 | DBG_DEBUG("name=%s\n", smb_fname->base_name); |
602 | |
|
603 | 0 | status = fget_acl_blob_fn(mem_ctx, handle, fsp, &blob); |
604 | 0 | if (NT_STATUS_IS_OK(status)) { |
605 | 0 | status = validate_nt_acl_blob(mem_ctx, |
606 | 0 | handle, |
607 | 0 | fsp, |
608 | 0 | smb_fname, |
609 | 0 | &blob, |
610 | 0 | &psd, |
611 | 0 | &psd_is_from_fs); |
612 | 0 | TALLOC_FREE(blob.data); |
613 | 0 | if (!NT_STATUS_IS_OK(status)) { |
614 | 0 | DBG_DEBUG("ACL validation for [%s] failed\n", |
615 | 0 | smb_fname->base_name); |
616 | 0 | goto fail; |
617 | 0 | } |
618 | 0 | } |
619 | | |
620 | 0 | if (psd == NULL) { |
621 | | /* Get the full underlying sd, as we failed to get the |
622 | | * blob for the hash, or the revision/hash type wasn't |
623 | | * known */ |
624 | |
|
625 | 0 | if (config->ignore_system_acls) { |
626 | 0 | status = vfs_stat_fsp(fsp); |
627 | 0 | if (!NT_STATUS_IS_OK(status)) { |
628 | 0 | goto fail; |
629 | 0 | } |
630 | | |
631 | 0 | status = make_default_filesystem_acl( |
632 | 0 | mem_ctx, |
633 | 0 | config->default_acl_style, |
634 | 0 | smb_fname->base_name, |
635 | 0 | &fsp->fsp_name->st, |
636 | 0 | &psd); |
637 | 0 | if (!NT_STATUS_IS_OK(status)) { |
638 | 0 | goto fail; |
639 | 0 | } |
640 | 0 | } else { |
641 | 0 | status = SMB_VFS_NEXT_FGET_NT_ACL(handle, |
642 | 0 | fsp, |
643 | 0 | security_info, |
644 | 0 | mem_ctx, |
645 | 0 | &psd); |
646 | |
|
647 | 0 | if (!NT_STATUS_IS_OK(status)) { |
648 | 0 | DBG_DEBUG("get_next_acl for file %s " |
649 | 0 | "returned %s\n", |
650 | 0 | smb_fname->base_name, |
651 | 0 | nt_errstr(status)); |
652 | 0 | goto fail; |
653 | 0 | } |
654 | | |
655 | 0 | psd_is_from_fs = true; |
656 | 0 | } |
657 | 0 | } |
658 | | |
659 | 0 | if (psd_is_from_fs) { |
660 | 0 | status = vfs_stat_fsp(fsp); |
661 | 0 | if (!NT_STATUS_IS_OK(status)) { |
662 | 0 | goto fail; |
663 | 0 | } |
664 | | |
665 | | /* |
666 | | * We're returning the underlying ACL from the |
667 | | * filesystem. If it's a directory, and has no |
668 | | * inheritable ACE entries we have to fake them. |
669 | | */ |
670 | | |
671 | 0 | if (fsp->fsp_flags.is_directory && |
672 | 0 | !sd_has_inheritable_components(psd, true)) { |
673 | 0 | status = add_directory_inheritable_components( |
674 | 0 | handle, |
675 | 0 | smb_fname->base_name, |
676 | 0 | &fsp->fsp_name->st, |
677 | 0 | psd); |
678 | 0 | if (!NT_STATUS_IS_OK(status)) { |
679 | 0 | goto fail; |
680 | 0 | } |
681 | 0 | } |
682 | | |
683 | | /* |
684 | | * The underlying POSIX module always sets the |
685 | | * ~SEC_DESC_DACL_PROTECTED bit, as ACLs can't be inherited in |
686 | | * this way under POSIX. Remove it for Windows-style ACLs. |
687 | | */ |
688 | 0 | psd->type &= ~SEC_DESC_DACL_PROTECTED; |
689 | 0 | } |
690 | | |
691 | 0 | if (!(security_info & SECINFO_OWNER)) { |
692 | 0 | psd->owner_sid = NULL; |
693 | 0 | } |
694 | 0 | if (!(security_info & SECINFO_GROUP)) { |
695 | 0 | psd->group_sid = NULL; |
696 | 0 | } |
697 | 0 | if (!(security_info & SECINFO_DACL)) { |
698 | 0 | psd->type &= ~SEC_DESC_DACL_PRESENT; |
699 | 0 | psd->dacl = NULL; |
700 | 0 | } |
701 | 0 | if (!(security_info & SECINFO_SACL)) { |
702 | 0 | psd->type &= ~SEC_DESC_SACL_PRESENT; |
703 | 0 | psd->sacl = NULL; |
704 | 0 | } |
705 | |
|
706 | 0 | if (DEBUGLEVEL >= 10) { |
707 | 0 | DBG_DEBUG("returning acl for %s is:\n", |
708 | 0 | smb_fname->base_name); |
709 | 0 | NDR_PRINT_DEBUG(security_descriptor, psd); |
710 | 0 | } |
711 | |
|
712 | 0 | *ppdesc = psd; |
713 | |
|
714 | 0 | return NT_STATUS_OK; |
715 | | |
716 | 0 | fail: |
717 | 0 | TALLOC_FREE(psd); |
718 | 0 | return status; |
719 | 0 | } |
720 | | |
721 | | /********************************************************************* |
722 | | Set the underlying ACL (e.g. POSIX ACLS, POSIX owner, etc) |
723 | | *********************************************************************/ |
724 | | static NTSTATUS set_underlying_acl(vfs_handle_struct *handle, files_struct *fsp, |
725 | | struct security_descriptor *psd, |
726 | | uint32_t security_info_sent, |
727 | | bool chown_needed) |
728 | 0 | { |
729 | 0 | NTSTATUS status; |
730 | 0 | const struct security_token *token = NULL; |
731 | 0 | struct dom_sid_buf buf; |
732 | |
|
733 | 0 | status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd); |
734 | 0 | if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { |
735 | 0 | return status; |
736 | 0 | } |
737 | | |
738 | | /* We got access denied here. If we're already root, |
739 | | or we didn't need to do a chown, or the fsp isn't |
740 | | open with WRITE_OWNER access, just return. */ |
741 | 0 | if (get_current_uid(handle->conn) == 0 || !chown_needed) { |
742 | 0 | return NT_STATUS_ACCESS_DENIED; |
743 | 0 | } |
744 | 0 | status = check_any_access_fsp(fsp, SEC_STD_WRITE_OWNER); |
745 | 0 | if (!NT_STATUS_IS_OK(status)) { |
746 | 0 | return status; |
747 | 0 | } |
748 | | |
749 | | /* |
750 | | * Only allow take-ownership, not give-ownership. That's the way Windows |
751 | | * implements SEC_STD_WRITE_OWNER. MS-FSA 2.1.5.16 just states: If |
752 | | * InputBuffer.OwnerSid is not a valid owner SID for a file in the |
753 | | * objectstore, as determined in an implementation specific manner, the |
754 | | * object store MUST return STATUS_INVALID_OWNER. |
755 | | */ |
756 | 0 | token = get_current_nttok(fsp->conn); |
757 | 0 | if (!security_token_is_sid(token, psd->owner_sid)) { |
758 | 0 | return NT_STATUS_INVALID_OWNER; |
759 | 0 | } |
760 | | |
761 | 0 | DBG_DEBUG("overriding chown on file %s for sid %s\n", |
762 | 0 | fsp_str_dbg(fsp), |
763 | 0 | dom_sid_str_buf(psd->owner_sid, &buf)); |
764 | | |
765 | | /* Ok, we failed to chown and we have |
766 | | SEC_STD_WRITE_OWNER access - override. */ |
767 | 0 | become_root(); |
768 | 0 | status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd); |
769 | 0 | unbecome_root(); |
770 | |
|
771 | 0 | return status; |
772 | 0 | } |
773 | | |
774 | | /********************************************************************* |
775 | | Store a v3 security descriptor |
776 | | *********************************************************************/ |
777 | | static NTSTATUS store_v3_blob( |
778 | | NTSTATUS (*store_acl_blob_fsp_fn)(vfs_handle_struct *handle, |
779 | | files_struct *fsp, |
780 | | DATA_BLOB *pblob), |
781 | | vfs_handle_struct *handle, files_struct *fsp, |
782 | | struct security_descriptor *psd, |
783 | | struct security_descriptor *pdesc_next, |
784 | | uint8_t hash[XATTR_SD_HASH_SIZE]) |
785 | 0 | { |
786 | 0 | NTSTATUS status; |
787 | 0 | DATA_BLOB blob; |
788 | |
|
789 | 0 | if (DEBUGLEVEL >= 10) { |
790 | 0 | DBG_DEBUG("storing xattr sd for file %s\n", |
791 | 0 | fsp_str_dbg(fsp)); |
792 | 0 | NDR_PRINT_DEBUG( |
793 | 0 | security_descriptor, |
794 | 0 | discard_const_p(struct security_descriptor, psd)); |
795 | |
|
796 | 0 | if (pdesc_next != NULL) { |
797 | 0 | DBG_DEBUG("storing xattr sd based on \n"); |
798 | 0 | NDR_PRINT_DEBUG( |
799 | 0 | security_descriptor, |
800 | 0 | discard_const_p(struct security_descriptor, |
801 | 0 | pdesc_next)); |
802 | 0 | } else { |
803 | 0 | DBG_DEBUG("ignoring underlying sd\n"); |
804 | 0 | } |
805 | 0 | } |
806 | 0 | status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash); |
807 | 0 | if (!NT_STATUS_IS_OK(status)) { |
808 | 0 | DBG_DEBUG("create_acl_blob failed\n"); |
809 | 0 | return status; |
810 | 0 | } |
811 | | |
812 | 0 | status = store_acl_blob_fsp_fn(handle, fsp, &blob); |
813 | 0 | return status; |
814 | 0 | } |
815 | | |
816 | | /********************************************************************* |
817 | | Store a security descriptor given an fsp. |
818 | | *********************************************************************/ |
819 | | |
820 | | NTSTATUS fset_nt_acl_common( |
821 | | NTSTATUS (*fget_acl_blob_fn)(TALLOC_CTX *ctx, |
822 | | vfs_handle_struct *handle, |
823 | | files_struct *fsp, |
824 | | DATA_BLOB *pblob), |
825 | | NTSTATUS (*store_acl_blob_fsp_fn)(vfs_handle_struct *handle, |
826 | | files_struct *fsp, |
827 | | DATA_BLOB *pblob), |
828 | | const char *module_name, |
829 | | vfs_handle_struct *handle, files_struct *fsp, |
830 | | uint32_t security_info_sent, |
831 | | const struct security_descriptor *orig_psd) |
832 | 0 | { |
833 | 0 | NTSTATUS status; |
834 | 0 | int ret; |
835 | 0 | DATA_BLOB blob, sys_acl_blob; |
836 | 0 | struct security_descriptor *pdesc_next = NULL; |
837 | 0 | struct security_descriptor *psd = NULL; |
838 | 0 | uint8_t hash[XATTR_SD_HASH_SIZE]; |
839 | 0 | uint8_t sys_acl_hash[XATTR_SD_HASH_SIZE]; |
840 | 0 | bool chown_needed = false; |
841 | 0 | char *sys_acl_description; |
842 | 0 | TALLOC_CTX *frame = talloc_stackframe(); |
843 | 0 | bool ignore_file_system_acl = lp_parm_bool( |
844 | 0 | SNUM(handle->conn), module_name, "ignore system acls", false); |
845 | 0 | struct acl_common_fsp_ext *ext = NULL; |
846 | |
|
847 | 0 | if (DEBUGLEVEL >= 10) { |
848 | 0 | DBG_DEBUG("incoming sd for file %s\n", fsp_str_dbg(fsp)); |
849 | 0 | NDR_PRINT_DEBUG(security_descriptor, |
850 | 0 | discard_const_p(struct security_descriptor, orig_psd)); |
851 | 0 | } |
852 | |
|
853 | 0 | status = fget_nt_acl_common(fget_acl_blob_fn, handle, fsp, |
854 | 0 | SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL, |
855 | 0 | frame, |
856 | 0 | &psd); |
857 | |
|
858 | 0 | if (!NT_STATUS_IS_OK(status)) { |
859 | 0 | TALLOC_FREE(frame); |
860 | 0 | return status; |
861 | 0 | } |
862 | | |
863 | 0 | psd->revision = orig_psd->revision; |
864 | 0 | if (security_info_sent & SECINFO_DACL) { |
865 | 0 | psd->type = orig_psd->type; |
866 | | /* All our SD's are self relative. */ |
867 | 0 | psd->type |= SEC_DESC_SELF_RELATIVE; |
868 | 0 | } |
869 | |
|
870 | 0 | if ((security_info_sent & SECINFO_OWNER) && (orig_psd->owner_sid != NULL)) { |
871 | 0 | if (!dom_sid_equal(orig_psd->owner_sid, psd->owner_sid)) { |
872 | | /* We're changing the owner. */ |
873 | 0 | chown_needed = true; |
874 | 0 | } |
875 | 0 | psd->owner_sid = orig_psd->owner_sid; |
876 | 0 | } |
877 | 0 | if ((security_info_sent & SECINFO_GROUP) && (orig_psd->group_sid != NULL)) { |
878 | 0 | if (!dom_sid_equal(orig_psd->group_sid, psd->group_sid)) { |
879 | | /* We're changing the group. */ |
880 | 0 | chown_needed = true; |
881 | 0 | } |
882 | 0 | psd->group_sid = orig_psd->group_sid; |
883 | 0 | } |
884 | 0 | if (security_info_sent & SECINFO_DACL) { |
885 | 0 | if (security_descriptor_with_ms_nfs(orig_psd)) { |
886 | | /* |
887 | | * If the sd contains a MS NFS SID, do |
888 | | * nothing, it's a chmod() request from OS X |
889 | | * with AAPL context. |
890 | | */ |
891 | 0 | TALLOC_FREE(frame); |
892 | 0 | return NT_STATUS_OK; |
893 | 0 | } |
894 | 0 | psd->dacl = orig_psd->dacl; |
895 | 0 | psd->type |= SEC_DESC_DACL_PRESENT; |
896 | 0 | } |
897 | 0 | if (security_info_sent & SECINFO_SACL) { |
898 | 0 | psd->sacl = orig_psd->sacl; |
899 | 0 | psd->type |= SEC_DESC_SACL_PRESENT; |
900 | 0 | } |
901 | |
|
902 | 0 | ext = VFS_ADD_FSP_EXTENSION(handle, |
903 | 0 | fsp, |
904 | 0 | struct acl_common_fsp_ext, |
905 | 0 | NULL); |
906 | 0 | ext->setting_nt_acl = true; |
907 | |
|
908 | 0 | if (ignore_file_system_acl) { |
909 | 0 | if (chown_needed) { |
910 | | /* send only ownership stuff to lower layer */ |
911 | 0 | security_info_sent &= (SECINFO_OWNER | SECINFO_GROUP); |
912 | 0 | status = set_underlying_acl(handle, fsp, psd, |
913 | 0 | security_info_sent, true); |
914 | 0 | if (!NT_STATUS_IS_OK(status)) { |
915 | 0 | goto done; |
916 | 0 | } |
917 | 0 | } |
918 | 0 | ZERO_ARRAY(hash); |
919 | 0 | status = store_v3_blob(store_acl_blob_fsp_fn, handle, fsp, psd, |
920 | 0 | NULL, hash); |
921 | 0 | goto done; |
922 | 0 | } |
923 | | |
924 | 0 | status = set_underlying_acl(handle, fsp, psd, security_info_sent, |
925 | 0 | chown_needed); |
926 | 0 | if (!NT_STATUS_IS_OK(status)) { |
927 | 0 | goto done; |
928 | 0 | } |
929 | | |
930 | | /* Get the full underlying sd, then hash. */ |
931 | 0 | status = SMB_VFS_NEXT_FGET_NT_ACL(handle, |
932 | 0 | fsp, |
933 | 0 | HASH_SECURITY_INFO, |
934 | 0 | frame, |
935 | 0 | &pdesc_next); |
936 | |
|
937 | 0 | if (!NT_STATUS_IS_OK(status)) { |
938 | 0 | goto done; |
939 | 0 | } |
940 | | |
941 | 0 | status = hash_sd_sha256(pdesc_next, hash); |
942 | 0 | if (!NT_STATUS_IS_OK(status)) { |
943 | 0 | goto done; |
944 | 0 | } |
945 | | |
946 | | /* Get the full underlying sd, then hash. */ |
947 | 0 | ret = SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle, |
948 | 0 | fsp, |
949 | 0 | frame, |
950 | 0 | &sys_acl_description, |
951 | 0 | &sys_acl_blob); |
952 | | |
953 | | /* If we fail to get the ACL blob (for some reason) then this |
954 | | * is not fatal, we just work based on the NT ACL only */ |
955 | 0 | if (ret != 0) { |
956 | 0 | status = store_v3_blob(store_acl_blob_fsp_fn, handle, fsp, psd, |
957 | 0 | pdesc_next, hash); |
958 | |
|
959 | 0 | goto done; |
960 | 0 | } |
961 | | |
962 | 0 | status = hash_blob_sha256(sys_acl_blob, sys_acl_hash); |
963 | 0 | if (!NT_STATUS_IS_OK(status)) { |
964 | 0 | goto done; |
965 | 0 | } |
966 | | |
967 | 0 | if (DEBUGLEVEL >= 10) { |
968 | 0 | DBG_DEBUG("storing xattr sd for file %s based on system ACL\n", |
969 | 0 | fsp_str_dbg(fsp)); |
970 | 0 | NDR_PRINT_DEBUG(security_descriptor, |
971 | 0 | discard_const_p(struct security_descriptor, psd)); |
972 | |
|
973 | 0 | DBG_DEBUG("storing hash in xattr sd based on system ACL and:\n"); |
974 | 0 | NDR_PRINT_DEBUG(security_descriptor, |
975 | 0 | discard_const_p(struct security_descriptor, pdesc_next)); |
976 | 0 | } |
977 | | |
978 | | /* We store hashes of both the sys ACL blob and the NT |
979 | | * security descriptor mapped from that ACL so as to improve |
980 | | * our chances against some inadvertent change breaking the |
981 | | * hash used */ |
982 | 0 | status = create_sys_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash, |
983 | 0 | sys_acl_description, sys_acl_hash); |
984 | 0 | if (!NT_STATUS_IS_OK(status)) { |
985 | 0 | DBG_DEBUG("create_sys_acl_blob failed\n"); |
986 | 0 | goto done; |
987 | 0 | } |
988 | | |
989 | 0 | status = store_acl_blob_fsp_fn(handle, fsp, &blob); |
990 | |
|
991 | 0 | done: |
992 | 0 | VFS_REMOVE_FSP_EXTENSION(handle, fsp); |
993 | 0 | TALLOC_FREE(frame); |
994 | 0 | return status; |
995 | 0 | } |
996 | | |
997 | | static int acl_common_remove_object(vfs_handle_struct *handle, |
998 | | struct files_struct *dirfsp, |
999 | | const struct smb_filename *smb_fname, |
1000 | | bool is_directory) |
1001 | 0 | { |
1002 | 0 | connection_struct *conn = handle->conn; |
1003 | 0 | struct stat_ex st; |
1004 | 0 | struct file_id id; |
1005 | 0 | files_struct *fsp = NULL; |
1006 | 0 | int ret = 0; |
1007 | |
|
1008 | 0 | SMB_ASSERT(strchr_m(smb_fname->base_name, '/') == NULL); |
1009 | | |
1010 | 0 | ret = SMB_VFS_FSTATAT( |
1011 | 0 | conn, dirfsp, smb_fname, &st, AT_SYMLINK_NOFOLLOW); |
1012 | 0 | if (ret == -1) { |
1013 | 0 | return ret; |
1014 | 0 | } |
1015 | | |
1016 | 0 | DBG_DEBUG("removing %s %s/%s\n", |
1017 | 0 | is_directory ? "directory" : "file", |
1018 | 0 | fsp_str_dbg(dirfsp), |
1019 | 0 | smb_fname_str_dbg(smb_fname)); |
1020 | | |
1021 | | /* Ensure we have this file open with DELETE access. */ |
1022 | 0 | id = vfs_file_id_from_sbuf(conn, &st); |
1023 | 0 | for (fsp = file_find_di_first(conn->sconn, id, true); fsp; |
1024 | 0 | fsp = file_find_di_next(fsp, true)) { |
1025 | 0 | if (fsp->access_mask & DELETE_ACCESS && |
1026 | 0 | fsp->fsp_flags.delete_on_close) |
1027 | 0 | { |
1028 | | /* We did open this for delete, |
1029 | | * allow the delete as root. |
1030 | | */ |
1031 | 0 | break; |
1032 | 0 | } |
1033 | 0 | } |
1034 | |
|
1035 | 0 | if (!fsp) { |
1036 | 0 | DBG_DEBUG("%s %s/%s not an open file\n", |
1037 | 0 | is_directory ? "directory" : "file", |
1038 | 0 | fsp_str_dbg(dirfsp), |
1039 | 0 | smb_fname_str_dbg(smb_fname)); |
1040 | 0 | return EACCES; |
1041 | 0 | } |
1042 | | |
1043 | 0 | become_root(); |
1044 | 0 | ret = SMB_VFS_NEXT_UNLINKAT(handle, |
1045 | 0 | dirfsp, |
1046 | 0 | smb_fname, |
1047 | 0 | is_directory ? AT_REMOVEDIR : 0); |
1048 | 0 | unbecome_root(); |
1049 | |
|
1050 | 0 | return ret; |
1051 | 0 | } |
1052 | | |
1053 | | int rmdir_acl_common(struct vfs_handle_struct *handle, |
1054 | | struct files_struct *dirfsp, |
1055 | | const struct smb_filename *smb_fname) |
1056 | 0 | { |
1057 | 0 | int ret; |
1058 | | |
1059 | | /* Try the normal rmdir first. */ |
1060 | 0 | ret = SMB_VFS_NEXT_UNLINKAT(handle, |
1061 | 0 | dirfsp, |
1062 | 0 | smb_fname, |
1063 | 0 | AT_REMOVEDIR); |
1064 | 0 | if (ret == 0) { |
1065 | 0 | return 0; |
1066 | 0 | } |
1067 | 0 | if (errno == EACCES || errno == EPERM) { |
1068 | | /* Failed due to access denied, |
1069 | | see if we need to root override. */ |
1070 | 0 | return acl_common_remove_object(handle, |
1071 | 0 | dirfsp, |
1072 | 0 | smb_fname, |
1073 | 0 | true); |
1074 | 0 | } |
1075 | | |
1076 | 0 | DBG_DEBUG("unlink of %s failed %s\n", |
1077 | 0 | smb_fname->base_name, |
1078 | 0 | strerror(errno)); |
1079 | 0 | return -1; |
1080 | 0 | } |
1081 | | |
1082 | | int unlink_acl_common(struct vfs_handle_struct *handle, |
1083 | | struct files_struct *dirfsp, |
1084 | | const struct smb_filename *smb_fname, |
1085 | | int flags) |
1086 | 0 | { |
1087 | 0 | int ret; |
1088 | | |
1089 | | /* Try the normal unlink first. */ |
1090 | 0 | ret = SMB_VFS_NEXT_UNLINKAT(handle, |
1091 | 0 | dirfsp, |
1092 | 0 | smb_fname, |
1093 | 0 | flags); |
1094 | 0 | if (ret == 0) { |
1095 | 0 | return 0; |
1096 | 0 | } |
1097 | 0 | if (errno == EACCES || errno == EPERM) { |
1098 | | /* Failed due to access denied, |
1099 | | see if we need to root override. */ |
1100 | | |
1101 | | /* Don't do anything fancy for streams. */ |
1102 | 0 | if (is_ntfs_stream_smb_fname(smb_fname)) { |
1103 | 0 | return -1; |
1104 | 0 | } |
1105 | 0 | return acl_common_remove_object(handle, |
1106 | 0 | dirfsp, |
1107 | 0 | smb_fname, |
1108 | 0 | false); |
1109 | 0 | } |
1110 | | |
1111 | 0 | DBG_DEBUG("unlink of %s failed %s\n", |
1112 | 0 | smb_fname->base_name, |
1113 | 0 | strerror(errno)); |
1114 | 0 | return -1; |
1115 | 0 | } |
1116 | | |
1117 | | int fchmod_acl_module_common(struct vfs_handle_struct *handle, |
1118 | | struct files_struct *fsp, mode_t mode) |
1119 | 0 | { |
1120 | 0 | if (fsp->fsp_flags.posix_open |
1121 | 0 | || fsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH) { |
1122 | | /* Only allow this on POSIX opens. */ |
1123 | 0 | return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode); |
1124 | 0 | } |
1125 | 0 | return 0; |
1126 | 0 | } |