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 948797 : 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 2317 : ssize_t sizeret;
47 948797 : int saved_errno = 0;
48 :
49 948797 : become_root();
50 948797 : sizeret = SMB_VFS_FGETXATTR(fsp, xattr_name, val, size);
51 948797 : if (sizeret == -1) {
52 192948 : saved_errno = errno;
53 : }
54 947704 : unbecome_root();
55 :
56 948797 : if (saved_errno != 0) {
57 192948 : errno = saved_errno;
58 : }
59 :
60 948797 : return sizeret;
61 : }
62 :
63 948769 : static NTSTATUS fget_acl_blob(TALLOC_CTX *ctx,
64 : vfs_handle_struct *handle,
65 : files_struct *fsp,
66 : DATA_BLOB *pblob)
67 : {
68 948769 : size_t size = 4096;
69 948769 : uint8_t *val = NULL;
70 2317 : uint8_t *tmp;
71 2317 : ssize_t sizeret;
72 :
73 948769 : ZERO_STRUCTP(pblob);
74 :
75 946452 : again:
76 :
77 948783 : tmp = talloc_realloc(ctx, val, uint8_t, size);
78 948783 : if (tmp == NULL) {
79 0 : TALLOC_FREE(val);
80 0 : return NT_STATUS_NO_MEMORY;
81 : }
82 948783 : val = tmp;
83 :
84 2317 : sizeret =
85 948783 : getxattr_do(handle, fsp, XATTR_NTACL_NAME, val, size);
86 :
87 948783 : if (sizeret >= 0) {
88 755835 : pblob->data = val;
89 755835 : pblob->length = sizeret;
90 755835 : return NT_STATUS_OK;
91 : }
92 :
93 192948 : if (errno != ERANGE) {
94 192934 : goto err;
95 : }
96 :
97 : /* Too small, try again. */
98 0 : sizeret =
99 14 : getxattr_do(handle, fsp, XATTR_NTACL_NAME, NULL, 0);
100 14 : if (sizeret < 0) {
101 0 : goto err;
102 : }
103 :
104 14 : if (size < sizeret) {
105 14 : size = sizeret;
106 : }
107 :
108 14 : if (size > 65536) {
109 : /* Max ACL size is 65536 bytes. */
110 0 : errno = ERANGE;
111 0 : goto err;
112 : }
113 :
114 14 : goto again;
115 192934 : err:
116 : /* Real error - exit here. */
117 192934 : TALLOC_FREE(val);
118 192934 : 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 157693 : static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
126 : files_struct *fsp,
127 : DATA_BLOB *pblob)
128 : {
129 431 : int ret;
130 157693 : int saved_errno = 0;
131 :
132 157693 : 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 157693 : become_root();
136 157693 : ret = SMB_VFS_FSETXATTR(fsp, XATTR_NTACL_NAME,
137 : pblob->data, pblob->length, 0);
138 157693 : if (ret) {
139 0 : saved_errno = errno;
140 : }
141 157693 : unbecome_root();
142 157693 : 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 157693 : return NT_STATUS_OK;
151 : }
152 :
153 : /*********************************************************************
154 : Remove a Windows ACL - we're setting the underlying POSIX ACL.
155 : *********************************************************************/
156 :
157 164255 : 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 515 : struct acl_common_fsp_ext *ext = (struct acl_common_fsp_ext *)
163 164255 : VFS_FETCH_FSP_EXTENSION(handle, fsp);
164 515 : int ret;
165 :
166 164255 : ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle,
167 : fsp,
168 : type,
169 : theacl);
170 164255 : if (ret == -1) {
171 0 : return -1;
172 : }
173 :
174 164255 : if (ext != NULL && ext->setting_nt_acl) {
175 163559 : return 0;
176 : }
177 :
178 185 : become_root();
179 185 : SMB_VFS_FREMOVEXATTR(fsp, XATTR_NTACL_NAME);
180 185 : unbecome_root();
181 :
182 185 : return 0;
183 : }
184 :
185 53460 : static int connect_acl_xattr(struct vfs_handle_struct *handle,
186 : const char *service,
187 : const char *user)
188 : {
189 53460 : const char *security_acl_xattr_name = NULL;
190 53460 : int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
191 851 : bool ok;
192 53460 : struct acl_common_config *config = NULL;
193 :
194 53460 : if (ret < 0) {
195 16 : return ret;
196 : }
197 :
198 53444 : ok = init_acl_common_config(handle, ACL_MODULE_NAME);
199 53444 : 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 53444 : 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 53444 : lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
212 53444 : lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
213 53444 : lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
214 :
215 53444 : SMB_VFS_HANDLE_GET_DATA(handle, config,
216 : struct acl_common_config,
217 851 : return -1);
218 :
219 53444 : if (config->ignore_system_acls) {
220 210 : mode_t create_mask = lp_create_mask(SNUM(handle->conn));
221 210 : char *create_mask_str = NULL;
222 :
223 210 : if ((create_mask & 0666) != 0666) {
224 210 : create_mask |= 0666;
225 210 : create_mask_str = talloc_asprintf(handle, "0%o",
226 : create_mask);
227 210 : if (create_mask_str == NULL) {
228 0 : DBG_ERR("talloc_asprintf failed\n");
229 0 : return -1;
230 : }
231 :
232 210 : DBG_NOTICE("setting 'create mask = %s'\n", create_mask_str);
233 :
234 210 : lp_do_parameter (SNUM(handle->conn),
235 : "create mask", create_mask_str);
236 :
237 210 : TALLOC_FREE(create_mask_str);
238 : }
239 :
240 210 : DBG_NOTICE("setting 'directory mask = 0777', "
241 : "'store dos attributes = yes' and all "
242 : "'map ...' options to 'no'\n");
243 :
244 210 : lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
245 210 : lp_do_parameter(SNUM(handle->conn), "map archive", "no");
246 210 : lp_do_parameter(SNUM(handle->conn), "map hidden", "no");
247 210 : lp_do_parameter(SNUM(handle->conn), "map readonly", "no");
248 210 : lp_do_parameter(SNUM(handle->conn), "map system", "no");
249 210 : lp_do_parameter(SNUM(handle->conn), "store dos attributes",
250 : "yes");
251 : }
252 :
253 53444 : security_acl_xattr_name = lp_parm_const_string(SNUM(handle->conn),
254 : "acl_xattr",
255 : "security_acl_name",
256 : NULL);
257 53444 : if (security_acl_xattr_name != NULL) {
258 34 : config->security_acl_xattr_name = talloc_strdup(config, security_acl_xattr_name);
259 34 : if (config->security_acl_xattr_name == NULL) {
260 0 : return -1;
261 : }
262 : }
263 :
264 52593 : return 0;
265 : }
266 :
267 148528 : 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 337 : int ret;
273 :
274 148528 : if (flags & AT_REMOVEDIR) {
275 10007 : ret = rmdir_acl_common(handle,
276 : dirfsp,
277 : smb_fname);
278 : } else {
279 138521 : ret = unlink_acl_common(handle,
280 : dirfsp,
281 : smb_fname,
282 : flags);
283 : }
284 148528 : return ret;
285 : }
286 :
287 791074 : 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 1886 : NTSTATUS status;
294 791074 : status = fget_nt_acl_common(fget_acl_blob, handle, fsp,
295 : security_info, mem_ctx, ppdesc);
296 791074 : return status;
297 : }
298 :
299 157695 : 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 431 : NTSTATUS status;
305 157695 : status = fset_nt_acl_common(fget_acl_blob, store_acl_blob_fsp,
306 : ACL_MODULE_NAME,
307 : handle, fsp, security_info_sent, psd);
308 157695 : 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 0 : 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 0 : 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 2346117 : 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 2346117 : struct acl_common_config *config = NULL;
419 :
420 2346117 : SMB_VFS_HANDLE_GET_DATA(handle, config,
421 : struct acl_common_config,
422 5150 : return -1);
423 :
424 2346117 : if (strequal(name, config->security_acl_xattr_name)) {
425 0 : errno = EACCES;
426 0 : return -1;
427 : }
428 2346317 : if (config->security_acl_xattr_name != NULL &&
429 200 : strequal(name, XATTR_NTACL_NAME))
430 : {
431 96 : name = config->security_acl_xattr_name;
432 : }
433 :
434 2346117 : return SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, value, size);
435 : }
436 :
437 725467 : 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 725467 : struct acl_common_config *config = NULL;
443 1071 : ssize_t size;
444 725467 : char *p = NULL;
445 1071 : size_t nlen, consumed;
446 :
447 725467 : SMB_VFS_HANDLE_GET_DATA(handle, config,
448 : struct acl_common_config,
449 1071 : return -1);
450 :
451 725467 : size = SMB_VFS_NEXT_FLISTXATTR(handle, fsp, listbuf, bufsize);
452 725467 : if (size < 0) {
453 0 : return -1;
454 : }
455 :
456 724396 : p = listbuf;
457 4159426 : while (p - listbuf < size) {
458 3433975 : nlen = strlen(p) + 1;
459 3433975 : if (strequal(p, config->security_acl_xattr_name)) {
460 16 : break;
461 : }
462 3433959 : p += nlen;
463 : }
464 725467 : if (p - listbuf >= size) {
465 : /* No match */
466 724380 : return size;
467 : }
468 :
469 : /*
470 : * The consumed helper variable just makes the math
471 : * a bit more digestible.
472 : */
473 16 : consumed = p - listbuf;
474 16 : if (consumed + nlen < size) {
475 : /* If not the last name move, else just skip */
476 6 : memmove(p, p + nlen, size - consumed - nlen);
477 : }
478 16 : size -= nlen;
479 :
480 16 : return size;
481 : }
482 :
483 1703 : static int acl_xattr_fremovexattr(struct vfs_handle_struct *handle,
484 : struct files_struct *fsp,
485 : const char *name)
486 : {
487 1703 : struct acl_common_config *config = NULL;
488 :
489 1703 : SMB_VFS_HANDLE_GET_DATA(handle, config,
490 : struct acl_common_config,
491 216 : return -1);
492 :
493 1703 : if (strequal(name, config->security_acl_xattr_name)) {
494 0 : errno = EACCES;
495 0 : return -1;
496 : }
497 1705 : if (config->security_acl_xattr_name != NULL &&
498 2 : strequal(name, XATTR_NTACL_NAME))
499 : {
500 0 : name = config->security_acl_xattr_name;
501 : }
502 :
503 1703 : return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, name);
504 : }
505 :
506 315073 : 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 315073 : struct acl_common_config *config = NULL;
514 :
515 315073 : SMB_VFS_HANDLE_GET_DATA(handle, config,
516 : struct acl_common_config,
517 1180 : return -1);
518 :
519 315073 : if (strequal(name, config->security_acl_xattr_name)) {
520 2 : errno = EACCES;
521 2 : return -1;
522 : }
523 315101 : if (config->security_acl_xattr_name != NULL &&
524 30 : strequal(name, XATTR_NTACL_NAME))
525 : {
526 14 : name = config->security_acl_xattr_name;
527 : }
528 :
529 315071 : 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 28486 : NTSTATUS vfs_acl_xattr_init(TALLOC_CTX *ctx)
549 : {
550 28486 : return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "acl_xattr",
551 : &vfs_acl_xattr_fns);
552 : }
|