s3:winbind: remove the method SET_MAPPING from winbind's API
[ira/wip.git] / source3 / modules / vfs_posixacl.c
1 /*
2    Unix SMB/Netbios implementation.
3    VFS module to get and set posix acls
4    Copyright (C) Volker Lendecke 2006
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21
22
23 /* prototypes for static functions first - for clarity */
24
25 static bool smb_ace_to_internal(acl_entry_t posix_ace,
26                                 struct smb_acl_entry *ace);
27 static struct smb_acl_t *smb_acl_to_internal(acl_t acl);
28 static int smb_acl_set_mode(acl_entry_t entry, SMB_ACL_PERM_T perm);
29 static acl_t smb_acl_to_posix(const struct smb_acl_t *acl);
30
31
32 /* public functions - the api */
33
34 SMB_ACL_T posixacl_sys_acl_get_file(vfs_handle_struct *handle,
35                                     const char *path_p,
36                                     SMB_ACL_TYPE_T type)
37 {
38         struct smb_acl_t *result;
39         acl_type_t acl_type;
40         acl_t acl;
41
42         switch(type) {
43         case SMB_ACL_TYPE_ACCESS:
44                 acl_type = ACL_TYPE_ACCESS;
45                 break;
46         case SMB_ACL_TYPE_DEFAULT:
47                 acl_type = ACL_TYPE_DEFAULT;
48                 break;
49         default:
50                 errno = EINVAL;
51                 return NULL;
52         }
53
54         acl = acl_get_file(path_p, acl_type);
55
56         if (acl == NULL) {
57                 return NULL;
58         }
59
60         result = smb_acl_to_internal(acl);
61         acl_free(acl);
62         return result;
63 }
64
65 SMB_ACL_T posixacl_sys_acl_get_fd(vfs_handle_struct *handle,
66                                   files_struct *fsp)
67 {
68         struct smb_acl_t *result;
69         acl_t acl = acl_get_fd(fsp->fh->fd);
70
71         if (acl == NULL) {
72                 return NULL;
73         }
74
75         result = smb_acl_to_internal(acl);
76         acl_free(acl);
77         return result;
78 }
79
80 int posixacl_sys_acl_set_file(vfs_handle_struct *handle,
81                               const char *name,
82                               SMB_ACL_TYPE_T type,
83                               SMB_ACL_T theacl)
84 {
85         int res;
86         acl_type_t acl_type;
87         acl_t acl;
88
89         DEBUG(10, ("Calling acl_set_file: %s, %d\n", name, type));
90
91         switch(type) {
92         case SMB_ACL_TYPE_ACCESS:
93                 acl_type = ACL_TYPE_ACCESS;
94                 break;
95         case SMB_ACL_TYPE_DEFAULT:
96                 acl_type = ACL_TYPE_DEFAULT;
97                 break;
98         default:
99                 errno = EINVAL;
100                 return -1;
101         }
102
103         if ((acl = smb_acl_to_posix(theacl)) == NULL) {
104                 return -1;
105         }
106         res = acl_set_file(name, acl_type, acl);
107         if (res != 0) {
108                 DEBUG(10, ("acl_set_file failed: %s\n", strerror(errno)));
109         }
110         acl_free(acl);
111         return res;
112 }
113
114 int posixacl_sys_acl_set_fd(vfs_handle_struct *handle,
115                             files_struct *fsp,
116                             SMB_ACL_T theacl)
117 {
118         int res;
119         acl_t acl = smb_acl_to_posix(theacl);
120         if (acl == NULL) {
121                 return -1;
122         }
123         res =  acl_set_fd(fsp->fh->fd, acl);
124         acl_free(acl);
125         return res;
126 }
127
128 int posixacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
129                                      const char *path)
130 {
131         return acl_delete_def_file(path);
132 }
133
134
135 /* private functions */
136
137 static bool smb_ace_to_internal(acl_entry_t posix_ace,
138                                 struct smb_acl_entry *ace)
139 {
140         acl_tag_t tag;
141         acl_permset_t permset;
142
143         if (acl_get_tag_type(posix_ace, &tag) != 0) {
144                 DEBUG(0, ("smb_acl_get_tag_type failed\n"));
145                 return False;
146         }
147
148         switch(tag) {
149         case ACL_USER:
150                 ace->a_type = SMB_ACL_USER;
151                 break;
152         case ACL_USER_OBJ:
153                 ace->a_type = SMB_ACL_USER_OBJ;
154                 break;
155         case ACL_GROUP:
156                 ace->a_type = SMB_ACL_GROUP;
157                 break;
158         case ACL_GROUP_OBJ:
159                 ace->a_type = SMB_ACL_GROUP_OBJ;
160                 break;
161         case ACL_OTHER:
162                 ace->a_type = SMB_ACL_OTHER;
163                 break;
164         case ACL_MASK:
165                 ace->a_type = SMB_ACL_MASK;
166                 break;
167         default:
168                 DEBUG(0, ("unknown tag type %d\n", (unsigned int)tag));
169                 return False;
170         }
171         switch(ace->a_type) {
172         case SMB_ACL_USER: {
173                 uid_t *puid = (uid_t *)acl_get_qualifier(posix_ace);
174                 if (puid == NULL) {
175                         DEBUG(0, ("smb_acl_get_qualifier failed\n"));
176                         return False;
177                 }
178                 ace->uid = *puid;
179                 acl_free(puid);
180                 break;
181         }
182                 
183         case SMB_ACL_GROUP: {
184                 gid_t *pgid = (uid_t *)acl_get_qualifier(posix_ace);
185                 if (pgid == NULL) {
186                         DEBUG(0, ("smb_acl_get_qualifier failed\n"));
187                         return False;
188                 }
189                 ace->gid = *pgid;
190                 acl_free(pgid);
191                 break;
192         }
193         default:
194                 break;
195         }
196         if (acl_get_permset(posix_ace, &permset) != 0) {
197                 DEBUG(0, ("smb_acl_get_mode failed\n"));
198                 return False;
199         }
200         ace->a_perm = 0;
201 #ifdef HAVE_ACL_GET_PERM_NP
202         ace->a_perm |= (acl_get_perm_np(permset, ACL_READ) ? SMB_ACL_READ : 0);
203         ace->a_perm |= (acl_get_perm_np(permset, ACL_WRITE) ? SMB_ACL_WRITE : 0);
204         ace->a_perm |= (acl_get_perm_np(permset, ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
205 #else
206         ace->a_perm |= (acl_get_perm(permset, ACL_READ) ? SMB_ACL_READ : 0);
207         ace->a_perm |= (acl_get_perm(permset, ACL_WRITE) ? SMB_ACL_WRITE : 0);
208         ace->a_perm |= (acl_get_perm(permset, ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
209 #endif
210         return True;
211 }
212
213 static struct smb_acl_t *smb_acl_to_internal(acl_t acl)
214 {
215         struct smb_acl_t *result = SMB_MALLOC_P(struct smb_acl_t);
216         int entry_id = ACL_FIRST_ENTRY;
217         acl_entry_t e;
218         if (result == NULL) {
219                 return NULL;
220         }
221         ZERO_STRUCTP(result);
222         while (acl_get_entry(acl, entry_id, &e) == 1) {
223
224                 entry_id = ACL_NEXT_ENTRY;
225
226                 result = (struct smb_acl_t *)SMB_REALLOC(
227                         result, sizeof(struct smb_acl_t) +
228                         (sizeof(struct smb_acl_entry) * (result->count+1)));
229                 if (result == NULL) {
230                         DEBUG(0, ("SMB_REALLOC failed\n"));
231                         errno = ENOMEM;
232                         return NULL;
233                 }
234
235                 if (!smb_ace_to_internal(e, &result->acl[result->count])) {
236                         SAFE_FREE(result);
237                         return NULL;
238                 }
239
240                 result->count += 1;
241         }
242         return result;
243 }
244
245 static int smb_acl_set_mode(acl_entry_t entry, SMB_ACL_PERM_T perm)
246 {
247         int ret;
248         acl_permset_t permset;
249
250         if ((ret = acl_get_permset(entry, &permset)) != 0) {
251                 return ret;
252         }
253         if ((ret = acl_clear_perms(permset)) != 0) {
254                 return ret;
255         }
256         if ((perm & SMB_ACL_READ) &&
257             ((ret = acl_add_perm(permset, ACL_READ)) != 0)) {
258                 return ret;
259         }
260         if ((perm & SMB_ACL_WRITE) &&
261             ((ret = acl_add_perm(permset, ACL_WRITE)) != 0)) {
262                 return ret;
263         }
264         if ((perm & SMB_ACL_EXECUTE) &&
265             ((ret = acl_add_perm(permset, ACL_EXECUTE)) != 0)) {
266                 return ret;
267         }
268         return acl_set_permset(entry, permset);
269 }
270
271 static acl_t smb_acl_to_posix(const struct smb_acl_t *acl)
272 {
273         acl_t result;
274         int i;
275
276         result = acl_init(acl->count);
277         if (result == NULL) {
278                 DEBUG(10, ("acl_init failed\n"));
279                 return NULL;
280         }
281
282         for (i=0; i<acl->count; i++) {
283                 const struct smb_acl_entry *entry = &acl->acl[i];
284                 acl_entry_t e;
285                 acl_tag_t tag;
286
287                 if (acl_create_entry(&result, &e) != 0) {
288                         DEBUG(1, ("acl_create_entry failed: %s\n",
289                                   strerror(errno)));
290                         goto fail;
291                 }
292
293                 switch (entry->a_type) {
294                 case SMB_ACL_USER:
295                         tag = ACL_USER;
296                         break;
297                 case SMB_ACL_USER_OBJ:
298                         tag = ACL_USER_OBJ;
299                         break;
300                 case SMB_ACL_GROUP:
301                         tag = ACL_GROUP;
302                         break;
303                 case SMB_ACL_GROUP_OBJ:
304                         tag = ACL_GROUP_OBJ;
305                         break;
306                 case SMB_ACL_OTHER:
307                         tag = ACL_OTHER;
308                         break;
309                 case SMB_ACL_MASK:
310                         tag = ACL_MASK;
311                         break;
312                 default:
313                         DEBUG(1, ("Unknown tag value %d\n", entry->a_type));
314                         goto fail;
315                 }
316
317                 if (acl_set_tag_type(e, tag) != 0) {
318                         DEBUG(10, ("acl_set_tag_type(%d) failed: %s\n",
319                                    tag, strerror(errno)));
320                         goto fail;
321                 }
322
323                 switch (entry->a_type) {
324                 case SMB_ACL_USER:
325                         if (acl_set_qualifier(e, &entry->uid) != 0) {
326                                 DEBUG(1, ("acl_set_qualifiier failed: %s\n",
327                                           strerror(errno)));
328                                 goto fail;
329                         }
330                         break;
331                 case SMB_ACL_GROUP:
332                         if (acl_set_qualifier(e, &entry->gid) != 0) {
333                                 DEBUG(1, ("acl_set_qualifiier failed: %s\n",
334                                           strerror(errno)));
335                                 goto fail;
336                         }
337                         break;
338                 default:        /* Shut up, compiler! :-) */
339                         break;
340                 }
341
342                 if (smb_acl_set_mode(e, entry->a_perm) != 0) {
343                         goto fail;
344                 }
345         }
346
347         if (acl_valid(result) != 0) {
348                 DEBUG(0, ("smb_acl_to_posix: ACL is invalid for set (%s)\n",
349                           strerror(errno)));
350                 goto fail;
351         }
352
353         return result;
354
355  fail:
356         if (result != NULL) {
357                 acl_free(result);
358         }
359         return NULL;
360 }
361
362 /* VFS operations structure */
363
364 static struct vfs_fn_pointers posixacl_fns = {
365         .sys_acl_get_file = posixacl_sys_acl_get_file,
366         .sys_acl_get_fd = posixacl_sys_acl_get_fd,
367         .sys_acl_set_file = posixacl_sys_acl_set_file,
368         .sys_acl_set_fd = posixacl_sys_acl_set_fd,
369         .sys_acl_delete_def_file = posixacl_sys_acl_delete_def_file,
370 };
371
372 NTSTATUS vfs_posixacl_init(void);
373 NTSTATUS vfs_posixacl_init(void)
374 {
375         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "posixacl",
376                                 &posixacl_fns);
377 }