s3: VFS: Change SMB_VFS_SYS_ACL_DELETE_DEF_FILE to use const struct smb_filename...
[samba.git] / source3 / modules / vfs_hpuxacl.c
1 /*
2  * Unix SMB/Netbios implementation.
3  * VFS module to get and set HP-UX 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 /*
21  * This module supports JFS (POSIX) ACLs on VxFS (Veritas * Filesystem).
22  * These are available on HP-UX 11.00 if JFS 3.3 is installed. 
23  * On HP-UX 11i (11.11 and above) these ACLs are supported out of
24  * the box.
25  *
26  * There is another form of ACLs on HFS. These ACLs have a
27  * completely different API and their own set of userland tools.
28  * Since HFS seems to be considered deprecated, HFS acls
29  * are not supported. (They could be supported through a separate
30  * vfs-module if there is demand.)
31  */
32
33 /* =================================================================
34  * NOTE:
35  *
36  * The original hpux-acl code in lib/sysacls.c was based upon the
37  * solaris acl code in the same file. Now for the new modularized
38  * acl implementation, I have taken the code from vfs_solarisacls.c
39  * and did similar adaptations as were done before, essentially
40  * reusing the original internal aclsort functions.
41  * The check for the presence of the acl() call has been adopted, and
42  * a check for the presence of the aclsort() call has been added. 
43  * 
44  * Michael Adam <obnox@samba.org>
45  *
46  * ================================================================= */
47
48
49 #include "includes.h"
50 #include "system/filesys.h"
51 #include "smbd/smbd.h"
52 #include "modules/vfs_hpuxacl.h"
53
54
55 /* 
56  * including standard header <sys/aclv.h> 
57  *
58  * included here as a quick hack for the special HP-UX-situation:
59  *
60  * The problem is that, on HP-UX, jfs/posix acls are
61  * defined in <sys/aclv.h>, while the deprecated hfs acls 
62  * are defined inside <sys/acl.h>.
63  *
64  */
65 /* GROUP is defined somewhere else so undef it here... */
66 #undef GROUP
67 #include <sys/aclv.h>
68 /* dl.h: needed to check for acl call via shl_findsym */
69 #include <dl.h>
70
71 typedef struct acl HPUX_ACE_T;
72 typedef struct acl *HPUX_ACL_T;
73 typedef int HPUX_ACL_TAG_T;   /* the type of an ACL entry */
74 typedef ushort HPUX_PERM_T;
75
76 /* Structure to capture the count for each type of ACE. 
77  * (for hpux_internal_aclsort */
78 struct hpux_acl_types {
79         int n_user;
80         int n_def_user;
81         int n_user_obj;
82         int n_def_user_obj;
83
84         int n_group;
85         int n_def_group;
86         int n_group_obj;
87         int n_def_group_obj;
88
89         int n_other;
90         int n_other_obj;
91         int n_def_other_obj;
92
93         int n_class_obj;
94         int n_def_class_obj;
95
96         int n_illegal_obj;
97 };
98
99 /* for convenience: check if hpux acl entry is a default entry?  */
100 #define _IS_DEFAULT(ace) ((ace).a_type & ACL_DEFAULT)
101 #define _IS_OF_TYPE(ace, type) ( \
102         (((type) == SMB_ACL_TYPE_ACCESS) && !_IS_DEFAULT(ace)) \
103         || \
104         (((type) == SMB_ACL_TYPE_DEFAULT) && _IS_DEFAULT(ace)) \
105 )
106
107
108 /* prototypes for private functions */
109
110 static HPUX_ACL_T hpux_acl_init(int count);
111 static bool smb_acl_to_hpux_acl(SMB_ACL_T smb_acl, 
112                 HPUX_ACL_T *solariacl, int *count, 
113                 SMB_ACL_TYPE_T type);
114 static SMB_ACL_T hpux_acl_to_smb_acl(HPUX_ACL_T hpuxacl, int count,
115                                      SMB_ACL_TYPE_T type, TALLOC_CTX *mem_ctx);
116 static HPUX_ACL_TAG_T smb_tag_to_hpux_tag(SMB_ACL_TAG_T smb_tag);
117 static SMB_ACL_TAG_T hpux_tag_to_smb_tag(HPUX_ACL_TAG_T hpux_tag);
118 static bool hpux_add_to_acl(HPUX_ACL_T *hpux_acl, int *count,
119                 HPUX_ACL_T add_acl, int add_count, SMB_ACL_TYPE_T type);
120 static bool hpux_acl_get_file(const char *name, HPUX_ACL_T *hpuxacl, 
121                 int *count);
122 static SMB_ACL_PERM_T hpux_perm_to_smb_perm(const HPUX_PERM_T perm);
123 static HPUX_PERM_T smb_perm_to_hpux_perm(const SMB_ACL_PERM_T perm);
124 #if 0
125 static bool hpux_acl_check(HPUX_ACL_T hpux_acl, int count);
126 #endif
127 /* aclsort (internal) and helpers: */
128 static bool hpux_acl_sort(HPUX_ACL_T acl, int count);
129 static int hpux_internal_aclsort(int acl_count, int calclass, HPUX_ACL_T aclp);
130 static void hpux_count_obj(int acl_count, HPUX_ACL_T aclp, 
131                 struct hpux_acl_types *acl_type_count);
132 static void hpux_swap_acl_entries(HPUX_ACE_T *aclp0, HPUX_ACE_T *aclp1);
133 static bool hpux_prohibited_duplicate_type(int acl_type);
134
135 static bool hpux_acl_call_present(void);
136 static bool hpux_aclsort_call_present(void);
137
138
139 /* public functions - the api */
140
141 SMB_ACL_T hpuxacl_sys_acl_get_file(vfs_handle_struct *handle,
142                                       const char *path_p,
143                                    SMB_ACL_TYPE_T type,
144                                    TALLOC_CTX *mem_ctx)
145 {
146         SMB_ACL_T result = NULL;
147         int count;
148         HPUX_ACL_T hpux_acl = NULL;
149
150         DEBUG(10, ("hpuxacl_sys_acl_get_file called for file '%s'.\n", 
151                    path_p));
152
153         if(hpux_acl_call_present() == False) {
154                 /* Looks like we don't have the acl() system call on HPUX. 
155                  * May be the system doesn't have the latest version of JFS.
156                  */
157                 goto done;
158         }
159
160         if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
161                 DEBUG(10, ("invalid SMB_ACL_TYPE given (%d)\n", type));
162                 errno = EINVAL;
163                 goto done;
164         }
165
166         DEBUGADD(10, ("getting %s acl\n", 
167                       ((type == SMB_ACL_TYPE_ACCESS) ? "access" : "default")));
168
169         if (!hpux_acl_get_file(path_p, &hpux_acl, &count)) {
170                 goto done;
171         }
172         result = hpux_acl_to_smb_acl(hpux_acl, count, type, mem_ctx);
173         if (result == NULL) {
174                 DEBUG(10, ("conversion hpux_acl -> smb_acl failed (%s).\n",
175                            strerror(errno)));
176         }
177
178  done:
179         DEBUG(10, ("hpuxacl_sys_acl_get_file %s.\n",
180                    ((result == NULL) ? "failed" : "succeeded" )));
181         SAFE_FREE(hpux_acl);
182         return result;
183 }
184
185
186 /*
187  * get the access ACL of a file referred to by a fd
188  */
189 SMB_ACL_T hpuxacl_sys_acl_get_fd(vfs_handle_struct *handle,
190                                  files_struct *fsp,
191                                  TALLOC_CTX *mem_ctx)
192 {
193         /* 
194          * HPUX doesn't have the facl call. Fake it using the path.... JRA. 
195          */
196         /*
197          * We know we're in the same conn context. So we
198          * can use the relative path.
199          */
200         DEBUG(10, ("redirecting call of hpuxacl_sys_acl_get_fd to "
201                 "hpuxacl_sys_acl_get_file (no facl syscall on HPUX).\n"));
202
203         return hpuxacl_sys_acl_get_file(handle,
204                                         fsp->fsp_name->base_name,
205                                         SMB_ACL_TYPE_ACCESS,
206                                         mem_ctx);
207 }
208
209
210 int hpuxacl_sys_acl_set_file(vfs_handle_struct *handle,
211                              const char *name,
212                              SMB_ACL_TYPE_T type,
213                              SMB_ACL_T theacl)
214 {
215         int ret = -1;
216         HPUX_ACL_T hpux_acl = NULL;
217         int count;
218         struct smb_filename *smb_fname = NULL;
219         NTSTATUS status;
220
221         DEBUG(10, ("hpuxacl_sys_acl_set_file called for file '%s'\n",
222                    name));
223
224         smb_fname = synthetic_smb_fname(talloc_tos(), name, NULL, NULL, 0);
225         if (smb_fname == NULL) {
226                 status = NT_STATUS_NO_MEMORY;
227                 goto done;
228         }
229
230         if(hpux_acl_call_present() == False) {
231                 /* Looks like we don't have the acl() system call on HPUX. 
232                  * May be the system doesn't have the latest version of JFS.
233                  */
234                 goto done;
235         }
236
237         if ((type != SMB_ACL_TYPE_ACCESS) && (type != SMB_ACL_TYPE_DEFAULT)) {
238                 errno = EINVAL;
239                 DEBUG(10, ("invalid smb acl type given (%d).\n", type));
240                 goto done;
241         }
242         DEBUGADD(10, ("setting %s acl\n", 
243                       ((type == SMB_ACL_TYPE_ACCESS) ? "access" : "default")));
244
245         if(!smb_acl_to_hpux_acl(theacl, &hpux_acl, &count, type)) {
246                 DEBUG(10, ("conversion smb_acl -> hpux_acl failed (%s).\n",
247                            strerror(errno)));
248                 goto done;
249         }
250
251         /*
252          * We can directly use SMB_VFS_STAT here, as if this was a
253          * POSIX call on a symlink, we've already refused it.
254          * For a Windows acl mapped call on a symlink, we want to follow
255          * it.
256          */
257         ret = SMB_VFS_STAT(handle->conn, smb_fname);
258         if (ret != 0) {
259                 DEBUG(10, ("Error in stat call: %s\n", strerror(errno)));
260                 goto done;
261         }
262         if (S_ISDIR(smb_fname->st.st_ex_mode)) {
263                 /*
264                  * if the file is a directory, there is extra work to do:
265                  * since the hpux acl call stores both the access acl and
266                  * the default acl as provided, we have to get the acl part
267                  * that has _not_ been specified in "type" from the file first
268                  * and concatenate it with the acl provided.
269                  */
270                 HPUX_ACL_T other_acl; 
271                 int other_count;
272                 SMB_ACL_TYPE_T other_type;
273
274                 other_type = (type == SMB_ACL_TYPE_ACCESS) 
275                         ? SMB_ACL_TYPE_DEFAULT
276                         : SMB_ACL_TYPE_ACCESS;
277                 DEBUGADD(10, ("getting acl from filesystem\n"));
278                 if (!hpux_acl_get_file(smb_fname->base_name, &other_acl,
279                                        &other_count)) {
280                         DEBUG(10, ("error getting acl from directory\n"));
281                         goto done;
282                 }
283                 DEBUG(10, ("adding %s part of fs acl to given acl\n",
284                            ((other_type == SMB_ACL_TYPE_ACCESS) 
285                             ? "access"
286                             : "default")));
287                 if (!hpux_add_to_acl(&hpux_acl, &count, other_acl,
288                                         other_count, other_type)) 
289                 {
290                         DEBUG(10, ("error adding other acl.\n"));
291                         SAFE_FREE(other_acl);
292                         goto done;
293                 }
294                 SAFE_FREE(other_acl);
295         }
296         else if (type != SMB_ACL_TYPE_ACCESS) {
297                 errno = EINVAL;
298                 goto done;
299         }
300
301         if (!hpux_acl_sort(hpux_acl, count)) {
302                 DEBUG(10, ("resulting acl is not valid!\n"));
303                 goto done;
304         }
305         DEBUG(10, ("resulting acl is valid.\n"));
306
307         ret = acl(discard_const_p(char, smb_fname->base_name), ACL_SET, count,
308                   hpux_acl);
309         if (ret != 0) {
310                 DEBUG(0, ("ERROR calling acl: %s\n", strerror(errno)));
311         }
312
313  done:
314         DEBUG(10, ("hpuxacl_sys_acl_set_file %s.\n",
315                    ((ret != 0) ? "failed" : "succeeded")));
316         TALLOC_FREE(smb_fname);
317         SAFE_FREE(hpux_acl);
318         return ret;
319 }
320
321 /*
322  * set the access ACL on the file referred to by a fd 
323  */
324 int hpuxacl_sys_acl_set_fd(vfs_handle_struct *handle,
325                               files_struct *fsp,
326                               SMB_ACL_T theacl)
327 {
328         /*
329          * HPUX doesn't have the facl call. Fake it using the path.... JRA.
330          */
331         /*
332          * We know we're in the same conn context. So we
333          * can use the relative path.
334          */
335         DEBUG(10, ("redirecting call of hpuxacl_sys_acl_set_fd to "
336                 "hpuxacl_sys_acl_set_file (no facl syscall on HPUX)\n"));
337
338         return hpuxacl_sys_acl_set_file(handle,
339                                         fsp->fsp_name->base_name,
340                                         SMB_ACL_TYPE_ACCESS, theacl);
341 }
342
343
344 /*
345  * delete the default ACL of a directory
346  *
347  * This is achieved by fetching the access ACL and rewriting it 
348  * directly, via the hpux system call: the ACL_SET call on 
349  * directories writes both the access and the default ACL as provided.
350  *
351  * XXX: posix acl_delete_def_file returns an error if
352  * the file referred to by path is not a directory.
353  * this function does not complain but the actions 
354  * have no effect on a file other than a directory.
355  * But sys_acl_delete_default_file is only called in
356  * smbd/posixacls.c after having checked that the file
357  * is a directory, anyways. So implementing the extra
358  * check is considered unnecessary. --- Agreed? XXX
359  */
360 int hpuxacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
361                                 const struct smb_filename *smb_fname)
362 {
363         SMB_ACL_T smb_acl;
364         int ret = -1;
365         HPUX_ACL_T hpux_acl;
366         int count;
367
368         DEBUG(10, ("entering hpuxacl_sys_acl_delete_def_file.\n"));
369
370         smb_acl = hpuxacl_sys_acl_get_file(handle, smb_fname->base_name,
371                                            SMB_ACL_TYPE_ACCESS);
372         if (smb_acl == NULL) {
373                 DEBUG(10, ("getting file acl failed!\n"));
374                 goto done;
375         }
376         if (!smb_acl_to_hpux_acl(smb_acl, &hpux_acl, &count, 
377                                  SMB_ACL_TYPE_ACCESS))
378         {
379                 DEBUG(10, ("conversion smb_acl -> hpux_acl failed.\n"));
380                 goto done;
381         }
382         if (!hpux_acl_sort(hpux_acl, count)) {
383                 DEBUG(10, ("resulting acl is not valid!\n"));
384                 goto done;
385         }
386         ret = acl(discard_const_p(char, smb_fname->base_name),
387                                 ACL_SET, count, hpux_acl);
388         if (ret != 0) {
389                 DEBUG(10, ("settinge file acl failed!\n"));
390         }
391
392  done:
393         DEBUG(10, ("hpuxacl_sys_acl_delete_def_file %s.\n",
394                    ((ret != 0) ? "failed" : "succeeded" )));
395         TALLOC_FREE(smb_acl);
396         return ret;
397 }
398
399
400 /* 
401  * private functions 
402  */
403
404 static HPUX_ACL_T hpux_acl_init(int count)
405 {
406         HPUX_ACL_T hpux_acl = 
407                 (HPUX_ACL_T)SMB_MALLOC(sizeof(HPUX_ACE_T) * count);
408         if (hpux_acl == NULL) {
409                 errno = ENOMEM;
410         }
411         return hpux_acl;
412 }
413
414 /*
415  * Convert the SMB acl to the ACCESS or DEFAULT part of a 
416  * hpux ACL, as desired.
417  */
418 static bool smb_acl_to_hpux_acl(SMB_ACL_T smb_acl, 
419                                    HPUX_ACL_T *hpux_acl, int *count, 
420                                    SMB_ACL_TYPE_T type)
421 {
422         bool ret = False;
423         int i;
424         int check_which, check_rc;
425
426         DEBUG(10, ("entering smb_acl_to_hpux_acl\n"));
427
428         *hpux_acl = NULL;
429         *count = 0;
430
431         for (i = 0; i < smb_acl->count; i++) {
432                 const struct smb_acl_entry *smb_entry = &(smb_acl->acl[i]);
433                 HPUX_ACE_T hpux_entry;
434
435                 ZERO_STRUCT(hpux_entry);
436
437                 hpux_entry.a_type = smb_tag_to_hpux_tag(smb_entry->a_type);
438                 if (hpux_entry.a_type == 0) {
439                         DEBUG(10, ("smb_tag to hpux_tag failed\n"));
440                         goto fail;
441                 }
442                 switch(hpux_entry.a_type) {
443                 case USER:
444                         DEBUG(10, ("got tag type USER with uid %d\n", 
445                                    smb_entry->info.user.uid));
446                         hpux_entry.a_id = (uid_t)smb_entry->info.user.uid;
447                         break;
448                 case GROUP:
449                         DEBUG(10, ("got tag type GROUP with gid %d\n", 
450                                    smb_entry->info.group.gid));
451                         hpux_entry.a_id = (uid_t)smb_entry->info.group.gid;
452                         break;
453                 default:
454                         break;
455                 }
456                 if (type == SMB_ACL_TYPE_DEFAULT) {
457                         DEBUG(10, ("adding default bit to hpux ace\n"));
458                         hpux_entry.a_type |= ACL_DEFAULT;
459                 }
460
461                 hpux_entry.a_perm = 
462                         smb_perm_to_hpux_perm(smb_entry->a_perm);
463                 DEBUG(10, ("assembled the following hpux ace:\n"));
464                 DEBUGADD(10, (" - type: 0x%04x\n", hpux_entry.a_type));
465                 DEBUGADD(10, (" - id: %d\n", hpux_entry.a_id));
466                 DEBUGADD(10, (" - perm: o%o\n", hpux_entry.a_perm));
467                 if (!hpux_add_to_acl(hpux_acl, count, &hpux_entry, 
468                                         1, type))
469                 {
470                         DEBUG(10, ("error adding acl entry\n"));
471                         goto fail;
472                 }
473                 DEBUG(10, ("count after adding: %d (i: %d)\n", *count, i));
474                 DEBUG(10, ("test, if entry has been copied into acl:\n"));
475                 DEBUGADD(10, (" - type: 0x%04x\n",
476                               (*hpux_acl)[(*count)-1].a_type));
477                 DEBUGADD(10, (" - id: %d\n",
478                               (*hpux_acl)[(*count)-1].a_id));
479                 DEBUGADD(10, (" - perm: o%o\n",
480                               (*hpux_acl)[(*count)-1].a_perm));
481         }
482
483         ret = True;
484         goto done;
485
486  fail:
487         SAFE_FREE(*hpux_acl);
488  done:
489         DEBUG(10, ("smb_acl_to_hpux_acl %s\n",
490                    ((ret == True) ? "succeeded" : "failed")));
491         return ret;
492 }
493
494 /* 
495  * convert either the access or the default part of a 
496  * soaris acl to the SMB_ACL format.
497  */
498 static SMB_ACL_T hpux_acl_to_smb_acl(HPUX_ACL_T hpux_acl, int count, 
499                                      SMB_ACL_TYPE_T type, TALLOC_CTX *mem_ctx)
500 {
501         SMB_ACL_T result;
502         int i;
503
504         if ((result = sys_acl_init(mem_ctx)) == NULL) {
505                 DEBUG(10, ("error allocating memory for SMB_ACL\n"));
506                 goto fail;
507         }
508         for (i = 0; i < count; i++) {
509                 SMB_ACL_ENTRY_T smb_entry;
510                 SMB_ACL_PERM_T smb_perm;
511
512                 if (!_IS_OF_TYPE(hpux_acl[i], type)) {
513                         continue;
514                 }
515                 result->acl = talloc_realloc(result, result->acl, struct smb_acl_entry, result->count + 1);
516                 if (result->acl == NULL) {
517                         DEBUG(10, ("error reallocating memory for SMB_ACL\n"));
518                         goto fail;
519                 }
520                 smb_entry = &result->acl[result->count];
521                 if (sys_acl_set_tag_type(smb_entry,
522                                          hpux_tag_to_smb_tag(hpux_acl[i].a_type)) != 0)
523                 {
524                         DEBUG(10, ("invalid tag type given: 0x%04x\n",
525                                    hpux_acl[i].a_type));
526                         goto fail;
527                 }
528                 /* intentionally not checking return code here: */
529                 sys_acl_set_qualifier(smb_entry, (void *)&hpux_acl[i].a_id);
530                 smb_perm = hpux_perm_to_smb_perm(hpux_acl[i].a_perm);
531                 if (sys_acl_set_permset(smb_entry, &smb_perm) != 0) {
532                         DEBUG(10, ("invalid permset given: %d\n", 
533                                    hpux_acl[i].a_perm));
534                         goto fail;
535                 }
536                 result->count += 1;
537         }
538         goto done;
539  fail:
540         TALLOC_FREE(result);
541  done:
542         DEBUG(10, ("hpux_acl_to_smb_acl %s\n",
543                    ((result == NULL) ? "failed" : "succeeded")));
544         return result;
545 }
546
547
548
549 static HPUX_ACL_TAG_T smb_tag_to_hpux_tag(SMB_ACL_TAG_T smb_tag)
550 {
551         HPUX_ACL_TAG_T hpux_tag = 0;
552
553         DEBUG(10, ("smb_tag_to_hpux_tag\n"));
554         DEBUGADD(10, (" --> got smb tag 0x%04x\n", smb_tag));
555
556         switch (smb_tag) {
557         case SMB_ACL_USER:
558                 hpux_tag = USER;
559                 break;
560         case SMB_ACL_USER_OBJ:
561                 hpux_tag = USER_OBJ;
562                 break;
563         case SMB_ACL_GROUP:
564                 hpux_tag = GROUP;
565                 break;
566         case SMB_ACL_GROUP_OBJ:
567                 hpux_tag = GROUP_OBJ;
568                 break;
569         case SMB_ACL_OTHER:
570                 hpux_tag = OTHER_OBJ;
571                 break;
572         case SMB_ACL_MASK:
573                 hpux_tag = CLASS_OBJ;
574                 break;
575         default:
576                 DEBUGADD(10, (" !!! unknown smb tag type 0x%04x\n", smb_tag));
577                 break;
578         }
579
580         DEBUGADD(10, (" --> determined hpux tag 0x%04x\n", hpux_tag));
581
582         return hpux_tag;
583 }
584
585 static SMB_ACL_TAG_T hpux_tag_to_smb_tag(HPUX_ACL_TAG_T hpux_tag)
586 {
587         SMB_ACL_TAG_T smb_tag = 0;
588
589         DEBUG(10, ("hpux_tag_to_smb_tag:\n"));
590         DEBUGADD(10, (" --> got hpux tag 0x%04x\n", hpux_tag)); 
591
592         hpux_tag &= ~ACL_DEFAULT; 
593
594         switch (hpux_tag) {
595         case USER:
596                 smb_tag = SMB_ACL_USER;
597                 break;
598         case USER_OBJ:
599                 smb_tag = SMB_ACL_USER_OBJ;
600                 break;
601         case GROUP:
602                 smb_tag = SMB_ACL_GROUP;
603                 break;
604         case GROUP_OBJ:
605                 smb_tag = SMB_ACL_GROUP_OBJ;
606                 break;
607         case OTHER_OBJ:
608                 smb_tag = SMB_ACL_OTHER;
609                 break;
610         case CLASS_OBJ:
611                 smb_tag = SMB_ACL_MASK;
612                 break;
613         default:
614                 DEBUGADD(10, (" !!! unknown hpux tag type: 0x%04x\n", 
615                                         hpux_tag));
616                 break;
617         }
618
619         DEBUGADD(10, (" --> determined smb tag 0x%04x\n", smb_tag));
620
621         return smb_tag;
622 }
623
624
625 /* 
626  * The permission bits used in the following two permission conversion 
627  * functions are same, but the functions make us independent of the concrete 
628  * permission data types.
629  */
630 static SMB_ACL_PERM_T hpux_perm_to_smb_perm(const HPUX_PERM_T perm)
631 {
632         SMB_ACL_PERM_T smb_perm = 0;
633         smb_perm |= ((perm & SMB_ACL_READ) ? SMB_ACL_READ : 0);
634         smb_perm |= ((perm & SMB_ACL_WRITE) ? SMB_ACL_WRITE : 0);
635         smb_perm |= ((perm & SMB_ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
636         return smb_perm;
637 }
638
639
640 static HPUX_PERM_T smb_perm_to_hpux_perm(const SMB_ACL_PERM_T perm)
641 {
642         HPUX_PERM_T hpux_perm = 0;
643         hpux_perm |= ((perm & SMB_ACL_READ) ? SMB_ACL_READ : 0);
644         hpux_perm |= ((perm & SMB_ACL_WRITE) ? SMB_ACL_WRITE : 0);
645         hpux_perm |= ((perm & SMB_ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
646         return hpux_perm;
647 }
648
649
650 static bool hpux_acl_get_file(const char *name, HPUX_ACL_T *hpux_acl, 
651                                  int *count)
652 {
653         bool result = False;
654         static HPUX_ACE_T dummy_ace;
655
656         DEBUG(10, ("hpux_acl_get_file called for file '%s'\n", name));
657
658         /* 
659          * The original code tries some INITIAL_ACL_SIZE
660          * and only did the ACL_CNT call upon failure
661          * (for performance reasons).
662          * For the sake of simplicity, I skip this for now. 
663          *
664          * NOTE: There is a catch here on HP-UX: acl with cmd parameter
665          * ACL_CNT fails with errno EINVAL when called with a NULL
666          * pointer as last argument. So we need to use a dummy acl
667          * struct here (we make it static so it does not need to be
668          * instantiated or malloced each time this function is
669          * called). Btw: the count parameter does not seem to matter...
670          */
671         *count = acl(discard_const_p(char, name), ACL_CNT, 0, &dummy_ace);
672         if (*count < 0) {
673                 DEBUG(10, ("acl ACL_CNT failed: %s\n", strerror(errno)));
674                 goto done;
675         }
676         *hpux_acl = hpux_acl_init(*count);
677         if (*hpux_acl == NULL) {
678                 DEBUG(10, ("error allocating memory for hpux acl...\n"));
679                 goto done;
680         }
681         *count = acl(discard_const_p(char, name), ACL_GET, *count, *hpux_acl);
682         if (*count < 0) {
683                 DEBUG(10, ("acl ACL_GET failed: %s\n", strerror(errno)));
684                 goto done;
685         }
686         result = True;
687
688  done:
689         DEBUG(10, ("hpux_acl_get_file %s.\n",
690                    ((result == True) ? "succeeded" : "failed" )));
691         return result;
692 }
693
694
695
696
697 /*
698  * Add entries to a hpux ACL.
699  *
700  * Entries are directly added to the hpuxacl parameter.
701  * if memory allocation fails, this may result in hpuxacl 
702  * being NULL. if the resulting acl is to be checked and is 
703  * not valid, it is kept in hpuxacl but False is returned.
704  *
705  * The type of ACEs (access/default) to be added to the ACL can 
706  * be selected via the type parameter. 
707  * I use the SMB_ACL_TYPE_T type here. Since SMB_ACL_TYPE_ACCESS
708  * is defined as "0", this means that one can only add either
709  * access or default ACEs from the given ACL, not both at the same 
710  * time. If it should become necessary to add all of an ACL, one 
711  * would have to replace this parameter by another type.
712  */
713 static bool hpux_add_to_acl(HPUX_ACL_T *hpux_acl, int *count,
714                                HPUX_ACL_T add_acl, int add_count, 
715                                SMB_ACL_TYPE_T type)
716 {
717         int i;
718
719         if ((type != SMB_ACL_TYPE_ACCESS) && (type != SMB_ACL_TYPE_DEFAULT)) 
720         {
721                 DEBUG(10, ("invalid acl type given: %d\n", type));
722                 errno = EINVAL;
723                 return False;
724         }
725         for (i = 0; i < add_count; i++) {
726                 if (!_IS_OF_TYPE(add_acl[i], type)) {
727                         continue;
728                 }
729                 ADD_TO_ARRAY(NULL, HPUX_ACE_T, add_acl[i], 
730                              hpux_acl, count);
731                 if (hpux_acl == NULL) {
732                         DEBUG(10, ("error enlarging acl.\n"));
733                         errno = ENOMEM;
734                         return False;
735                 }
736         }
737         return True;
738 }
739
740
741 /* 
742  * sort the ACL and check it for validity
743  *
744  * [original comment from lib/sysacls.c:]
745  * 
746  * if it's a minimal ACL with only 4 entries then we
747  * need to recalculate the mask permissions to make
748  * sure that they are the same as the GROUP_OBJ
749  * permissions as required by the UnixWare acl() system call.
750  *
751  * (note: since POSIX allows minimal ACLs which only contain
752  * 3 entries - ie there is no mask entry - we should, in theory,
753  * check for this and add a mask entry if necessary - however
754  * we "know" that the caller of this interface always specifies
755  * a mask, so in practice "this never happens" (tm) - if it *does*
756  * happen aclsort() will fail and return an error and someone will
757  * have to fix it...)
758  */
759 static bool hpux_acl_sort(HPUX_ACL_T hpux_acl, int count)
760 {
761         int fixmask = (count <= 4);
762
763         if (hpux_internal_aclsort(count, fixmask, hpux_acl) != 0) {
764                 errno = EINVAL;
765                 return False;
766         }
767         return True;
768 }
769
770
771 /*
772  * Helpers for hpux_internal_aclsort:
773  *   - hpux_count_obj
774  *   - hpux_swap_acl_entries
775  *   - hpux_prohibited_duplicate_type
776  *   - hpux_get_needed_class_perm
777  */
778
779 /* hpux_count_obj:
780  * Counts the different number of objects in a given array of ACL
781  * structures.
782  * Inputs:
783  *
784  * acl_count      - Count of ACLs in the array of ACL strucutres.
785  * aclp           - Array of ACL structures.
786  * acl_type_count - Pointer to acl_types structure. Should already be
787  *                  allocated.
788  * Output: 
789  *
790  * acl_type_count - This structure is filled up with counts of various 
791  *                  acl types.
792  */
793
794 static void hpux_count_obj(int acl_count, HPUX_ACL_T aclp, struct hpux_acl_types *acl_type_count)
795 {
796         int i;
797
798         memset(acl_type_count, 0, sizeof(struct hpux_acl_types));
799
800         for(i=0;i<acl_count;i++) {
801                 switch(aclp[i].a_type) {
802                 case USER: 
803                         acl_type_count->n_user++;
804                         break;
805                 case USER_OBJ: 
806                         acl_type_count->n_user_obj++;
807                         break;
808                 case DEF_USER_OBJ: 
809                         acl_type_count->n_def_user_obj++;
810                         break;
811                 case GROUP: 
812                         acl_type_count->n_group++;
813                         break;
814                 case GROUP_OBJ: 
815                         acl_type_count->n_group_obj++;
816                         break;
817                 case DEF_GROUP_OBJ: 
818                         acl_type_count->n_def_group_obj++;
819                         break;
820                 case OTHER_OBJ: 
821                         acl_type_count->n_other_obj++;
822                         break;
823                 case DEF_OTHER_OBJ: 
824                         acl_type_count->n_def_other_obj++;
825                         break;
826                 case CLASS_OBJ:
827                         acl_type_count->n_class_obj++;
828                         break;
829                 case DEF_CLASS_OBJ:
830                         acl_type_count->n_def_class_obj++;
831                         break;
832                 case DEF_USER:
833                         acl_type_count->n_def_user++;
834                         break;
835                 case DEF_GROUP:
836                         acl_type_count->n_def_group++;
837                         break;
838                 default: 
839                         acl_type_count->n_illegal_obj++;
840                         break;
841                 }
842         }
843 }
844
845 /* hpux_swap_acl_entries:  Swaps two ACL entries. 
846  *
847  * Inputs: aclp0, aclp1 - ACL entries to be swapped.
848  */
849
850 static void hpux_swap_acl_entries(HPUX_ACE_T *aclp0, HPUX_ACE_T *aclp1)
851 {
852         HPUX_ACE_T temp_acl;
853
854         temp_acl.a_type = aclp0->a_type;
855         temp_acl.a_id = aclp0->a_id;
856         temp_acl.a_perm = aclp0->a_perm;
857
858         aclp0->a_type = aclp1->a_type;
859         aclp0->a_id = aclp1->a_id;
860         aclp0->a_perm = aclp1->a_perm;
861
862         aclp1->a_type = temp_acl.a_type;
863         aclp1->a_id = temp_acl.a_id;
864         aclp1->a_perm = temp_acl.a_perm;
865 }
866
867 /* hpux_prohibited_duplicate_type
868  * Identifies if given ACL type can have duplicate entries or 
869  * not.
870  *
871  * Inputs: acl_type - ACL Type.
872  *
873  * Outputs: 
874  *
875  * Return.. 
876  *
877  * True - If the ACL type matches any of the prohibited types.
878  * False - If the ACL type doesn't match any of the prohibited types.
879  */ 
880
881 static bool hpux_prohibited_duplicate_type(int acl_type)
882 {
883         switch(acl_type) {
884                 case USER:
885                 case GROUP:
886                 case DEF_USER: 
887                 case DEF_GROUP:
888                         return True;
889                 default:
890                         return False;
891         }
892 }
893
894 /* hpux_get_needed_class_perm
895  * Returns the permissions of a ACL structure only if the ACL
896  * type matches one of the pre-determined types for computing 
897  * CLASS_OBJ permissions.
898  *
899  * Inputs: aclp - Pointer to ACL structure.
900  */
901
902 static int hpux_get_needed_class_perm(struct acl *aclp)
903 {
904         switch(aclp->a_type) {
905                 case USER: 
906                 case GROUP_OBJ: 
907                 case GROUP: 
908                 case DEF_USER_OBJ: 
909                 case DEF_USER:
910                 case DEF_GROUP_OBJ: 
911                 case DEF_GROUP:
912                 case DEF_CLASS_OBJ:
913                 case DEF_OTHER_OBJ: 
914                         return aclp->a_perm;
915                 default: 
916                         return 0;
917         }
918 }
919
920 /* hpux_internal_aclsort: aclsort for HPUX.
921  *
922  * -> The aclsort() system call is available on the latest HPUX General
923  * -> Patch Bundles. So for HPUX, we developed our version of aclsort
924  * -> function. Because, we don't want to update to a new
925  * -> HPUX GR bundle just for aclsort() call.
926  *
927  * aclsort sorts the array of ACL structures as per the description in
928  * aclsort man page. Refer to aclsort man page for more details
929  *
930  * Inputs:
931  *
932  * acl_count - Count of ACLs in the array of ACL structures.
933  * calclass  - If this is not zero, then we compute the CLASS_OBJ
934  *             permissions.
935  * aclp      - Array of ACL structures.
936  *
937  * Outputs:
938  *
939  * aclp     - Sorted array of ACL structures.
940  *
941  * Outputs:
942  *
943  * Returns 0 for success -1 for failure. Prints a message to the Samba
944  * debug log in case of failure.
945  */
946
947 static int hpux_internal_aclsort(int acl_count, int calclass, HPUX_ACL_T aclp)
948 {
949         struct hpux_acl_types acl_obj_count;
950         int n_class_obj_perm = 0;
951         int i, j;
952
953         DEBUG(10,("Entering hpux_internal_aclsort. (calclass = %d)\n", calclass));
954
955         if (hpux_aclsort_call_present()) {
956                 DEBUG(10, ("calling hpux aclsort\n"));
957                 return aclsort(acl_count, calclass, aclp);
958         }
959
960         DEBUG(10, ("using internal aclsort\n"));
961
962         if(!acl_count) {
963                 DEBUG(10,("Zero acl count passed. Returning Success\n"));
964                 return 0;
965         }
966
967         if(aclp == NULL) {
968                 DEBUG(0,("Null ACL pointer in hpux_acl_sort. Returning Failure. \n"));
969                 return -1;
970         }
971
972         /* Count different types of ACLs in the ACLs array */
973
974         hpux_count_obj(acl_count, aclp, &acl_obj_count);
975
976         /* There should be only one entry each of type USER_OBJ, GROUP_OBJ, 
977          * CLASS_OBJ and OTHER_OBJ 
978          */
979
980         if ( (acl_obj_count.n_user_obj  != 1) || 
981                 (acl_obj_count.n_group_obj != 1) || 
982                 (acl_obj_count.n_class_obj != 1) ||
983                 (acl_obj_count.n_other_obj != 1) ) 
984         {
985                 DEBUG(0,("hpux_internal_aclsort: More than one entry or no entries for \
986 USER OBJ or GROUP_OBJ or OTHER_OBJ or CLASS_OBJ\n"));
987                 return -1;
988         }
989
990         /* If any of the default objects are present, there should be only
991          * one of them each.
992          */
993
994         if ( (acl_obj_count.n_def_user_obj  > 1) || 
995                 (acl_obj_count.n_def_group_obj > 1) || 
996                 (acl_obj_count.n_def_other_obj > 1) || 
997                 (acl_obj_count.n_def_class_obj > 1) ) 
998         {
999                 DEBUG(0,("hpux_internal_aclsort: More than one entry for DEF_CLASS_OBJ \
1000 or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
1001                 return -1;
1002         }
1003
1004         /* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl 
1005          * structures.  
1006          *
1007          * Sorting crieteria - First sort by ACL type. If there are multiple entries of
1008          * same ACL type, sort by ACL id.
1009          *
1010          * I am using the trival kind of sorting method here because, performance isn't 
1011          * really effected by the ACLs feature. More over there aren't going to be more
1012          * than 17 entries on HPUX. 
1013          */
1014
1015         for(i=0; i<acl_count;i++) {
1016                 for (j=i+1; j<acl_count; j++) {
1017                         if( aclp[i].a_type > aclp[j].a_type ) {
1018                                 /* ACL entries out of order, swap them */
1019                                 hpux_swap_acl_entries((aclp+i), (aclp+j));
1020                         } else if ( aclp[i].a_type == aclp[j].a_type ) {
1021                                 /* ACL entries of same type, sort by id */
1022                                 if(aclp[i].a_id > aclp[j].a_id) {
1023                                         hpux_swap_acl_entries((aclp+i), (aclp+j));
1024                                 } else if (aclp[i].a_id == aclp[j].a_id) {
1025                                         /* We have a duplicate entry. */
1026                                         if(hpux_prohibited_duplicate_type(aclp[i].a_type)) {
1027                                                 DEBUG(0, ("hpux_internal_aclsort: Duplicate entry: Type(hex): %x Id: %d\n",
1028                                                         aclp[i].a_type, aclp[i].a_id));
1029                                                 return -1;
1030                                         }
1031                                 }
1032                         }
1033                 }
1034         }
1035
1036         /* set the class obj permissions to the computed one. */
1037         if(calclass) {
1038                 int n_class_obj_index = -1;
1039
1040                 for(i=0;i<acl_count;i++) {
1041                         n_class_obj_perm |= hpux_get_needed_class_perm((aclp+i));
1042
1043                         if(aclp[i].a_type == CLASS_OBJ)
1044                                 n_class_obj_index = i;
1045                 }
1046                 aclp[n_class_obj_index].a_perm = n_class_obj_perm;
1047         }
1048
1049         return 0;
1050 }
1051
1052
1053 /* 
1054  * hpux_acl_call_present:
1055  *
1056  * This checks if the POSIX ACL system call is defined
1057  * which basically corresponds to whether JFS 3.3 or
1058  * higher is installed. If acl() was called when it
1059  * isn't defined, it causes the process to core dump
1060  * so it is important to check this and avoid acl()
1061  * calls if it isn't there.                            
1062  */
1063
1064 static bool hpux_acl_call_present(void)
1065 {
1066
1067         shl_t handle = NULL;
1068         void *value;
1069         int ret_val=0;
1070         static bool already_checked = False;
1071
1072         if(already_checked)
1073                 return True;
1074
1075         errno = 0;
1076
1077         ret_val = shl_findsym(&handle, "acl", TYPE_PROCEDURE, &value);
1078
1079         if(ret_val != 0) {
1080                 DEBUG(5, ("hpux_acl_call_present: shl_findsym() returned %d, errno = %d, error %s\n",
1081                         ret_val, errno, strerror(errno)));
1082                 DEBUG(5,("hpux_acl_call_present: acl() system call is not present. Check if you have JFS 3.3 and above?\n"));
1083                 errno = ENOSYS;
1084                 return False;
1085         }
1086
1087         DEBUG(10,("hpux_acl_call_present: acl() system call is present. We have JFS 3.3 or above \n"));
1088
1089         already_checked = True;
1090         return True;
1091 }
1092
1093 /* 
1094  * runtime check for presence of aclsort library call. 
1095  * same code as for acl call. if there are more of these,
1096  * a dispatcher function could be handy...
1097  */
1098
1099 static bool hpux_aclsort_call_present(void) 
1100 {
1101         shl_t handle = NULL;
1102         void *value;
1103         int ret_val = 0;
1104         static bool already_checked = False;
1105
1106         if (already_checked) {
1107                 return True;
1108         }
1109
1110         errno = 0;
1111         ret_val = shl_findsym(&handle, "aclsort", TYPE_PROCEDURE, &value);
1112         if (ret_val != 0) {
1113                 DEBUG(5, ("hpux_aclsort_call_present: shl_findsym "
1114                         "returned %d, errno = %d, error %s", 
1115                         ret_val, errno, strerror(errno)));
1116                 DEBUG(5, ("hpux_aclsort_call_present: "
1117                         "aclsort() function not available.\n"));
1118                 return False;
1119         }
1120         DEBUG(10,("hpux_aclsort_call_present: aclsort() function present.\n"));
1121         already_checked = True;
1122         return True;
1123 }
1124
1125 #if 0
1126 /*
1127  * acl check function:
1128  *   unused at the moment but could be used to get more
1129  *   concrete error messages for debugging...
1130  *   (acl sort just says that the acl is invalid...)
1131  */
1132 static bool hpux_acl_check(HPUX_ACL_T hpux_acl, int count)
1133 {
1134         int check_rc;
1135         int check_which;
1136
1137         check_rc = aclcheck(hpux_acl, count, &check_which);
1138         if (check_rc != 0) {
1139                 DEBUG(10, ("acl is not valid:\n"));
1140                 DEBUGADD(10, (" - return code: %d\n", check_rc));
1141                 DEBUGADD(10, (" - which: %d\n", check_which));
1142                 if (check_which != -1) {
1143                         DEBUGADD(10, (" - invalid entry:\n"));
1144                         DEBUGADD(10, ("   * type: %d:\n", 
1145                                       hpux_acl[check_which].a_type));
1146                         DEBUGADD(10, ("   * id: %d\n",
1147                                       hpux_acl[check_which].a_id));
1148                         DEBUGADD(10, ("   * perm: 0o%o\n",
1149                                       hpux_acl[check_which].a_perm));
1150                 }
1151                 return False;
1152         }
1153         return True;
1154 }
1155 #endif
1156
1157 /* VFS operations structure */
1158
1159 static struct vfs_fn_pointers hpuxacl_fns = {
1160         .sys_acl_get_file_fn = hpuxacl_sys_acl_get_file,
1161         .sys_acl_get_fd_fn = hpuxacl_sys_acl_get_fd,
1162         .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
1163         .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
1164         .sys_acl_set_file_fn = hpuxacl_sys_acl_set_file,
1165         .sys_acl_set_fd_fn = hpuxacl_sys_acl_set_fd,
1166         .sys_acl_delete_def_file_fn = hpuxacl_sys_acl_delete_def_file,
1167 };
1168
1169 NTSTATUS vfs_hpuxacl_init(TALLOC_CTX *ctx)
1170 {
1171         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "hpuxacl",
1172                                 &hpuxacl_fns);
1173 }
1174
1175 /* ENTE */