Line data Source code
1 : /*
2 : * Store Windows ACLs in xattrs.
3 : *
4 : * Copyright (C) Volker Lendecke, 2008
5 : * Copyright (C) Jeremy Allison, 2008
6 : *
7 : * This program is free software; you can redistribute it and/or modify
8 : * it under the terms of the GNU General Public License as published by
9 : * the Free Software Foundation; either version 3 of the License, or
10 : * (at your option) any later version.
11 : *
12 : * This program is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "smbd/smbd.h"
23 : #include "system/filesys.h"
24 : #include "librpc/gen_ndr/xattr.h"
25 : #include "auth.h"
26 : #include "vfs_acl_common.h"
27 : #include "lib/util/tevent_ntstatus.h"
28 : #include "lib/util/tevent_unix.h"
29 :
30 : /* Pull in the common functions. */
31 : #define ACL_MODULE_NAME "acl_xattr"
32 :
33 : #undef DBGC_CLASS
34 : #define DBGC_CLASS DBGC_VFS
35 :
36 : /*******************************************************************
37 : Pull a security descriptor into a DATA_BLOB from a xattr.
38 : *******************************************************************/
39 :
40 9043 : static ssize_t getxattr_do(vfs_handle_struct *handle,
41 : files_struct *fsp,
42 : const char *xattr_name,
43 : uint8_t *val,
44 : size_t size)
45 : {
46 : ssize_t sizeret;
47 9043 : int saved_errno = 0;
48 :
49 9043 : become_root();
50 9043 : sizeret = SMB_VFS_FGETXATTR(fsp, xattr_name, val, size);
51 9043 : if (sizeret == -1) {
52 3770 : saved_errno = errno;
53 : }
54 9043 : unbecome_root();
55 :
56 9043 : if (saved_errno != 0) {
57 3770 : errno = saved_errno;
58 : }
59 :
60 9043 : return sizeret;
61 : }
62 :
63 9043 : static NTSTATUS fget_acl_blob(TALLOC_CTX *ctx,
64 : vfs_handle_struct *handle,
65 : files_struct *fsp,
66 : DATA_BLOB *pblob)
67 : {
68 9043 : size_t size = 4096;
69 9043 : uint8_t *val = NULL;
70 : uint8_t *tmp;
71 : ssize_t sizeret;
72 :
73 16587 : ZERO_STRUCTP(pblob);
74 :
75 9043 : again:
76 :
77 9043 : tmp = talloc_realloc(ctx, val, uint8_t, size);
78 9043 : if (tmp == NULL) {
79 0 : TALLOC_FREE(val);
80 0 : return NT_STATUS_NO_MEMORY;
81 : }
82 9043 : val = tmp;
83 :
84 7544 : sizeret =
85 1499 : getxattr_do(handle, fsp, XATTR_NTACL_NAME, val, size);
86 :
87 9043 : if (sizeret >= 0) {
88 5273 : pblob->data = val;
89 5273 : pblob->length = sizeret;
90 5273 : return NT_STATUS_OK;
91 : }
92 :
93 3770 : if (errno != ERANGE) {
94 3770 : goto err;
95 : }
96 :
97 : /* Too small, try again. */
98 0 : sizeret =
99 0 : getxattr_do(handle, fsp, XATTR_NTACL_NAME, NULL, 0);
100 0 : if (sizeret < 0) {
101 0 : goto err;
102 : }
103 :
104 0 : if (size < sizeret) {
105 0 : size = sizeret;
106 : }
107 :
108 0 : if (size > 65536) {
109 : /* Max ACL size is 65536 bytes. */
110 0 : errno = ERANGE;
111 0 : goto err;
112 : }
113 :
114 0 : goto again;
115 3770 : err:
116 : /* Real error - exit here. */
117 3770 : TALLOC_FREE(val);
118 3770 : return map_nt_error_from_unix(errno);
119 : }
120 :
121 : /*******************************************************************
122 : Store a DATA_BLOB into an xattr given an fsp pointer.
123 : *******************************************************************/
124 :
125 2382 : static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
126 : files_struct *fsp,
127 : DATA_BLOB *pblob)
128 : {
129 : int ret;
130 2382 : int saved_errno = 0;
131 :
132 2382 : DEBUG(10,("store_acl_blob_fsp: storing blob length %u on file %s\n",
133 : (unsigned int)pblob->length, fsp_str_dbg(fsp)));
134 :
135 2382 : become_root();
136 2382 : ret = SMB_VFS_FSETXATTR(fsp, XATTR_NTACL_NAME,
137 : pblob->data, pblob->length, 0);
138 2382 : if (ret) {
139 0 : saved_errno = errno;
140 : }
141 2382 : unbecome_root();
142 2382 : if (ret) {
143 0 : DEBUG(5, ("store_acl_blob_fsp: setting attr failed for file %s"
144 : "with error %s\n",
145 : fsp_str_dbg(fsp),
146 : strerror(saved_errno) ));
147 0 : errno = saved_errno;
148 0 : return map_nt_error_from_unix(saved_errno);
149 : }
150 2382 : return NT_STATUS_OK;
151 : }
152 :
153 : /*********************************************************************
154 : Remove a Windows ACL - we're setting the underlying POSIX ACL.
155 : *********************************************************************/
156 :
157 1718 : static int sys_acl_set_fd_xattr(vfs_handle_struct *handle,
158 : files_struct *fsp,
159 : SMB_ACL_TYPE_T type,
160 : SMB_ACL_T theacl)
161 : {
162 1285 : struct acl_common_fsp_ext *ext = (struct acl_common_fsp_ext *)
163 433 : VFS_FETCH_FSP_EXTENSION(handle, fsp);
164 : int ret;
165 :
166 1718 : ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle,
167 : fsp,
168 : type,
169 : theacl);
170 1718 : if (ret == -1) {
171 0 : return -1;
172 : }
173 :
174 1718 : if (ext != NULL && ext->setting_nt_acl) {
175 1689 : return 0;
176 : }
177 :
178 29 : become_root();
179 29 : SMB_VFS_FREMOVEXATTR(fsp, XATTR_NTACL_NAME);
180 29 : unbecome_root();
181 :
182 29 : return 0;
183 : }
184 :
185 7952 : static int connect_acl_xattr(struct vfs_handle_struct *handle,
186 : const char *service,
187 : const char *user)
188 : {
189 7952 : const char *security_acl_xattr_name = NULL;
190 7952 : int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
191 : bool ok;
192 7952 : struct acl_common_config *config = NULL;
193 :
194 7952 : if (ret < 0) {
195 0 : return ret;
196 : }
197 :
198 7952 : ok = init_acl_common_config(handle, ACL_MODULE_NAME);
199 7952 : if (!ok) {
200 0 : DBG_ERR("init_acl_common_config failed\n");
201 0 : return -1;
202 : }
203 :
204 : /* Ensure we have the parameters correct if we're
205 : * using this module. */
206 7952 : DEBUG(2,("connect_acl_xattr: setting 'inherit acls = true' "
207 : "'dos filemode = true' and "
208 : "'force unknown acl user = true' for service %s\n",
209 : service ));
210 :
211 7952 : lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
212 7952 : lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
213 7952 : lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
214 :
215 7952 : SMB_VFS_HANDLE_GET_DATA(handle, config,
216 : struct acl_common_config,
217 : return -1);
218 :
219 7952 : if (config->ignore_system_acls) {
220 0 : mode_t create_mask = lp_create_mask(SNUM(handle->conn));
221 0 : char *create_mask_str = NULL;
222 :
223 0 : if ((create_mask & 0666) != 0666) {
224 0 : create_mask |= 0666;
225 0 : create_mask_str = talloc_asprintf(handle, "0%o",
226 : create_mask);
227 0 : if (create_mask_str == NULL) {
228 0 : DBG_ERR("talloc_asprintf failed\n");
229 0 : return -1;
230 : }
231 :
232 0 : DBG_NOTICE("setting 'create mask = %s'\n", create_mask_str);
233 :
234 0 : lp_do_parameter (SNUM(handle->conn),
235 : "create mask", create_mask_str);
236 :
237 0 : TALLOC_FREE(create_mask_str);
238 : }
239 :
240 0 : DBG_NOTICE("setting 'directory mask = 0777', "
241 : "'store dos attributes = yes' and all "
242 : "'map ...' options to 'no'\n");
243 :
244 0 : lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
245 0 : lp_do_parameter(SNUM(handle->conn), "map archive", "no");
246 0 : lp_do_parameter(SNUM(handle->conn), "map hidden", "no");
247 0 : lp_do_parameter(SNUM(handle->conn), "map readonly", "no");
248 0 : lp_do_parameter(SNUM(handle->conn), "map system", "no");
249 0 : lp_do_parameter(SNUM(handle->conn), "store dos attributes",
250 : "yes");
251 : }
252 :
253 7952 : security_acl_xattr_name = lp_parm_const_string(SNUM(handle->conn),
254 : "acl_xattr",
255 : "security_acl_name",
256 : NULL);
257 7952 : if (security_acl_xattr_name != NULL) {
258 0 : config->security_acl_xattr_name = talloc_strdup(config, security_acl_xattr_name);
259 0 : if (config->security_acl_xattr_name == NULL) {
260 0 : return -1;
261 : }
262 : }
263 :
264 7952 : return 0;
265 : }
266 :
267 1377 : static int acl_xattr_unlinkat(vfs_handle_struct *handle,
268 : struct files_struct *dirfsp,
269 : const struct smb_filename *smb_fname,
270 : int flags)
271 : {
272 : int ret;
273 :
274 1377 : if (flags & AT_REMOVEDIR) {
275 804 : ret = rmdir_acl_common(handle,
276 : dirfsp,
277 : smb_fname);
278 : } else {
279 573 : ret = unlink_acl_common(handle,
280 : dirfsp,
281 : smb_fname,
282 : flags);
283 : }
284 1377 : return ret;
285 : }
286 :
287 6661 : static NTSTATUS acl_xattr_fget_nt_acl(vfs_handle_struct *handle,
288 : files_struct *fsp,
289 : uint32_t security_info,
290 : TALLOC_CTX *mem_ctx,
291 : struct security_descriptor **ppdesc)
292 : {
293 : NTSTATUS status;
294 6661 : status = fget_nt_acl_common(fget_acl_blob, handle, fsp,
295 : security_info, mem_ctx, ppdesc);
296 6661 : return status;
297 : }
298 :
299 2382 : static NTSTATUS acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
300 : files_struct *fsp,
301 : uint32_t security_info_sent,
302 : const struct security_descriptor *psd)
303 : {
304 : NTSTATUS status;
305 2382 : status = fset_nt_acl_common(fget_acl_blob, store_acl_blob_fsp,
306 : ACL_MODULE_NAME,
307 : handle, fsp, security_info_sent, psd);
308 2382 : return status;
309 : }
310 :
311 : struct acl_xattr_getxattrat_state {
312 : struct vfs_aio_state aio_state;
313 : ssize_t xattr_size;
314 : uint8_t *xattr_value;
315 : };
316 :
317 : static void acl_xattr_getxattrat_done(struct tevent_req *subreq);
318 :
319 0 : static struct tevent_req *acl_xattr_getxattrat_send(
320 : TALLOC_CTX *mem_ctx,
321 : struct tevent_context *ev,
322 : struct vfs_handle_struct *handle,
323 : files_struct *dirfsp,
324 : const struct smb_filename *smb_fname,
325 : const char *xattr_name,
326 : size_t alloc_hint)
327 : {
328 0 : struct tevent_req *req = NULL;
329 0 : struct tevent_req *subreq = NULL;
330 0 : struct acl_xattr_getxattrat_state *state = NULL;
331 0 : struct acl_common_config *config = NULL;
332 :
333 0 : SMB_VFS_HANDLE_GET_DATA(handle, config,
334 : struct acl_common_config,
335 : return NULL);
336 :
337 0 : req = tevent_req_create(mem_ctx, &state,
338 : struct acl_xattr_getxattrat_state);
339 0 : if (req == NULL) {
340 0 : return NULL;
341 : }
342 :
343 0 : if (strequal(xattr_name, config->security_acl_xattr_name)) {
344 0 : tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
345 0 : return tevent_req_post(req, ev);
346 : }
347 0 : if (config->security_acl_xattr_name != NULL &&
348 0 : strequal(xattr_name, XATTR_NTACL_NAME))
349 : {
350 0 : xattr_name = config->security_acl_xattr_name;
351 : }
352 :
353 0 : subreq = SMB_VFS_NEXT_GETXATTRAT_SEND(state,
354 : ev,
355 : handle,
356 : dirfsp,
357 : smb_fname,
358 : xattr_name,
359 : alloc_hint);
360 0 : if (tevent_req_nomem(subreq, req)) {
361 0 : return tevent_req_post(req, ev);
362 : }
363 0 : tevent_req_set_callback(subreq, acl_xattr_getxattrat_done, req);
364 :
365 0 : return req;
366 : }
367 :
368 0 : static void acl_xattr_getxattrat_done(struct tevent_req *subreq)
369 : {
370 0 : struct tevent_req *req = tevent_req_callback_data(
371 : subreq, struct tevent_req);
372 0 : struct acl_xattr_getxattrat_state *state = tevent_req_data(
373 : req, struct acl_xattr_getxattrat_state);
374 :
375 0 : state->xattr_size = SMB_VFS_NEXT_GETXATTRAT_RECV(subreq,
376 : &state->aio_state,
377 : state,
378 : &state->xattr_value);
379 0 : TALLOC_FREE(subreq);
380 0 : if (state->xattr_size == -1) {
381 0 : tevent_req_error(req, state->aio_state.error);
382 0 : return;
383 : }
384 :
385 0 : tevent_req_done(req);
386 : }
387 :
388 0 : static ssize_t acl_xattr_getxattrat_recv(struct tevent_req *req,
389 : struct vfs_aio_state *aio_state,
390 : TALLOC_CTX *mem_ctx,
391 : uint8_t **xattr_value)
392 : {
393 0 : struct acl_xattr_getxattrat_state *state = tevent_req_data(
394 : req, struct acl_xattr_getxattrat_state);
395 : ssize_t xattr_size;
396 :
397 0 : if (tevent_req_is_unix_error(req, &aio_state->error)) {
398 0 : tevent_req_received(req);
399 0 : return -1;
400 : }
401 :
402 0 : *aio_state = state->aio_state;
403 0 : xattr_size = state->xattr_size;
404 0 : if (xattr_value != NULL) {
405 0 : *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
406 : }
407 :
408 0 : tevent_req_received(req);
409 0 : return xattr_size;
410 : }
411 :
412 39484 : static ssize_t acl_xattr_fgetxattr(struct vfs_handle_struct *handle,
413 : struct files_struct *fsp,
414 : const char *name,
415 : void *value,
416 : size_t size)
417 : {
418 39484 : struct acl_common_config *config = NULL;
419 :
420 39484 : SMB_VFS_HANDLE_GET_DATA(handle, config,
421 : struct acl_common_config,
422 : return -1);
423 :
424 39484 : if (strequal(name, config->security_acl_xattr_name)) {
425 0 : errno = EACCES;
426 0 : return -1;
427 : }
428 39484 : if (config->security_acl_xattr_name != NULL &&
429 0 : strequal(name, XATTR_NTACL_NAME))
430 : {
431 0 : name = config->security_acl_xattr_name;
432 : }
433 :
434 39484 : return SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, value, size);
435 : }
436 :
437 10320 : static ssize_t acl_xattr_flistxattr(struct vfs_handle_struct *handle,
438 : struct files_struct *fsp,
439 : char *listbuf,
440 : size_t bufsize)
441 : {
442 10320 : struct acl_common_config *config = NULL;
443 : ssize_t size;
444 10320 : char *p = NULL;
445 : size_t nlen, consumed;
446 :
447 10320 : SMB_VFS_HANDLE_GET_DATA(handle, config,
448 : struct acl_common_config,
449 : return -1);
450 :
451 10320 : size = SMB_VFS_NEXT_FLISTXATTR(handle, fsp, listbuf, bufsize);
452 10320 : if (size < 0) {
453 0 : return -1;
454 : }
455 :
456 10320 : p = listbuf;
457 39516 : while (p - listbuf < size) {
458 21777 : nlen = strlen(p) + 1;
459 21777 : if (strequal(p, config->security_acl_xattr_name)) {
460 0 : break;
461 : }
462 21777 : p += nlen;
463 : }
464 10320 : if (p - listbuf >= size) {
465 : /* No match */
466 10320 : return size;
467 : }
468 :
469 : /*
470 : * The consumed helper variable just makes the math
471 : * a bit more digestible.
472 : */
473 0 : consumed = p - listbuf;
474 0 : if (consumed + nlen < size) {
475 : /* If not the last name move, else just skip */
476 0 : memmove(p, p + nlen, size - consumed - nlen);
477 : }
478 0 : size -= nlen;
479 :
480 0 : return size;
481 : }
482 :
483 29 : static int acl_xattr_fremovexattr(struct vfs_handle_struct *handle,
484 : struct files_struct *fsp,
485 : const char *name)
486 : {
487 29 : struct acl_common_config *config = NULL;
488 :
489 29 : SMB_VFS_HANDLE_GET_DATA(handle, config,
490 : struct acl_common_config,
491 : return -1);
492 :
493 29 : if (strequal(name, config->security_acl_xattr_name)) {
494 0 : errno = EACCES;
495 0 : return -1;
496 : }
497 29 : if (config->security_acl_xattr_name != NULL &&
498 0 : strequal(name, XATTR_NTACL_NAME))
499 : {
500 0 : name = config->security_acl_xattr_name;
501 : }
502 :
503 29 : return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, name);
504 : }
505 :
506 3861 : static int acl_xattr_fsetxattr(struct vfs_handle_struct *handle,
507 : struct files_struct *fsp,
508 : const char *name,
509 : const void *value,
510 : size_t size,
511 : int flags)
512 : {
513 3861 : struct acl_common_config *config = NULL;
514 :
515 3861 : SMB_VFS_HANDLE_GET_DATA(handle, config,
516 : struct acl_common_config,
517 : return -1);
518 :
519 3861 : if (strequal(name, config->security_acl_xattr_name)) {
520 0 : errno = EACCES;
521 0 : return -1;
522 : }
523 3861 : if (config->security_acl_xattr_name != NULL &&
524 0 : strequal(name, XATTR_NTACL_NAME))
525 : {
526 0 : name = config->security_acl_xattr_name;
527 : }
528 :
529 3861 : return SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, value, size, flags);
530 : }
531 :
532 : static struct vfs_fn_pointers vfs_acl_xattr_fns = {
533 : .connect_fn = connect_acl_xattr,
534 : .unlinkat_fn = acl_xattr_unlinkat,
535 : .fchmod_fn = fchmod_acl_module_common,
536 : .fget_nt_acl_fn = acl_xattr_fget_nt_acl,
537 : .fset_nt_acl_fn = acl_xattr_fset_nt_acl,
538 : .sys_acl_set_fd_fn = sys_acl_set_fd_xattr,
539 : .getxattrat_send_fn = acl_xattr_getxattrat_send,
540 : .getxattrat_recv_fn = acl_xattr_getxattrat_recv,
541 : .fgetxattr_fn = acl_xattr_fgetxattr,
542 : .flistxattr_fn = acl_xattr_flistxattr,
543 : .fremovexattr_fn = acl_xattr_fremovexattr,
544 : .fsetxattr_fn = acl_xattr_fsetxattr,
545 : };
546 :
547 : static_decl_vfs;
548 4865 : NTSTATUS vfs_acl_xattr_init(TALLOC_CTX *ctx)
549 : {
550 4865 : return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "acl_xattr",
551 : &vfs_acl_xattr_fns);
552 : }
|