vfs_tru64acl: add support for SMB_ACL_TYPE_DEFAULT to tru64acl_sys_acl_set_fd()
[samba.git] / source3 / modules / vfs_tru64acl.c
1 /*
2    Unix SMB/Netbios implementation.
3    VFS module to get and set Tru64 acls
4    Copyright (C) Michael Adam 2006,2008
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 #include "system/filesys.h"
22 #include "smbd/smbd.h"
23 #include "modules/vfs_tru64acl.h"
24
25 /* prototypes for private functions first - for clarity */
26
27 static struct smb_acl_t *tru64_acl_to_smb_acl(const struct acl *tru64_acl,
28                                               TALLOC_CTX *mem_ctx);
29 static bool tru64_ace_to_smb_ace(acl_entry_t tru64_ace, 
30                                 struct smb_acl_entry *smb_ace);
31 static acl_t smb_acl_to_tru64_acl(const SMB_ACL_T smb_acl);
32 static acl_tag_t smb_tag_to_tru64(SMB_ACL_TAG_T smb_tag);
33 static SMB_ACL_TAG_T tru64_tag_to_smb(acl_tag_t tru64_tag);
34 static acl_perm_t smb_permset_to_tru64(SMB_ACL_PERM_T smb_permset);
35 static SMB_ACL_PERM_T tru64_permset_to_smb(const acl_perm_t tru64_permset);
36
37
38 /* public functions - the api */
39
40 SMB_ACL_T tru64acl_sys_acl_get_file(vfs_handle_struct *handle,
41                                 const struct smb_filename *smb_fname,
42                                 SMB_ACL_TYPE_T type,
43                                 TALLOC_CTX *mem_ctx)
44 {
45         struct smb_acl_t *result;
46         acl_type_t the_acl_type;
47         acl_t tru64_acl;
48
49         DEBUG(10, ("Hi! This is tru64acl_sys_acl_get_file.\n"));
50
51         switch(type) {
52         case SMB_ACL_TYPE_ACCESS:
53                 the_acl_type = ACL_TYPE_ACCESS;
54                 break;
55         case SMB_ACL_TYPE_DEFAULT:
56                 the_acl_type = ACL_TYPE_DEFAULT;
57                 break;
58         default:
59                 errno = EINVAL;
60                 return NULL;
61         }
62
63         tru64_acl = acl_get_file((char *)smb_fname->base_name, the_acl_type);
64
65         if (tru64_acl == NULL) {
66                 return NULL;
67         }
68
69         result = tru64_acl_to_smb_acl(tru64_acl, mem_ctx);
70         acl_free(tru64_acl);
71         return result;
72 }
73
74 SMB_ACL_T tru64acl_sys_acl_get_fd(vfs_handle_struct *handle,
75                                   files_struct *fsp,
76                                   TALLOC_CTX *mem_ctx)
77 {
78         struct smb_acl_t *result;
79         acl_t tru64_acl = acl_get_fd(fsp_get_io_fd(fsp), ACL_TYPE_ACCESS);
80
81         if (tru64_acl == NULL) {
82                 return NULL;
83         }
84         
85         result = tru64_acl_to_smb_acl(tru64_acl, mem_ctx);
86         acl_free(tru64_acl);
87         return result;
88 }
89
90 int tru64acl_sys_acl_set_file(vfs_handle_struct *handle,
91                               const struct smb_filename *smb_fname,
92                               SMB_ACL_TYPE_T type,
93                               SMB_ACL_T theacl)
94 {
95         int res;
96         acl_type_t the_acl_type;
97         acl_t tru64_acl;
98
99         DEBUG(10, ("tru64acl_sys_acl_set_file called with name %s, type %d\n", 
100                         smb_fname->base_name, type));
101
102         switch(type) {
103         case SMB_ACL_TYPE_ACCESS:
104                 DEBUGADD(10, ("got acl type ACL_TYPE_ACCESS\n"));
105                 the_acl_type = ACL_TYPE_ACCESS;
106                 break;
107         case SMB_ACL_TYPE_DEFAULT:
108                 DEBUGADD(10, ("got acl type ACL_TYPE_DEFAULT\n"));
109                 the_acl_type = ACL_TYPE_DEFAULT;
110                 break;
111         default:
112                 DEBUGADD(10, ("invalid acl type\n"));
113                 errno = EINVAL;
114                 goto fail;
115         }
116
117         tru64_acl = smb_acl_to_tru64_acl(theacl);
118         if (tru64_acl == NULL) {
119                 DEBUG(10, ("smb_acl_to_tru64_acl failed!\n"));
120                 goto fail;
121         }
122         DEBUG(10, ("got tru64 acl...\n"));
123         res = acl_set_file((char *)smb_fname->base_name,
124                                 the_acl_type, tru64_acl);
125         acl_free(tru64_acl);
126         if (res != 0) {
127                 DEBUG(10, ("acl_set_file failed: %s\n", strerror(errno)));
128                 goto fail;
129         }
130         return res;
131 fail:
132         DEBUG(1, ("tru64acl_sys_acl_set_file failed!\n"));
133         return -1;
134 }
135
136 int tru64acl_sys_acl_set_fd(vfs_handle_struct *handle,
137                             files_struct *fsp,
138                             SMB_ACL_TYPE_T type,
139                             SMB_ACL_T theacl)
140 {
141         int res;
142         acl_t tru64_acl = smb_acl_to_tru64_acl(theacl);
143         acl_type_t the_acl_type;
144
145         switch(type) {
146         case SMB_ACL_TYPE_ACCESS:
147                 the_acl_type = ACL_TYPE_ACCESS;
148                 break;
149         case SMB_ACL_TYPE_DEFAULT:
150                 the_acl_type = ACL_TYPE_DEFAULT;
151                 break;
152         default:
153                 errno = EINVAL;
154                 return -1;
155         }
156
157         if (tru64_acl == NULL) {
158                 return -1;
159         }
160         res =  acl_set_fd(fsp_get_io_fd(fsp), the_acl_type, tru64_acl);
161         acl_free(tru64_acl);
162         return res;
163
164 }
165
166 int tru64acl_sys_acl_delete_def_file(vfs_handle_struct *handle,
167                                 const struct smb_filename *smb_fname)
168 {
169         return acl_delete_def_file((char *)smb_fname->base_name);
170 }
171
172
173 /* private functions */
174
175 static struct smb_acl_t *tru64_acl_to_smb_acl(const struct acl *tru64_acl,
176                                               TALLOC_CTX *mem_ctx)
177 {
178         struct smb_acl_t *result;
179         acl_entry_t entry;
180
181         DEBUG(10, ("Hi! This is tru64_acl_to_smb_acl.\n"));
182         
183         if ((result = sys_acl_init(mem_ctx)) == NULL) {
184                 DEBUG(0, ("sys_acl_init() failed in tru64_acl_to_smb_acl\n"));
185                 errno = ENOMEM;
186                 goto fail;
187         }
188         if (acl_first_entry((struct acl *)tru64_acl) != 0) {
189                 DEBUG(10, ("acl_first_entry failed: %s\n", strerror(errno)));
190                 goto fail;
191         }
192         while ((entry = acl_get_entry((struct acl *)tru64_acl)) != NULL) {
193                 result->acl = talloc_realloc(result, result->acl, struct smb_acl_entry, 
194                                              result->count + 1);
195                 if (result->acl == NULL) {
196                         TALLOC_FREE(result);
197                         DEBUG(0, ("talloc_realloc failed in tru64_acl_to_smb_acl\n"));
198                         errno = ENOMEM;
199                         goto fail;
200                 }
201                 /* XYZ */
202                 if (!tru64_ace_to_smb_ace(entry, &result->acl[result->count])) {
203                         TALLOC_FREE(result);
204                         goto fail;
205                 }
206                 result->count += 1;
207         }
208         return result;
209
210 fail:
211         TALLOC_FREE(result);
212         DEBUG(1, ("tru64_acl_to_smb_acl failed!\n"));
213         return NULL;
214 }
215
216 static bool tru64_ace_to_smb_ace(acl_entry_t tru64_ace, 
217                                 struct smb_acl_entry *smb_ace) 
218 {
219         acl_tag_t tru64_tag;
220         acl_permset_t permset;
221         SMB_ACL_TAG_T smb_tag_type;
222         SMB_ACL_PERM_T smb_permset;
223         void *qualifier;
224
225         if (acl_get_tag_type(tru64_ace, &tru64_tag) != 0) {
226                 DEBUG(0, ("acl_get_tag_type failed: %s\n", strerror(errno)));
227                 return False;
228         }
229         
230         /* On could set the tag type directly to save a function call, 
231          * but I like this better... */
232         smb_tag_type = tru64_tag_to_smb(tru64_tag);
233         if (smb_tag_type == 0) {
234                 DEBUG(3, ("invalid tag type given: %d\n", tru64_tag));
235                 return False;
236         }
237         if (sys_acl_set_tag_type(smb_ace, smb_tag_type) != 0) {
238                 DEBUG(3, ("sys_acl_set_tag_type failed: %s\n", 
239                                 strerror(errno)));
240                 return False;
241         }
242         qualifier = acl_get_qualifier(tru64_ace);
243         if (qualifier != NULL) {
244                 if (sys_acl_set_qualifier(smb_ace, qualifier) != 0) {
245                         DEBUG(3, ("sys_acl_set_qualifier failed\n"));
246                         return False;
247                 }
248         }
249         if (acl_get_permset(tru64_ace, &permset) != 0) {
250                 DEBUG(3, ("acl_get_permset failed: %s\n", strerror(errno)));
251                 return False;
252         }
253         smb_permset = tru64_permset_to_smb(*permset);
254         if (sys_acl_set_permset(smb_ace, &smb_permset) != 0) {
255                 DEBUG(3, ("sys_acl_set_permset failed: %s\n", strerror(errno)));
256                 return False;
257         }
258         return True;
259 }
260
261 static acl_t smb_acl_to_tru64_acl(const SMB_ACL_T smb_acl) 
262 {
263         acl_t result;
264         acl_entry_t tru64_entry;
265         int i;
266         char *acl_text;
267         ssize_t acl_text_len;
268         
269         /* The tru64 acl_init function takes a size_t value
270          * instead of a count of entries (as with posix). 
271          * the size parameter "Specifies the size of the working
272          * storage in bytes" (according to the man page). 
273          * But it is unclear to me, how this size is to be 
274          * calculated. 
275          *
276          * It should not matter, since acl_create_entry enlarges 
277          * the working storage at need. ... */
278
279         DEBUG(10, ("Hi! This is smb_acl_to_tru64_acl.\n"));
280
281         result = acl_init(1);
282
283         if (result == NULL) {
284                 DEBUG(3, ("acl_init failed!\n"));
285                 goto fail;
286         }
287         
288         DEBUGADD(10, ("parsing acl entries...\n"));
289         for (i = 0; i < smb_acl->count; i++) {
290                 /* XYZ - maybe eliminate this direct access? */
291                 const struct smb_acl_entry *smb_entry = &smb_acl->acl[i];
292                 acl_tag_t tru64_tag;
293                 acl_perm_t tru64_permset;
294
295                 tru64_tag = smb_tag_to_tru64(smb_entry->a_type);
296                 if (tru64_tag == -1) {
297                         DEBUG(3, ("smb_tag_to_tru64 failed!\n"));
298                         goto fail;
299                 }
300
301                 if (tru64_tag == ACL_MASK) {
302                         DEBUGADD(10, (" - acl type ACL_MASK: not implemented on Tru64 ==> skipping\n"));
303                         continue;
304                 }
305                 
306                 tru64_entry = acl_create_entry(&result);
307                 if (tru64_entry == NULL) {
308                         DEBUG(3, ("acl_create_entry failed: %s\n", 
309                                         strerror(errno)));
310                         goto fail;
311                 }
312
313                 if (acl_set_tag_type(tru64_entry, tru64_tag) != 0) {
314                         DEBUG(3, ("acl_set_tag_type(%d) failed: %s\n",
315                                         strerror(errno)));
316                         goto fail;
317                 }
318                 
319                 switch (smb_entry->a_type) {
320                 case SMB_ACL_USER:
321                         if (acl_set_qualifier(tru64_entry, 
322                                                 (int *)&smb_entry->info.user.uid) != 0) 
323                         {
324                                 DEBUG(3, ("acl_set_qualifier failed: %s\n",
325                                         strerror(errno)));
326                                 goto fail;
327                         }
328                         DEBUGADD(10, (" - setting uid to %d\n", smb_entry->info.user.uid));
329                         break;
330                 case SMB_ACL_GROUP:
331                         if (acl_set_qualifier(tru64_entry, 
332                                                 (int *)&smb_entry->info.group.gid) != 0)
333                         {
334                                 DEBUG(3, ("acl_set_qualifier failed: %s\n",
335                                         strerror(errno)));
336                                 goto fail;
337                         }
338                         DEBUGADD(10, (" - setting gid to %d\n", smb_entry->info.group.gid));
339                         break;
340                 default:
341                         break;
342                 }
343
344                 tru64_permset = smb_permset_to_tru64(smb_entry->a_perm);
345                 if (tru64_permset == -1) {
346                         DEBUG(3, ("smb_permset_to_tru64 failed!\n"));
347                         goto fail;
348                 }
349                 DEBUGADD(10, (" - setting perms to %0d\n", tru64_permset));
350                 if (acl_set_permset(tru64_entry, &tru64_permset) != 0)
351                 {
352                         DEBUG(3, ("acl_set_permset failed: %s\n", strerror(errno)));
353                         goto fail;
354                 }
355         } /* for */
356         DEBUGADD(10, ("done parsing acl entries\n"));
357
358         tru64_entry = NULL;
359         if (acl_valid(result, &tru64_entry) != 0) {
360                 DEBUG(1, ("smb_acl_to_tru64_acl: ACL is invalid (%s)\n",
361                                 strerror(errno)));
362                 if (tru64_entry != NULL) {
363                         DEBUGADD(1, ("the acl contains duplicate entries\n"));
364                 }
365                 goto fail;
366         }
367         DEBUGADD(10, ("acl is valid\n"));
368
369         acl_text = acl_to_text(result, &acl_text_len);
370         if (acl_text == NULL) {
371                 DEBUG(3, ("acl_to_text failed: %s\n", strerror(errno)));
372                 goto fail;
373         }
374         DEBUG(1, ("acl_text: %s\n", acl_text));
375         free(acl_text);
376
377         return result;
378
379 fail:
380         if (result != NULL) {
381                 acl_free(result);
382         }
383         DEBUG(1, ("smb_acl_to_tru64_acl failed!\n"));
384         return NULL;
385 }
386
387 static acl_tag_t smb_tag_to_tru64(SMB_ACL_TAG_T smb_tag)
388 {
389         acl_tag_t result;
390         switch (smb_tag) {
391         case SMB_ACL_USER:
392                 result = ACL_USER;
393                 DEBUGADD(10, ("got acl type ACL_USER\n"));
394                 break;
395         case SMB_ACL_USER_OBJ:
396                 result = ACL_USER_OBJ;
397                 DEBUGADD(10, ("got acl type ACL_USER_OBJ\n"));
398                 break;
399         case SMB_ACL_GROUP:
400                 result = ACL_GROUP;
401                 DEBUGADD(10, ("got acl type ACL_GROUP\n"));
402                 break;
403         case SMB_ACL_GROUP_OBJ:
404                 result = ACL_GROUP_OBJ;
405                 DEBUGADD(10, ("got acl type ACL_GROUP_OBJ\n"));
406                 break;
407         case SMB_ACL_OTHER:
408                 result = ACL_OTHER;
409                 DEBUGADD(10, ("got acl type ACL_OTHER\n"));
410                 break;
411         case SMB_ACL_MASK:
412                 result = ACL_MASK;
413                 DEBUGADD(10, ("got acl type ACL_MASK\n"));
414                 break;
415         default:
416                 DEBUG(1, ("Unknown tag type %d\n", smb_tag));
417                 result = -1;
418         }
419         return result;
420 }
421
422
423 static SMB_ACL_TAG_T tru64_tag_to_smb(acl_tag_t tru64_tag)
424 {
425         SMB_ACL_TAG_T smb_tag_type;
426         switch(tru64_tag) {
427         case ACL_USER:
428                 smb_tag_type = SMB_ACL_USER;
429                 DEBUGADD(10, ("got smb acl tag type SMB_ACL_USER\n"));
430                 break;
431         case ACL_USER_OBJ:
432                 smb_tag_type = SMB_ACL_USER_OBJ;
433                 DEBUGADD(10, ("got smb acl tag type SMB_ACL_USER_OBJ\n"));
434                 break;
435         case ACL_GROUP:
436                 smb_tag_type = SMB_ACL_GROUP;
437                 DEBUGADD(10, ("got smb acl tag type SMB_ACL_GROUP\n"));
438                 break;
439         case ACL_GROUP_OBJ:
440                 smb_tag_type = SMB_ACL_GROUP_OBJ;
441                 DEBUGADD(10, ("got smb acl tag type SMB_ACL_GROUP_OBJ\n"));
442                 break;
443         case ACL_OTHER:
444                 smb_tag_type = SMB_ACL_OTHER;
445                 DEBUGADD(10, ("got smb acl tag type SMB_ACL_OTHER\n"));
446                 break;
447         case ACL_MASK:
448                 smb_tag_type = SMB_ACL_MASK;
449                 DEBUGADD(10, ("got smb acl tag type SMB_ACL_MASK\n"));
450                 break;
451         default:
452                 DEBUG(0, ("Unknown tag type %d\n", (unsigned int)tru64_tag));
453                 smb_tag_type = 0;
454         }
455         return smb_tag_type;
456 }
457
458 static acl_perm_t smb_permset_to_tru64(SMB_ACL_PERM_T smb_permset)
459 {
460         /* originally, I thought that acl_clear_perm was the
461          * proper way to reset the permset to 0. but without 
462          * initializing it to 0, acl_clear_perm fails.
463          * so probably, acl_clear_perm is not necessary here... ?! */
464         acl_perm_t tru64_permset = 0;
465         if (acl_clear_perm(&tru64_permset) != 0) {
466                 DEBUG(5, ("acl_clear_perm failed: %s\n", strerror(errno)));
467                 return -1;
468         }
469         /* according to original lib/sysacls.c, acl_add_perm is
470          * broken on tru64 ... */
471         tru64_permset |= ((smb_permset & SMB_ACL_READ) ? ACL_READ : 0);
472         tru64_permset |= ((smb_permset & SMB_ACL_WRITE) ? ACL_WRITE : 0);
473         tru64_permset |= ((smb_permset & SMB_ACL_EXECUTE) ? ACL_EXECUTE : 0);
474         return tru64_permset;
475 }
476
477 static SMB_ACL_PERM_T tru64_permset_to_smb(const acl_perm_t tru64_permset)
478 {
479         SMB_ACL_PERM_T smb_permset  = 0;
480         smb_permset |= ((tru64_permset & ACL_READ) ? SMB_ACL_READ : 0);
481         smb_permset |= ((tru64_permset & ACL_WRITE) ? SMB_ACL_WRITE : 0);
482         smb_permset |= ((tru64_permset & ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
483         return smb_permset;
484 }
485
486
487 /* VFS operations structure */
488
489 static struct vfs_fn_pointers tru64acl_fns = {
490         .sys_acl_get_file_fn = tru64acl_sys_acl_get_file,
491         .sys_acl_get_fd_fn = tru64acl_sys_acl_get_fd,
492         .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
493         .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
494         .sys_acl_set_file_fn = tru64acl_sys_acl_set_file,
495         .sys_acl_set_fd_fn = tru64acl_sys_acl_set_fd,
496         .sys_acl_delete_def_file_fn = tru64acl_sys_acl_delete_def_file,
497 };
498
499 static_decl_vfs;
500 NTSTATUS vfs_tru64acl_init(TALLOC_CTX *ctx)
501 {
502         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "tru64acl",
503                                 &tru64acl_fns);
504 }
505
506 /* ENTE */