s3:passdb: add sid_check_object_is_for_passdb()
[kai/samba.git] / source3 / modules / vfs_fake_acls.c
1 /* 
2  * Fake ACLs VFS module.  Implements passthrough operation of all VFS
3  * calls to disk functions, except for file ownership and ACLs, which
4  * are stored in xattrs.
5  *
6  * Copyright (C) Tim Potter, 1999-2000
7  * Copyright (C) Alexander Bokovoy, 2002
8  * Copyright (C) Andrew Bartlett, 2002,2012
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 3 of the License, or
13  * (at your option) any later version.
14  *  
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *  
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #include "includes.h"
25 #include "smbd/smbd.h"
26 #include "system/filesys.h"
27 #include "auth.h"
28 #include "librpc/gen_ndr/ndr_smb_acl.h"
29
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_VFS
32
33 #define FAKE_UID "system.fake_uid"
34 #define FAKE_GID "system.fake_gid"
35 #define FAKE_ACL_ACCESS_XATTR "system.fake_access_acl"
36 #define FAKE_ACL_DEFAULT_XATTR "system.fake_default_acl"
37
38 static int fake_acls_uid(vfs_handle_struct *handle,
39                          const char *path,
40                          uid_t *uid)
41 {
42         ssize_t size;
43         uint8_t uid_buf[4];
44         size = SMB_VFS_NEXT_GETXATTR(handle, path, FAKE_UID, uid_buf, sizeof(uid_buf));
45         if (size == -1 && errno == ENOATTR) {
46                 return 0;
47         }
48         if (size != 4) {
49                 return -1;
50         }
51         *uid = IVAL(uid_buf, 0);
52         return 0;
53 }
54
55 static int fake_acls_gid(vfs_handle_struct *handle,
56                          const char *path,
57                          uid_t *gid)
58 {
59         ssize_t size;
60         uint8_t gid_buf[4];
61
62         size = SMB_VFS_NEXT_GETXATTR(handle, path, FAKE_GID, gid_buf, sizeof(gid_buf));
63         if (size == -1 && errno == ENOATTR) {
64                 return 0;
65         }
66         if (size != 4) {
67                 return -1;
68         }
69         *gid = IVAL(gid_buf, 0);
70         return 0;
71 }
72
73 static int fake_acls_fuid(vfs_handle_struct *handle,
74                            files_struct *fsp,
75                            uid_t *uid)
76 {
77         ssize_t size;
78         uint8_t uid_buf[4];
79
80         size = SMB_VFS_NEXT_FGETXATTR(handle, fsp, FAKE_UID, uid_buf, sizeof(uid_buf));
81         if (size == -1 && errno == ENOATTR) {
82                 return 0;
83         }
84         if (size != 4) {
85                 return -1;
86         }
87         *uid = IVAL(uid_buf, 0);
88         return 0;
89 }
90
91 static int fake_acls_fgid(vfs_handle_struct *handle,
92                            files_struct *fsp,
93                           uid_t *gid)
94 {
95         ssize_t size;
96         uint8_t gid_buf[4];
97
98         size = SMB_VFS_NEXT_FGETXATTR(handle, fsp, FAKE_GID, gid_buf, sizeof(gid_buf));
99         if (size == -1 && errno == ENOATTR) {
100                 return 0;
101         }
102         if (size != 4) {
103                 return -1;
104         }
105         *gid = IVAL(gid_buf, 0);
106         return 0;
107 }
108
109 static int fake_acls_stat(vfs_handle_struct *handle,
110                            struct smb_filename *smb_fname)
111 {
112         int ret = -1;
113
114         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
115         if (ret == 0) {
116                 TALLOC_CTX *frame = talloc_stackframe();
117                 char *path;
118                 NTSTATUS status;
119                 status = get_full_smb_filename(frame, smb_fname, &path);
120                 if (!NT_STATUS_IS_OK(status)) {
121                         errno = map_errno_from_nt_status(status);
122                         TALLOC_FREE(frame);
123                         return -1;
124                 }
125                 
126                 ret = fake_acls_uid(handle, path, &smb_fname->st.st_ex_uid);
127                 if (ret != 0) {
128                         TALLOC_FREE(frame);
129                         return ret;
130                 }
131                 ret = fake_acls_gid(handle, path, &smb_fname->st.st_ex_gid);
132                 if (ret != 0) {
133                         TALLOC_FREE(frame);
134                         return ret;
135                 }
136                 TALLOC_FREE(frame);
137         }
138
139         return ret;
140 }
141
142 static int fake_acls_lstat(vfs_handle_struct *handle,
143                            struct smb_filename *smb_fname)
144 {
145         int ret = -1;
146
147         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
148         if (ret == 0) {
149                 TALLOC_CTX *frame = talloc_stackframe();
150                 char *path;
151                 NTSTATUS status;
152                 status = get_full_smb_filename(frame, smb_fname, &path);
153                 if (!NT_STATUS_IS_OK(status)) {
154                         errno = map_errno_from_nt_status(status);
155                         TALLOC_FREE(frame);
156                         return -1;
157                 }
158
159                 /* This isn't quite right (calling getxattr not
160                  * lgetxattr), but for the test purposes of this
161                  * module (fake NT ACLs from windows clients), it is
162                  * close enough.  We removed the l*xattr functions
163                  * because linux doesn't support using them, but we
164                  * could fake them in xattr_tdb if we really wanted
165                  * to.  We ignore errors because the link might not point anywhere */
166                 fake_acls_uid(handle, path, &smb_fname->st.st_ex_uid);
167                 fake_acls_gid(handle, path, &smb_fname->st.st_ex_gid);
168                 TALLOC_FREE(frame);
169         }
170
171         return ret;
172 }
173
174 static int fake_acls_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
175 {
176         int ret = -1;
177
178         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
179         if (ret == 0) {
180                 ret = fake_acls_fuid(handle, fsp, &sbuf->st_ex_uid);
181                 if (ret != 0) {
182                         return ret;
183                 }
184                 ret = fake_acls_fgid(handle, fsp, &sbuf->st_ex_gid);
185                 if (ret != 0) {
186                         return ret;
187                 }
188         }
189         return ret;
190 }
191
192 static SMB_ACL_T fake_acls_blob2acl(DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
193 {
194         enum ndr_err_code ndr_err;
195         struct smb_acl_t *acl = talloc(mem_ctx, struct smb_acl_t);
196         if (!acl) {
197                 errno = ENOMEM;
198                 return NULL;
199         }
200
201         ndr_err = ndr_pull_struct_blob(blob, acl, acl, 
202                 (ndr_pull_flags_fn_t)ndr_pull_smb_acl_t);
203
204         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
205                 DEBUG(0, ("ndr_pull_acl_t failed: %s\n",
206                           ndr_errstr(ndr_err)));
207                 TALLOC_FREE(acl);
208                 return NULL;
209         }
210         return acl;
211 }
212
213 static DATA_BLOB fake_acls_acl2blob(TALLOC_CTX *mem_ctx, SMB_ACL_T acl)
214 {
215         enum ndr_err_code ndr_err;
216         DATA_BLOB blob;
217         ndr_err = ndr_push_struct_blob(&blob, mem_ctx, acl, 
218                 (ndr_push_flags_fn_t)ndr_push_smb_acl_t);
219
220         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
221                 DEBUG(0, ("ndr_push_acl_t failed: %s\n",
222                           ndr_errstr(ndr_err)));
223                 return data_blob_null;
224         }
225         return blob;
226 }
227
228 static SMB_ACL_T fake_acls_sys_acl_get_file(struct vfs_handle_struct *handle,
229                                             const char *path,
230                                             SMB_ACL_TYPE_T type,
231                                             TALLOC_CTX *mem_ctx)
232 {
233         DATA_BLOB blob = data_blob_null;
234         ssize_t length;
235         const char *name = NULL;
236         struct smb_acl_t *acl = NULL;
237         TALLOC_CTX *frame = talloc_stackframe();
238         switch (type) {
239         case SMB_ACL_TYPE_ACCESS:
240                 name = FAKE_ACL_ACCESS_XATTR;
241                 break;
242         case SMB_ACL_TYPE_DEFAULT:
243                 name = FAKE_ACL_DEFAULT_XATTR;
244                 break;
245         }
246
247         do {
248                 blob.length += 1000;
249                 blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
250                 if (!blob.data) {
251                         errno = ENOMEM;
252                         TALLOC_FREE(frame);
253                         return NULL;
254                 }
255                 length = SMB_VFS_NEXT_GETXATTR(handle, path, name, blob.data, blob.length);
256                 blob.length = length;
257         } while (length == -1 && errno == ERANGE);
258         if (length == -1 && errno == ENOATTR) {
259                 TALLOC_FREE(frame);
260                 return NULL;
261         }
262         if (length != -1) {
263                 acl = fake_acls_blob2acl(&blob, mem_ctx);
264         }
265         TALLOC_FREE(frame);
266         return acl;
267 }
268
269 static SMB_ACL_T fake_acls_sys_acl_get_fd(struct vfs_handle_struct *handle,
270                                           files_struct *fsp,
271                                           TALLOC_CTX *mem_ctx)
272 {
273         DATA_BLOB blob = data_blob_null;
274         ssize_t length;
275         const char *name = FAKE_ACL_ACCESS_XATTR;
276         struct smb_acl_t *acl = NULL;
277         TALLOC_CTX *frame = talloc_stackframe();
278                 
279         do {
280                 blob.length += 1000;
281                 blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
282                 if (!blob.data) {
283                         errno = ENOMEM;
284                         TALLOC_FREE(frame);
285                         return NULL;
286                 }
287                 length = SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, blob.data, blob.length);
288                 blob.length = length;
289         } while (length == -1 && errno == ERANGE);
290         if (length == -1 && errno == ENOATTR) {
291                 TALLOC_FREE(frame);
292                 return NULL;
293         }
294         if (length != -1) {
295                 acl = fake_acls_blob2acl(&blob, mem_ctx);
296         }
297         TALLOC_FREE(frame);
298         return acl;
299 }
300
301
302 static int fake_acls_sys_acl_set_file(vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
303 {
304         int ret;
305         const char *name = NULL;
306         TALLOC_CTX *frame = talloc_stackframe();
307         DATA_BLOB blob = fake_acls_acl2blob(frame, theacl);
308         if (!blob.data) {
309                 DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n"));
310                 TALLOC_FREE(frame);
311                 errno = EINVAL;
312                 return -1;
313         }
314         switch (acltype) {
315         case SMB_ACL_TYPE_ACCESS:
316                 name = FAKE_ACL_ACCESS_XATTR;
317                 break;
318         case SMB_ACL_TYPE_DEFAULT:
319                 name = FAKE_ACL_DEFAULT_XATTR;
320                 break;
321         }
322         ret = SMB_VFS_NEXT_SETXATTR(handle, path, name, blob.data, blob.length, 0);
323         TALLOC_FREE(frame);
324         return ret;
325 }
326
327 static int fake_acls_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, SMB_ACL_T theacl)
328 {
329         int ret;
330         const char *name = FAKE_ACL_ACCESS_XATTR;
331         TALLOC_CTX *frame = talloc_stackframe();
332         DATA_BLOB blob = fake_acls_acl2blob(frame, theacl);
333         if (!blob.data) {
334                 DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n"));
335                 TALLOC_FREE(frame);
336                 errno = EINVAL;
337                 return -1;
338         }
339         ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, blob.data, blob.length, 0);
340         TALLOC_FREE(frame);
341         return ret;
342 }
343
344 static int fake_acls_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path)
345 {
346         int ret;
347         const char *name = FAKE_ACL_DEFAULT_XATTR;
348         TALLOC_CTX *frame = talloc_stackframe();
349         struct smb_filename *smb_fname = NULL;
350         NTSTATUS status = create_synthetic_smb_fname_split(frame, path, NULL,
351                                                   &smb_fname);
352         if (!NT_STATUS_IS_OK(status)) {
353                 errno = map_errno_from_nt_status(status);
354                 TALLOC_FREE(frame);
355                 return -1;
356         }
357
358         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
359         if (ret == -1) {
360                 TALLOC_FREE(frame);
361                 return -1;
362         }
363
364         if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
365                 errno = EINVAL;
366                 TALLOC_FREE(frame);
367                 return -1;
368         }
369
370         ret = SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
371         if (ret == -1 && errno == ENOATTR) {
372                 ret = 0;
373                 errno = 0;
374         }
375
376         TALLOC_FREE(frame);
377         return ret;
378 }
379
380 static int fake_acls_chown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
381 {
382         int ret;
383         uint8_t id_buf[4];
384         if (uid != -1) {
385                 SIVAL(id_buf, 0, uid);
386                 ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_UID, id_buf, sizeof(id_buf), 0);
387                 if (ret != 0) {
388                         return ret;
389                 }
390         }
391         if (gid != -1) {
392                 SIVAL(id_buf, 0, gid);
393                 ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_GID, id_buf, sizeof(id_buf), 0);
394                 if (ret != 0) {
395                         return ret;
396                 }
397         }
398         return 0;
399 }
400
401 static int fake_acls_lchown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
402 {
403         int ret;
404         uint8_t id_buf[4];
405         if (uid != -1) {
406                 /* This isn't quite right (calling setxattr not
407                  * lsetxattr), but for the test purposes of this
408                  * module (fake NT ACLs from windows clients), it is
409                  * close enough.  We removed the l*xattr functions
410                  * because linux doesn't support using them, but we
411                  * could fake them in xattr_tdb if we really wanted
412                  * to.
413                  */
414                 SIVAL(id_buf, 0, uid);
415                 ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_UID, id_buf, sizeof(id_buf), 0);
416                 if (ret != 0) {
417                         return ret;
418                 }
419         }
420         if (gid != -1) {
421                 SIVAL(id_buf, 0, gid);
422                 ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_GID, id_buf, sizeof(id_buf), 0);
423                 if (ret != 0) {
424                         return ret;
425                 }
426         }
427         return 0;
428 }
429
430 static int fake_acls_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
431 {
432         int ret;
433         uint8_t id_buf[4];
434         if (uid != -1) {
435                 SIVAL(id_buf, 0, uid);
436                 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, FAKE_UID, id_buf, sizeof(id_buf), 0);
437                 if (ret != 0) {
438                         return ret;
439                 }
440         }
441         if (gid != -1) {
442                 SIVAL(id_buf, 0, gid);
443                 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, FAKE_GID, id_buf, sizeof(id_buf), 0);
444                 if (ret != 0) {
445                         return ret;
446                 }
447         }
448         return 0;
449 }
450
451
452 static struct vfs_fn_pointers vfs_fake_acls_fns = {
453         .stat_fn = fake_acls_stat,
454         .lstat_fn = fake_acls_lstat,
455         .fstat_fn = fake_acls_fstat,
456         .sys_acl_get_file_fn = fake_acls_sys_acl_get_file,
457         .sys_acl_get_fd_fn = fake_acls_sys_acl_get_fd,
458         .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
459         .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
460         .sys_acl_set_file_fn = fake_acls_sys_acl_set_file,
461         .sys_acl_set_fd_fn = fake_acls_sys_acl_set_fd,
462         .sys_acl_delete_def_file_fn = fake_acls_sys_acl_delete_def_file,
463         .chown_fn = fake_acls_chown,
464         .lchown_fn = fake_acls_lchown,
465         .fchown_fn = fake_acls_fchown,
466         
467 };
468
469 NTSTATUS vfs_fake_acls_init(void);
470 NTSTATUS vfs_fake_acls_init(void)
471 {
472         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "fake_acls",
473                                 &vfs_fake_acls_fns);
474 }