s3:libsmb: allow store_cldap_reply() to work with a ipv6 response
[samba.git] / source3 / modules / vfs_acl_xattr.c
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 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         int saved_errno = 0;
48
49         become_root();
50         sizeret = SMB_VFS_FGETXATTR(fsp, xattr_name, val, size);
51         if (sizeret == -1) {
52                 saved_errno = errno;
53         }
54         unbecome_root();
55
56         if (saved_errno != 0) {
57                 errno = saved_errno;
58         }
59
60         return sizeret;
61 }
62
63 static NTSTATUS fget_acl_blob(TALLOC_CTX *ctx,
64                         vfs_handle_struct *handle,
65                         files_struct *fsp,
66                         DATA_BLOB *pblob)
67 {
68         size_t size = 4096;
69         uint8_t *val = NULL;
70         uint8_t *tmp;
71         ssize_t sizeret;
72
73         ZERO_STRUCTP(pblob);
74
75   again:
76
77         tmp = talloc_realloc(ctx, val, uint8_t, size);
78         if (tmp == NULL) {
79                 TALLOC_FREE(val);
80                 return NT_STATUS_NO_MEMORY;
81         }
82         val = tmp;
83
84         sizeret =
85             getxattr_do(handle, fsp, XATTR_NTACL_NAME, val, size);
86
87         if (sizeret >= 0) {
88                 pblob->data = val;
89                 pblob->length = sizeret;
90                 return NT_STATUS_OK;
91         }
92
93         if (errno != ERANGE) {
94                 goto err;
95         }
96
97         /* Too small, try again. */
98         sizeret =
99             getxattr_do(handle, fsp, XATTR_NTACL_NAME, NULL, 0);
100         if (sizeret < 0) {
101                 goto err;
102         }
103
104         if (size < sizeret) {
105                 size = sizeret;
106         }
107
108         if (size > 65536) {
109                 /* Max ACL size is 65536 bytes. */
110                 errno = ERANGE;
111                 goto err;
112         }
113
114         goto again;
115   err:
116         /* Real error - exit here. */
117         TALLOC_FREE(val);
118         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 static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
126                                 files_struct *fsp,
127                                 DATA_BLOB *pblob)
128 {
129         int ret;
130         int saved_errno = 0;
131
132         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         become_root();
136         ret = SMB_VFS_FSETXATTR(fsp, XATTR_NTACL_NAME,
137                         pblob->data, pblob->length, 0);
138         if (ret) {
139                 saved_errno = errno;
140         }
141         unbecome_root();
142         if (ret) {
143                 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                 errno = saved_errno;
148                 return map_nt_error_from_unix(saved_errno);
149         }
150         return NT_STATUS_OK;
151 }
152
153 /*********************************************************************
154  Remove a Windows ACL - we're setting the underlying POSIX ACL.
155 *********************************************************************/
156
157 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         struct acl_common_fsp_ext *ext = (struct acl_common_fsp_ext *)
163                 VFS_FETCH_FSP_EXTENSION(handle, fsp);
164         int ret;
165
166         ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle,
167                                           fsp,
168                                           type,
169                                           theacl);
170         if (ret == -1) {
171                 return -1;
172         }
173
174         if (ext != NULL && ext->setting_nt_acl) {
175                 return 0;
176         }
177
178         become_root();
179         SMB_VFS_FREMOVEXATTR(fsp, XATTR_NTACL_NAME);
180         unbecome_root();
181
182         return 0;
183 }
184
185 static int connect_acl_xattr(struct vfs_handle_struct *handle,
186                                 const char *service,
187                                 const char *user)
188 {
189         const char *security_acl_xattr_name = NULL;
190         int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
191         bool ok;
192         struct acl_common_config *config = NULL;
193
194         if (ret < 0) {
195                 return ret;
196         }
197
198         ok = init_acl_common_config(handle, ACL_MODULE_NAME);
199         if (!ok) {
200                 DBG_ERR("init_acl_common_config failed\n");
201                 return -1;
202         }
203
204         /* Ensure we have the parameters correct if we're
205          * using this module. */
206         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         lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
212         lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
213         lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
214
215         SMB_VFS_HANDLE_GET_DATA(handle, config,
216                                 struct acl_common_config,
217                                 return -1);
218
219         if (config->ignore_system_acls) {
220                 mode_t create_mask = lp_create_mask(SNUM(handle->conn));
221                 char *create_mask_str = NULL;
222
223                 if ((create_mask & 0666) != 0666) {
224                         create_mask |= 0666;
225                         create_mask_str = talloc_asprintf(handle, "0%o",
226                                                           create_mask);
227                         if (create_mask_str == NULL) {
228                                 DBG_ERR("talloc_asprintf failed\n");
229                                 return -1;
230                         }
231
232                         DBG_NOTICE("setting 'create mask = %s'\n", create_mask_str);
233
234                         lp_do_parameter (SNUM(handle->conn),
235                                         "create mask", create_mask_str);
236
237                         TALLOC_FREE(create_mask_str);
238                 }
239
240                 DBG_NOTICE("setting 'directory mask = 0777', "
241                            "'store dos attributes = yes' and all "
242                            "'map ...' options to 'no'\n");
243
244                 lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
245                 lp_do_parameter(SNUM(handle->conn), "map archive", "no");
246                 lp_do_parameter(SNUM(handle->conn), "map hidden", "no");
247                 lp_do_parameter(SNUM(handle->conn), "map readonly", "no");
248                 lp_do_parameter(SNUM(handle->conn), "map system", "no");
249                 lp_do_parameter(SNUM(handle->conn), "store dos attributes",
250                                 "yes");
251         }
252
253         security_acl_xattr_name = lp_parm_const_string(SNUM(handle->conn),
254                                           "acl_xattr",
255                                           "security_acl_name",
256                                           NULL);
257         if (security_acl_xattr_name != NULL) {
258                 config->security_acl_xattr_name = talloc_strdup(config, security_acl_xattr_name);
259                 if (config->security_acl_xattr_name == NULL) {
260                         return -1;
261                 }
262         }
263
264         return 0;
265 }
266
267 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         if (flags & AT_REMOVEDIR) {
275                 ret = rmdir_acl_common(handle,
276                                 dirfsp,
277                                 smb_fname);
278         } else {
279                 ret = unlink_acl_common(handle,
280                                 dirfsp,
281                                 smb_fname,
282                                 flags);
283         }
284         return ret;
285 }
286
287 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         status = fget_nt_acl_common(fget_acl_blob, handle, fsp,
295                                    security_info, mem_ctx, ppdesc);
296         return status;
297 }
298
299 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         status = fset_nt_acl_common(fget_acl_blob, store_acl_blob_fsp,
306                                     ACL_MODULE_NAME,
307                                     handle, fsp, security_info_sent, psd);
308         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 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         struct tevent_req *req = NULL;
329         struct tevent_req *subreq = NULL;
330         struct acl_xattr_getxattrat_state *state = NULL;
331         struct acl_common_config *config = NULL;
332
333         SMB_VFS_HANDLE_GET_DATA(handle, config,
334                                 struct acl_common_config,
335                                 return NULL);
336
337         req = tevent_req_create(mem_ctx, &state,
338                                 struct acl_xattr_getxattrat_state);
339         if (req == NULL) {
340                 return NULL;
341         }
342
343         if (strequal(xattr_name, config->security_acl_xattr_name)) {
344                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
345                 return tevent_req_post(req, ev);
346         }
347         if (config->security_acl_xattr_name != NULL &&
348             strequal(xattr_name, XATTR_NTACL_NAME))
349         {
350                 xattr_name = config->security_acl_xattr_name;
351         }
352
353         subreq = SMB_VFS_NEXT_GETXATTRAT_SEND(state,
354                                               ev,
355                                               handle,
356                                               dirfsp,
357                                               smb_fname,
358                                               xattr_name,
359                                               alloc_hint);
360         if (tevent_req_nomem(subreq, req)) {
361                 return tevent_req_post(req, ev);
362         }
363         tevent_req_set_callback(subreq, acl_xattr_getxattrat_done, req);
364
365         return req;
366 }
367
368 static void acl_xattr_getxattrat_done(struct tevent_req *subreq)
369 {
370         struct tevent_req *req = tevent_req_callback_data(
371                 subreq, struct tevent_req);
372         struct acl_xattr_getxattrat_state *state = tevent_req_data(
373                 req, struct acl_xattr_getxattrat_state);
374
375         state->xattr_size = SMB_VFS_NEXT_GETXATTRAT_RECV(subreq,
376                                                          &state->aio_state,
377                                                          state,
378                                                          &state->xattr_value);
379         TALLOC_FREE(subreq);
380         if (state->xattr_size == -1) {
381                 tevent_req_error(req, state->aio_state.error);
382                 return;
383         }
384
385         tevent_req_done(req);
386 }
387
388 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         struct acl_xattr_getxattrat_state *state = tevent_req_data(
394                 req, struct acl_xattr_getxattrat_state);
395         ssize_t xattr_size;
396
397         if (tevent_req_is_unix_error(req, &aio_state->error)) {
398                 tevent_req_received(req);
399                 return -1;
400         }
401
402         *aio_state = state->aio_state;
403         xattr_size = state->xattr_size;
404         if (xattr_value != NULL) {
405                 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
406         }
407
408         tevent_req_received(req);
409         return xattr_size;
410 }
411
412 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         struct acl_common_config *config = NULL;
419
420         SMB_VFS_HANDLE_GET_DATA(handle, config,
421                                 struct acl_common_config,
422                                 return -1);
423
424         if (strequal(name, config->security_acl_xattr_name)) {
425                 errno = EACCES;
426                 return -1;
427         }
428         if (config->security_acl_xattr_name != NULL &&
429             strequal(name, XATTR_NTACL_NAME))
430         {
431                 name = config->security_acl_xattr_name;
432         }
433
434         return SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, value, size);
435 }
436
437 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         struct acl_common_config *config = NULL;
443         ssize_t size;
444         char *p = NULL;
445         size_t nlen, consumed;
446
447         SMB_VFS_HANDLE_GET_DATA(handle, config,
448                                 struct acl_common_config,
449                                 return -1);
450
451         size = SMB_VFS_NEXT_FLISTXATTR(handle, fsp, listbuf, bufsize);
452         if (size < 0) {
453                 return -1;
454         }
455
456         p = listbuf;
457         while (p - listbuf < size) {
458                 nlen = strlen(p) + 1;
459                 if (strequal(p, config->security_acl_xattr_name)) {
460                         break;
461                 }
462                 p += nlen;
463         }
464         if (p - listbuf >= size) {
465                 /* No match */
466                 return size;
467         }
468
469         /*
470          * The consumed helper variable just makes the math
471          * a bit more digestible.
472          */
473         consumed = p - listbuf;
474         if (consumed + nlen < size) {
475                 /* If not the last name move, else just skip */
476                 memmove(p, p + nlen, size - consumed - nlen);
477         }
478         size -= nlen;
479
480         return size;
481 }
482
483 static int acl_xattr_fremovexattr(struct vfs_handle_struct *handle,
484                                   struct files_struct *fsp,
485                                   const char *name)
486 {
487         struct acl_common_config *config = NULL;
488
489         SMB_VFS_HANDLE_GET_DATA(handle, config,
490                                 struct acl_common_config,
491                                 return -1);
492
493         if (strequal(name, config->security_acl_xattr_name)) {
494                 errno = EACCES;
495                 return -1;
496         }
497         if (config->security_acl_xattr_name != NULL &&
498             strequal(name, XATTR_NTACL_NAME))
499         {
500                 name = config->security_acl_xattr_name;
501         }
502
503         return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, name);
504 }
505
506 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         struct acl_common_config *config = NULL;
514
515         SMB_VFS_HANDLE_GET_DATA(handle, config,
516                                 struct acl_common_config,
517                                 return -1);
518
519         if (strequal(name, config->security_acl_xattr_name)) {
520                 errno = EACCES;
521                 return -1;
522         }
523         if (config->security_acl_xattr_name != NULL &&
524             strequal(name, XATTR_NTACL_NAME))
525         {
526                 name = config->security_acl_xattr_name;
527         }
528
529         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 NTSTATUS vfs_acl_xattr_init(TALLOC_CTX *ctx)
549 {
550         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "acl_xattr",
551                                 &vfs_acl_xattr_fns);
552 }