Prepare the zfs acl module for the api change in get_nt_acl().
[ira/wip.git] / source3 / modules / vfs_zfsacl.c
1 /*
2  * Convert ZFS/NFSv4 acls to NT acls and vice versa.
3  *
4  * Copyright (C) Jiri Sasek, 2007
5  * based on the foobar.c module which is copyrighted by Volker Lendecke
6  *
7  * Many thanks to Axel Apitz for help to fix the special ace's handling
8  * issues.
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
25 #include "includes.h"
26 #include "nfs4_acls.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_VFS
30
31 #define ZFSACL_MODULE_NAME "zfsacl"
32
33 /* zfs_get_nt_acl()
34  * read the local file's acls and return it in NT form
35  * using the NFSv4 format conversion
36  */
37 static NTSTATUS zfs_get_nt_acl_common(const char *name,
38                                       uint32 security_info,
39                                       SMB4ACL_T **ppacl)
40 {
41         int naces, i;
42         ace_t *acebuf;
43         SMB4ACL_T *pacl;
44         TALLOC_CTX      *mem_ctx;
45
46         /* read the number of file aces */
47         if((naces = acl(name, ACE_GETACLCNT, 0, NULL)) == -1) {
48                 if(errno == ENOSYS) {
49                         DEBUG(9, ("acl(ACE_GETACLCNT, %s): Operation is not supported on the filesystem where the file reside"));
50                 } else {
51                         DEBUG(9, ("acl(ACE_GETACLCNT, %s): %s ", name,
52                                         strerror(errno)));
53                 }
54                 return map_nt_error_from_unix(errno);
55         }
56         /* allocate the field of ZFS aces */
57         mem_ctx = talloc_tos();
58         acebuf = (ace_t *) talloc_size(mem_ctx, sizeof(ace_t)*naces);
59         if(acebuf == NULL) {
60                 return NT_STATUS_NO_MEMORY;
61         }
62         /* read the aces into the field */
63         if(acl(name, ACE_GETACL, naces, acebuf) < 0) {
64                 DEBUG(9, ("acl(ACE_GETACL, %s): %s ", name,
65                                 strerror(errno)));
66                 return map_nt_error_from_unix(errno);
67         }
68         /* create SMB4ACL data */
69         if((pacl = smb_create_smb4acl()) == NULL) {
70                 return NT_STATUS_NO_MEMORY;
71         }
72         for(i=0; i<naces; i++) {
73                 SMB_ACE4PROP_T aceprop;
74
75                 aceprop.aceType  = (uint32) acebuf[i].a_type;
76                 aceprop.aceFlags = (uint32) acebuf[i].a_flags;
77                 aceprop.aceMask  = (uint32) acebuf[i].a_access_mask;
78                 aceprop.who.id   = (uint32) acebuf[i].a_who;
79
80                 if(aceprop.aceFlags & ACE_OWNER) {
81                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
82                         aceprop.who.special_id = SMB_ACE4_WHO_OWNER;
83                 } else if(aceprop.aceFlags & ACE_GROUP) {
84                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
85                         aceprop.who.special_id = SMB_ACE4_WHO_GROUP;
86                 } else if(aceprop.aceFlags & ACE_EVERYONE) {
87                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
88                         aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE;
89                 } else {
90                         aceprop.flags   = 0;
91                 }
92                 if(smb_add_ace4(pacl, &aceprop) == NULL)
93                         return NT_STATUS_NO_MEMORY;
94         }
95
96         *ppacl = pacl;
97         return NT_STATUS_OK;
98 }
99
100 /* call-back function processing the NT acl -> ZFS acl using NFSv4 conv. */
101 static bool zfs_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
102 {
103         int naces = smb_get_naces(smbacl), i;
104         ace_t *acebuf;
105         SMB4ACE_T *smbace;
106         TALLOC_CTX      *mem_ctx;
107
108         /* allocate the field of ZFS aces */
109         mem_ctx = talloc_tos();
110         acebuf = (ace_t *) talloc_size(mem_ctx, sizeof(ace_t)*naces);
111         if(acebuf == NULL) {
112                 errno = ENOMEM;
113                 return False;
114         }
115         /* handle all aces */
116         for(smbace = smb_first_ace4(smbacl), i = 0;
117                         smbace!=NULL;
118                         smbace = smb_next_ace4(smbace), i++) {
119                 SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
120
121                 acebuf[i].a_type        = aceprop->aceType;
122                 acebuf[i].a_flags       = aceprop->aceFlags;
123                 acebuf[i].a_access_mask = aceprop->aceMask;
124                 acebuf[i].a_who         = aceprop->who.id;
125                 if(aceprop->flags & SMB_ACE4_ID_SPECIAL) {
126                         switch(aceprop->who.special_id) {
127                         case SMB_ACE4_WHO_EVERYONE:
128                                 acebuf[i].a_flags |= ACE_EVERYONE;
129                                 break;
130                         case SMB_ACE4_WHO_OWNER:
131                                 acebuf[i].a_flags |= ACE_OWNER;
132                                 break;
133                         case SMB_ACE4_WHO_GROUP:
134                                 acebuf[i].a_flags |= ACE_GROUP;
135                                 break;
136                         default:
137                                 DEBUG(8, ("unsupported special_id %d\n", \
138                                         aceprop->who.special_id));
139                                 continue; /* don't add it !!! */
140                         }
141                 }
142         }
143         SMB_ASSERT(i == naces);
144
145         /* store acl */
146         if(acl(fsp->fsp_name, ACE_SETACL, naces, acebuf)) {
147                 if(errno == ENOSYS) {
148                         DEBUG(9, ("acl(ACE_SETACL, %s): Operation is not supported on the filesystem where the file reside"));
149                 } else {
150                         DEBUG(9, ("acl(ACE_SETACL, %s): %s ", fsp->fsp_name,
151                                         strerror(errno)));
152                 }
153                 return 0;
154         }
155
156         return True;
157 }
158
159 /* zfs_set_nt_acl()
160  * set the local file's acls obtaining it in NT form
161  * using the NFSv4 format conversion
162  */
163 static NTSTATUS zfs_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
164                            uint32 security_info_sent,
165                            struct security_descriptor *psd)
166 {
167         return smb_set_nt_acl_nfs4(fsp, security_info_sent, psd,
168                         zfs_process_smbacl);
169 }
170
171 static NTSTATUS zfsacl_fget_nt_acl(struct vfs_handle_struct *handle,
172                                  struct files_struct *fsp,
173                                  int fd,  uint32 security_info,
174                                  struct security_descriptor **ppdesc)
175 {
176         SMB4ACL_T *pacl;
177         NTSTATUS status;
178
179         status = zfs_get_nt_acl_common(fsp->fsp_name, security_info, &pacl);
180         if (!NT_STATUS_IS_OK(status)) {
181                 return status;
182         }
183
184         return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
185 }
186
187 static NTSTATUS zfsacl_get_nt_acl(struct vfs_handle_struct *handle,
188                                 struct files_struct *fsp,
189                                 const char *name,  uint32 security_info,
190                                 struct security_descriptor **ppdesc)
191 {
192         SMB4ACL_T *pacl;
193         NTSTATUS status;
194
195         status = zfs_get_nt_acl_common(name, security_info, &pacl);
196         if (!NT_STATUS_IS_OK(status)) {
197                 return status;
198         }
199
200         return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc,
201                                    pacl);
202 }
203
204 static NTSTATUS zfsacl_fset_nt_acl(vfs_handle_struct *handle,
205                          files_struct *fsp,
206                          int fd, uint32 security_info_sent,
207                          SEC_DESC *psd)
208 {
209         return zfs_set_nt_acl(handle, fsp, security_info_sent, psd);
210 }
211
212 static NTSTATUS zfsacl_set_nt_acl(vfs_handle_struct *handle,
213                        files_struct *fsp,
214                        const char *name, uint32 security_info_sent,
215                        SEC_DESC *psd)
216 {
217         return zfs_set_nt_acl(handle, fsp, security_info_sent, psd);
218 }
219
220 /* VFS operations structure */
221
222 static vfs_op_tuple zfsacl_ops[] = {    
223         {SMB_VFS_OP(zfsacl_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL,
224          SMB_VFS_LAYER_OPAQUE},
225         {SMB_VFS_OP(zfsacl_get_nt_acl), SMB_VFS_OP_GET_NT_ACL,
226          SMB_VFS_LAYER_OPAQUE},
227         {SMB_VFS_OP(zfsacl_fset_nt_acl), SMB_VFS_OP_FSET_NT_ACL,
228          SMB_VFS_LAYER_OPAQUE},
229         {SMB_VFS_OP(zfsacl_set_nt_acl), SMB_VFS_OP_SET_NT_ACL,
230          SMB_VFS_LAYER_OPAQUE},
231         {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
232 };
233
234 /* != 0 if this module will be compiled as static */
235
236 #define STATIC 0
237
238 #if STATIC
239 NTSTATUS vfs_zfsacl_init(void);
240 #else
241 NTSTATUS init_module(void);
242 #endif
243
244 NTSTATUS
245 #if STATIC
246         vfs_zfsacl_init
247 #else
248         init_module
249 #endif
250                 (void)
251 {
252         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "zfsacl",
253                                 zfsacl_ops);
254 }