6390b67395b13924a5d8a36a3b3ed651e638d043
[kamenim/samba-autobuild/.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)
193 {
194         enum ndr_err_code ndr_err;
195         /* For now, ACLs are allocated on NULL */
196         struct smb_acl_t *acl = talloc(NULL, struct smb_acl_t);
197         if (!acl) {
198                 errno = ENOMEM;
199                 return NULL;
200         }
201
202         ndr_err = ndr_pull_struct_blob(blob, acl, acl, 
203                 (ndr_pull_flags_fn_t)ndr_pull_smb_acl_t);
204
205         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
206                 DEBUG(0, ("ndr_pull_acl_t failed: %s\n",
207                           ndr_errstr(ndr_err)));
208                 TALLOC_FREE(acl);
209                 return NULL;
210         }
211         return acl;
212 }
213
214 static DATA_BLOB fake_acls_acl2blob(TALLOC_CTX *mem_ctx, SMB_ACL_T acl)
215 {
216         enum ndr_err_code ndr_err;
217         DATA_BLOB blob;
218         ndr_err = ndr_push_struct_blob(&blob, mem_ctx, acl, 
219                 (ndr_push_flags_fn_t)ndr_push_smb_acl_t);
220
221         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
222                 DEBUG(0, ("ndr_push_acl_t failed: %s\n",
223                           ndr_errstr(ndr_err)));
224                 return data_blob_null;
225         }
226         return blob;
227 }
228
229 static SMB_ACL_T fake_acls_sys_acl_get_file(struct vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T type)
230 {
231         DATA_BLOB blob = data_blob_null;
232         ssize_t length;
233         const char *name = NULL;
234         struct smb_acl_t *acl = NULL;
235         TALLOC_CTX *frame = talloc_stackframe();
236         switch (type) {
237         case SMB_ACL_TYPE_ACCESS:
238                 name = FAKE_ACL_ACCESS_XATTR;
239                 break;
240         case SMB_ACL_TYPE_DEFAULT:
241                 name = FAKE_ACL_DEFAULT_XATTR;
242                 break;
243         }
244
245         do {
246                 blob.length += 1000;
247                 blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
248                 if (!blob.data) {
249                         errno = ENOMEM;
250                         TALLOC_FREE(frame);
251                         return NULL;
252                 }
253                 length = SMB_VFS_NEXT_GETXATTR(handle, path, name, blob.data, blob.length);
254                 blob.length = length;
255         } while (length == -1 && errno == ERANGE);
256         if (length == -1 && errno == ENOATTR) {
257                 TALLOC_FREE(frame);
258                 return NULL;
259         }
260         if (length != -1) {
261                 acl = fake_acls_blob2acl(&blob);
262         }
263         TALLOC_FREE(frame);
264         return acl;
265 }
266
267 static SMB_ACL_T fake_acls_sys_acl_get_fd(struct vfs_handle_struct *handle, files_struct *fsp)
268 {
269         DATA_BLOB blob = data_blob_null;
270         ssize_t length;
271         const char *name = FAKE_ACL_ACCESS_XATTR;
272         struct smb_acl_t *acl = NULL;
273         TALLOC_CTX *frame = talloc_stackframe();
274                 
275         do {
276                 blob.length += 1000;
277                 blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
278                 if (!blob.data) {
279                         errno = ENOMEM;
280                         TALLOC_FREE(frame);
281                         return NULL;
282                 }
283                 length = SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, blob.data, blob.length);
284                 blob.length = length;
285         } while (length == -1 && errno == ERANGE);
286         if (length == -1 && errno == ENOATTR) {
287                 TALLOC_FREE(frame);
288                 return NULL;
289         }
290         if (length != -1) {
291                 acl = fake_acls_blob2acl(&blob);
292         }
293         TALLOC_FREE(frame);
294         return acl;
295 }
296
297
298 static int fake_acls_sys_acl_blob_get_file(struct vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T type, TALLOC_CTX *mem_ctx, 
299                                            char **blob_description, DATA_BLOB *blob)
300 {
301         ssize_t length;
302         const char *name = NULL;
303         switch (type) {
304         case SMB_ACL_TYPE_ACCESS:
305                 name = FAKE_ACL_ACCESS_XATTR;
306                 break;
307         case SMB_ACL_TYPE_DEFAULT:
308                 name = FAKE_ACL_DEFAULT_XATTR;
309                 break;
310         }
311
312         *blob_description = talloc_strdup(mem_ctx, "fake_acls");
313         if (!*blob_description) {
314                 errno = ENOMEM;
315                 return -1;
316         }
317
318         *blob = data_blob_null;
319         do {
320                 blob->length += 1000;
321                 blob->data = talloc_realloc(mem_ctx, blob->data, uint8_t, blob->length);
322                 if (!blob->data) {
323                         errno = ENOMEM;
324                         return -1;
325                 }
326                 length = SMB_VFS_NEXT_GETXATTR(handle, path, name, blob->data, blob->length);
327                 blob->length = length;
328         } while (length == -1 && errno == ERANGE);
329         if (length == -1) {
330                 return -1;
331         }
332         return 0;
333 }
334
335 static int fake_acls_sys_acl_blob_get_fd(struct vfs_handle_struct *handle, files_struct *fsp, TALLOC_CTX *mem_ctx, 
336                                          char **blob_description, DATA_BLOB *blob)
337 {
338         ssize_t length;
339         const char *name = FAKE_ACL_ACCESS_XATTR;
340                 
341         *blob_description = talloc_strdup(mem_ctx, "fake_acls");
342         if (!*blob_description) {
343                 errno = ENOMEM;
344                 return -1;
345         }
346         *blob = data_blob_null;
347         do {
348                 blob->length += 1000;
349                 blob->data = talloc_realloc(mem_ctx, blob->data, uint8_t, blob->length);
350                 if (!blob->data) {
351                         errno = ENOMEM;
352                         return -1;
353                 }
354                 length = SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, blob->data, blob->length);
355                 blob->length = length;
356         } while (length == -1 && errno == ERANGE);
357         if (length == -1) {
358                 return -1;
359         }
360         return 0;
361 }
362
363 static int fake_acls_sys_acl_set_file(vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
364 {
365         int ret;
366         const char *name = NULL;
367         TALLOC_CTX *frame = talloc_stackframe();
368         DATA_BLOB blob = fake_acls_acl2blob(frame, theacl);
369         if (!blob.data) {
370                 DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n"));
371                 TALLOC_FREE(frame);
372                 errno = EINVAL;
373                 return -1;
374         }
375         switch (acltype) {
376         case SMB_ACL_TYPE_ACCESS:
377                 name = FAKE_ACL_ACCESS_XATTR;
378                 break;
379         case SMB_ACL_TYPE_DEFAULT:
380                 name = FAKE_ACL_DEFAULT_XATTR;
381                 break;
382         }
383         ret = SMB_VFS_NEXT_SETXATTR(handle, path, name, blob.data, blob.length, 0);
384         TALLOC_FREE(frame);
385         return ret;
386 }
387
388 static int fake_acls_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, SMB_ACL_T theacl)
389 {
390         int ret;
391         const char *name = FAKE_ACL_ACCESS_XATTR;
392         TALLOC_CTX *frame = talloc_stackframe();
393         DATA_BLOB blob = fake_acls_acl2blob(frame, theacl);
394         if (!blob.data) {
395                 DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n"));
396                 TALLOC_FREE(frame);
397                 errno = EINVAL;
398                 return -1;
399         }
400         ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, blob.data, blob.length, 0);
401         TALLOC_FREE(frame);
402         return ret;
403 }
404
405 static int fake_acls_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path)
406 {
407         int ret;
408         const char *name = FAKE_ACL_DEFAULT_XATTR;
409         TALLOC_CTX *frame = talloc_stackframe();
410         struct smb_filename *smb_fname = NULL;
411         NTSTATUS status = create_synthetic_smb_fname_split(frame, path, NULL,
412                                                   &smb_fname);
413         if (!NT_STATUS_IS_OK(status)) {
414                 errno = map_errno_from_nt_status(status);
415                 TALLOC_FREE(frame);
416                 return -1;
417         }
418
419         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
420         if (ret == -1) {
421                 TALLOC_FREE(frame);
422                 return -1;
423         }
424
425         if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
426                 errno = EINVAL;
427                 TALLOC_FREE(frame);
428                 return -1;
429         }
430
431         ret = SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
432         if (ret == -1 && errno == ENOATTR) {
433                 ret = 0;
434                 errno = 0;
435         }
436
437         TALLOC_FREE(frame);
438         return ret;
439 }
440
441 static int fake_acls_chown(vfs_handle_struct *handle,  const char *path, uid_t uid, gid_t gid)
442 {
443         int ret;
444         uint8_t id_buf[4];
445         if (uid != -1) {
446                 SIVAL(id_buf, 0, uid);
447                 ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_UID, id_buf, sizeof(id_buf), 0);
448                 if (ret != 0) {
449                         return ret;
450                 }
451         }
452         if (gid != -1) {
453                 SIVAL(id_buf, 0, gid);
454                 ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_GID, id_buf, sizeof(id_buf), 0);
455                 if (ret != 0) {
456                         return ret;
457                 }
458         }
459         return 0;
460 }
461
462 static int fake_acls_lchown(vfs_handle_struct *handle,  const char *path, uid_t uid, gid_t gid)
463 {
464         int ret;
465         uint8_t id_buf[4];
466         if (uid != -1) {
467                 /* This isn't quite right (calling setxattr not
468                  * lsetxattr), but for the test purposes of this
469                  * module (fake NT ACLs from windows clients), it is
470                  * close enough.  We removed the l*xattr functions
471                  * because linux doesn't support using them, but we
472                  * could fake them in xattr_tdb if we really wanted
473                  * to.
474                  */
475                 SIVAL(id_buf, 0, uid);
476                 ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_UID, id_buf, sizeof(id_buf), 0);
477                 if (ret != 0) {
478                         return ret;
479                 }
480         }
481         if (gid != -1) {
482                 SIVAL(id_buf, 0, gid);
483                 ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_GID, id_buf, sizeof(id_buf), 0);
484                 if (ret != 0) {
485                         return ret;
486                 }
487         }
488         return 0;
489 }
490
491 static int fake_acls_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
492 {
493         int ret;
494         uint8_t id_buf[4];
495         if (uid != -1) {
496                 SIVAL(id_buf, 0, uid);
497                 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, FAKE_UID, id_buf, sizeof(id_buf), 0);
498                 if (ret != 0) {
499                         return ret;
500                 }
501         }
502         if (gid != -1) {
503                 SIVAL(id_buf, 0, gid);
504                 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, FAKE_GID, id_buf, sizeof(id_buf), 0);
505                 if (ret != 0) {
506                         return ret;
507                 }
508         }
509         return 0;
510 }
511
512
513 static struct vfs_fn_pointers vfs_fake_acls_fns = {
514         .stat_fn = fake_acls_stat,
515         .lstat_fn = fake_acls_lstat,
516         .fstat_fn = fake_acls_fstat,
517         .sys_acl_get_file_fn = fake_acls_sys_acl_get_file,
518         .sys_acl_get_fd_fn = fake_acls_sys_acl_get_fd,
519         .sys_acl_blob_get_file_fn = fake_acls_sys_acl_blob_get_file,
520         .sys_acl_blob_get_fd_fn = fake_acls_sys_acl_blob_get_fd,
521         .sys_acl_set_file_fn = fake_acls_sys_acl_set_file,
522         .sys_acl_set_fd_fn = fake_acls_sys_acl_set_fd,
523         .sys_acl_delete_def_file_fn = fake_acls_sys_acl_delete_def_file,
524         .chown_fn = fake_acls_chown,
525         .lchown_fn = fake_acls_lchown,
526         .fchown_fn = fake_acls_fchown,
527         
528 };
529
530 NTSTATUS vfs_fake_acls_init(void);
531 NTSTATUS vfs_fake_acls_init(void)
532 {
533         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "fake_acls",
534                                 &vfs_fake_acls_fns);
535 }