Leave out two unneeded sys*_fd() functions due to their using
[rsync/rsync.git] / lib / sysacls.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba system utilities for ACL support.
4    Copyright (C) Jeremy Allison 2000.
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 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "rsync.h"
22 #include "sysacls.h" /****** ADDED ******/
23
24 #ifdef SUPPORT_ACLS
25
26 /****** EXTRAS -- THESE ITEMS ARE NOT FROM THE SAMBA SOURCE ******/
27 #ifdef DEBUG
28 #undef DEBUG
29 #endif
30 #define DEBUG(x,y)
31
32 void SAFE_FREE(void *mem)
33 {
34         if (mem)
35                 free(mem);
36 }
37
38 char *uidtoname(uid_t uid)
39 {
40         static char idbuf[12];
41         struct passwd *pw;
42
43         if ((pw = getpwuid(uid)) == NULL) {
44                 slprintf(idbuf, sizeof(idbuf)-1, "%ld", (long)uid);
45                 return idbuf;
46         }
47         return pw->pw_name;
48 }
49 /****** EXTRAS -- END ******/
50
51 /*
52  This file wraps all differing system ACL interfaces into a consistent
53  one based on the POSIX interface. It also returns the correct errors
54  for older UNIX systems that don't support ACLs.
55
56  The interfaces that each ACL implementation must support are as follows :
57
58  int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
59  int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
60  int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p
61  void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
62  SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
63  SMB_ACL_T sys_acl_get_fd(int fd)
64  int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset);
65  int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm);
66  char *sys_acl_to_text( SMB_ACL_T theacl, ssize_t *plen)
67  SMB_ACL_T sys_acl_init( int count)
68  int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
69  int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
70  int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
71  int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
72  int sys_acl_valid( SMB_ACL_T theacl )
73  int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
74  int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
75  int sys_acl_delete_def_file(const char *path)
76
77  This next one is not POSIX complient - but we *have* to have it !
78  More POSIX braindamage.
79
80  int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
81
82  The generic POSIX free is the following call. We split this into
83  several different free functions as we may need to add tag info
84  to structures when emulating the POSIX interface.
85
86  int sys_acl_free( void *obj_p)
87
88  The calls we actually use are :
89
90  int sys_acl_free_text(char *text) - free acl_to_text
91  int sys_acl_free_acl(SMB_ACL_T posix_acl)
92  int sys_acl_free_qualifier(void *qualifier, SMB_ACL_TAG_T tagtype)
93
94 */
95
96 #if defined(HAVE_POSIX_ACLS)
97
98 /* Identity mapping - easy. */
99
100 int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
101 {
102         return acl_get_entry( the_acl, entry_id, entry_p);
103 }
104
105 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
106 {
107         return acl_get_tag_type( entry_d, tag_type_p);
108 }
109
110 int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
111 {
112         return acl_get_permset( entry_d, permset_p);
113 }
114
115 void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
116 {
117         return acl_get_qualifier( entry_d);
118 }
119
120 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
121 {
122         return acl_get_file( path_p, type);
123 }
124
125 SMB_ACL_T sys_acl_get_fd(int fd)
126 {
127         return acl_get_fd(fd);
128 }
129
130 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
131 {
132         return acl_clear_perms(permset);
133 }
134
135 int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
136 {
137         return acl_add_perm(permset, perm);
138 }
139
140 int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
141 {
142 #if defined(HAVE_ACL_GET_PERM_NP)
143         /*
144          * Required for TrustedBSD-based ACL implementations where
145          * non-POSIX.1e functions are denoted by a _np (non-portable)
146          * suffix.
147          */
148         return acl_get_perm_np(permset, perm);
149 #else
150         return acl_get_perm(permset, perm);
151 #endif
152 }
153
154 char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
155 {
156         return acl_to_text( the_acl, plen);
157 }
158
159 SMB_ACL_T sys_acl_init( int count)
160 {
161         return acl_init(count);
162 }
163
164 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
165 {
166         return acl_create_entry(pacl, pentry);
167 }
168
169 int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
170 {
171         return acl_set_tag_type(entry, tagtype);
172 }
173
174 int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
175 {
176         return acl_set_qualifier(entry, qual);
177 }
178
179 int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
180 {
181         return acl_set_permset(entry, permset);
182 }
183
184 int sys_acl_valid( SMB_ACL_T theacl )
185 {
186         return acl_valid(theacl);
187 }
188
189 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
190 {
191         return acl_set_file(name, acltype, theacl);
192 }
193
194 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
195 {
196         return acl_set_fd(fd, theacl);
197 }
198
199 int sys_acl_delete_def_file(const char *name)
200 {
201         return acl_delete_def_file(name);
202 }
203
204 int sys_acl_free_text(char *text)
205 {
206         return acl_free(text);
207 }
208
209 int sys_acl_free_acl(SMB_ACL_T the_acl) 
210 {
211         return acl_free(the_acl);
212 }
213
214 int sys_acl_free_qualifier(void *qual, UNUSED(SMB_ACL_TAG_T tagtype))
215 {
216         return acl_free(qual);
217 }
218
219 #elif defined(HAVE_TRU64_ACLS)
220 /*
221  * The interface to DEC/Compaq Tru64 UNIX ACLs
222  * is based on Draft 13 of the POSIX spec which is
223  * slightly different from the Draft 16 interface.
224  * 
225  * Also, some of the permset manipulation functions
226  * such as acl_clear_perm() and acl_add_perm() appear
227  * to be broken on Tru64 so we have to manipulate
228  * the permission bits in the permset directly.
229  */
230 int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
231 {
232         SMB_ACL_ENTRY_T entry;
233
234         if (entry_id == SMB_ACL_FIRST_ENTRY && acl_first_entry(the_acl) != 0) {
235                 return -1;
236         }
237
238         errno = 0;
239         if ((entry = acl_get_entry(the_acl)) != NULL) {
240                 *entry_p = entry;
241                 return 1;
242         }
243
244         return errno ? -1 : 0;
245 }
246
247 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
248 {
249         return acl_get_tag_type( entry_d, tag_type_p);
250 }
251
252 int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
253 {
254         return acl_get_permset( entry_d, permset_p);
255 }
256
257 void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
258 {
259         return acl_get_qualifier( entry_d);
260 }
261
262 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
263 {
264         return acl_get_file((char *)path_p, type);
265 }
266
267 SMB_ACL_T sys_acl_get_fd(int fd)
268 {
269         return acl_get_fd(fd, ACL_TYPE_ACCESS);
270 }
271
272 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
273 {
274         *permset = 0;           /* acl_clear_perm() is broken on Tru64  */
275
276         return 0;
277 }
278
279 int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
280 {
281         if (perm & ~(SMB_ACL_READ | SMB_ACL_WRITE | SMB_ACL_EXECUTE)) {
282                 errno = EINVAL;
283                 return -1;
284         }
285
286         *permset |= perm;       /* acl_add_perm() is broken on Tru64    */
287
288         return 0;
289 }
290
291 int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
292 {
293         return *permset & perm; /* Tru64 doesn't have acl_get_perm() */
294 }
295
296 char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
297 {
298         return acl_to_text( the_acl, plen);
299 }
300
301 SMB_ACL_T sys_acl_init( int count)
302 {
303         return acl_init(count);
304 }
305
306 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
307 {
308         SMB_ACL_ENTRY_T entry;
309
310         if ((entry = acl_create_entry(pacl)) == NULL) {
311                 return -1;
312         }
313
314         *pentry = entry;
315         return 0;
316 }
317
318 int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
319 {
320         return acl_set_tag_type(entry, tagtype);
321 }
322
323 int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
324 {
325         return acl_set_qualifier(entry, qual);
326 }
327
328 int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
329 {
330         return acl_set_permset(entry, permset);
331 }
332
333 int sys_acl_valid( SMB_ACL_T theacl )
334 {
335         acl_entry_t     entry;
336
337         return acl_valid(theacl, &entry);
338 }
339
340 int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
341 {
342         return acl_set_file((char *)name, acltype, theacl);
343 }
344
345 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
346 {
347         return acl_set_fd(fd, ACL_TYPE_ACCESS, theacl);
348 }
349
350 int sys_acl_delete_def_file(const char *name)
351 {
352         return acl_delete_def_file((char *)name);
353 }
354
355 int sys_acl_free_text(char *text)
356 {
357         /*
358          * (void) cast and explicit return 0 are for DEC UNIX
359          *  which just #defines acl_free_text() to be free()
360          */
361         (void) acl_free_text(text);
362         return 0;
363 }
364
365 int sys_acl_free_acl(SMB_ACL_T the_acl) 
366 {
367         return acl_free(the_acl);
368 }
369
370 int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
371 {
372         return acl_free_qualifier(qual, tagtype);
373 }
374
375 #elif defined(HAVE_UNIXWARE_ACLS) || defined(HAVE_SOLARIS_ACLS)
376
377 /*
378  * Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX.
379  * Modified by Toomas Soome <tsoome@ut.ee> for Solaris.
380  */
381
382 /*
383  * Note that while this code implements sufficient functionality
384  * to support the sys_acl_* interfaces it does not provide all
385  * of the semantics of the POSIX ACL interfaces.
386  *
387  * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
388  * from a call to sys_acl_get_entry() should not be assumed to be
389  * valid after calling any of the following functions, which may
390  * reorder the entries in the ACL.
391  *
392  *      sys_acl_valid()
393  *      sys_acl_set_file()
394  *      sys_acl_set_fd()
395  */
396
397 /*
398  * The only difference between Solaris and UnixWare / OpenUNIX is
399  * that the #defines for the ACL operations have different names
400  */
401 #if defined(HAVE_UNIXWARE_ACLS)
402
403 #define SETACL          ACL_SET
404 #define GETACL          ACL_GET
405 #define GETACLCNT       ACL_CNT
406
407 #endif
408
409
410 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
411 {
412         if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
413                 errno = EINVAL;
414                 return -1;
415         }
416
417         if (entry_p == NULL) {
418                 errno = EINVAL;
419                 return -1;
420         }
421
422         if (entry_id == SMB_ACL_FIRST_ENTRY) {
423                 acl_d->next = 0;
424         }
425
426         if (acl_d->next < 0) {
427                 errno = EINVAL;
428                 return -1;
429         }
430
431         if (acl_d->next >= acl_d->count) {
432                 return 0;
433         }
434
435         *entry_p = &acl_d->acl[acl_d->next++];
436
437         return 1;
438 }
439
440 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
441 {
442         *type_p = entry_d->a_type;
443
444         return 0;
445 }
446
447 int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
448 {
449         *permset_p = &entry_d->a_perm;
450
451         return 0;
452 }
453
454 void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
455 {
456         if (entry_d->a_type != SMB_ACL_USER
457             && entry_d->a_type != SMB_ACL_GROUP) {
458                 errno = EINVAL;
459                 return NULL;
460         }
461
462         return &entry_d->a_id;
463 }
464
465 /*
466  * There is no way of knowing what size the ACL returned by
467  * GETACL will be unless you first call GETACLCNT which means
468  * making an additional system call.
469  *
470  * In the hope of avoiding the cost of the additional system
471  * call in most cases, we initially allocate enough space for
472  * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
473  * be too small then we use GETACLCNT to find out the actual
474  * size, reallocate the ACL buffer, and then call GETACL again.
475  */
476
477 #define INITIAL_ACL_SIZE        16
478
479 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
480 {
481         SMB_ACL_T       acl_d;
482         int             count;          /* # of ACL entries allocated   */
483         int             naccess;        /* # of access ACL entries      */
484         int             ndefault;       /* # of default ACL entries     */
485
486         if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
487                 errno = EINVAL;
488                 return NULL;
489         }
490
491         count = INITIAL_ACL_SIZE;
492         if ((acl_d = sys_acl_init(count)) == NULL) {
493                 return NULL;
494         }
495
496         /*
497          * If there isn't enough space for the ACL entries we use
498          * GETACLCNT to determine the actual number of ACL entries
499          * reallocate and try again. This is in a loop because it
500          * is possible that someone else could modify the ACL and
501          * increase the number of entries between the call to
502          * GETACLCNT and the call to GETACL.
503          */
504         while ((count = acl(path_p, GETACL, count, &acl_d->acl[0])) < 0
505             && errno == ENOSPC) {
506
507                 sys_acl_free_acl(acl_d);
508
509                 if ((count = acl(path_p, GETACLCNT, 0, NULL)) < 0) {
510                         return NULL;
511                 }
512
513                 if ((acl_d = sys_acl_init(count)) == NULL) {
514                         return NULL;
515                 }
516         }
517
518         if (count < 0) {
519                 sys_acl_free_acl(acl_d);
520                 return NULL;
521         }
522
523         /*
524          * calculate the number of access and default ACL entries
525          *
526          * Note: we assume that the acl() system call returned a
527          * well formed ACL which is sorted so that all of the
528          * access ACL entries preceed any default ACL entries
529          */
530         for (naccess = 0; naccess < count; naccess++) {
531                 if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
532                         break;
533         }
534         ndefault = count - naccess;
535         
536         /*
537          * if the caller wants the default ACL we have to copy
538          * the entries down to the start of the acl[] buffer
539          * and mask out the ACL_DEFAULT flag from the type field
540          */
541         if (type == SMB_ACL_TYPE_DEFAULT) {
542                 int     i, j;
543
544                 for (i = 0, j = naccess; i < ndefault; i++, j++) {
545                         acl_d->acl[i] = acl_d->acl[j];
546                         acl_d->acl[i].a_type &= ~ACL_DEFAULT;
547                 }
548
549                 acl_d->count = ndefault;
550         } else {
551                 acl_d->count = naccess;
552         }
553
554         return acl_d;
555 }
556
557 SMB_ACL_T sys_acl_get_fd(int fd)
558 {
559         SMB_ACL_T       acl_d;
560         int             count;          /* # of ACL entries allocated   */
561         int             naccess;        /* # of access ACL entries      */
562
563         count = INITIAL_ACL_SIZE;
564         if ((acl_d = sys_acl_init(count)) == NULL) {
565                 return NULL;
566         }
567
568         while ((count = facl(fd, GETACL, count, &acl_d->acl[0])) < 0
569             && errno == ENOSPC) {
570
571                 sys_acl_free_acl(acl_d);
572
573                 if ((count = facl(fd, GETACLCNT, 0, NULL)) < 0) {
574                         return NULL;
575                 }
576
577                 if ((acl_d = sys_acl_init(count)) == NULL) {
578                         return NULL;
579                 }
580         }
581
582         if (count < 0) {
583                 sys_acl_free_acl(acl_d);
584                 return NULL;
585         }
586
587         /*
588          * calculate the number of access ACL entries
589          */
590         for (naccess = 0; naccess < count; naccess++) {
591                 if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
592                         break;
593         }
594         
595         acl_d->count = naccess;
596
597         return acl_d;
598 }
599
600 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
601 {
602         *permset_d = 0;
603
604         return 0;
605 }
606
607 int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
608 {
609         if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
610             && perm != SMB_ACL_EXECUTE) {
611                 errno = EINVAL;
612                 return -1;
613         }
614
615         if (permset_d == NULL) {
616                 errno = EINVAL;
617                 return -1;
618         }
619
620         *permset_d |= perm;
621
622         return 0;
623 }
624
625 int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
626 {
627         return *permset_d & perm;
628 }
629
630 char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
631 {
632         int     i;
633         int     len, maxlen;
634         char    *text;
635
636         /*
637          * use an initial estimate of 20 bytes per ACL entry
638          * when allocating memory for the text representation
639          * of the ACL
640          */
641         len     = 0;
642         maxlen  = 20 * acl_d->count;
643         if ((text = SMB_MALLOC(maxlen)) == NULL) {
644                 errno = ENOMEM;
645                 return NULL;
646         }
647
648         for (i = 0; i < acl_d->count; i++) {
649                 struct acl      *ap     = &acl_d->acl[i];
650                 struct group    *gr;
651                 char            tagbuf[12];
652                 char            idbuf[12];
653                 char            *tag;
654                 char            *id     = "";
655                 char            perms[4];
656                 int             nbytes;
657
658                 switch (ap->a_type) {
659                         /*
660                          * for debugging purposes it's probably more
661                          * useful to dump unknown tag types rather
662                          * than just returning an error
663                          */
664                         default:
665                                 slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
666                                         ap->a_type);
667                                 tag = tagbuf;
668                                 slprintf(idbuf, sizeof(idbuf)-1, "%ld",
669                                         (long)ap->a_id);
670                                 id = idbuf;
671                                 break;
672
673                         case SMB_ACL_USER:
674                                 id = uidtoname(ap->a_id);
675                         case SMB_ACL_USER_OBJ:
676                                 tag = "user";
677                                 break;
678
679                         case SMB_ACL_GROUP:
680                                 if ((gr = getgrgid(ap->a_id)) == NULL) {
681                                         slprintf(idbuf, sizeof(idbuf)-1, "%ld",
682                                                 (long)ap->a_id);
683                                         id = idbuf;
684                                 } else {
685                                         id = gr->gr_name;
686                                 }
687                         case SMB_ACL_GROUP_OBJ:
688                                 tag = "group";
689                                 break;
690
691                         case SMB_ACL_OTHER:
692                                 tag = "other";
693                                 break;
694
695                         case SMB_ACL_MASK:
696                                 tag = "mask";
697                                 break;
698
699                 }
700
701                 perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
702                 perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
703                 perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
704                 perms[3] = '\0';
705
706                 /*          <tag>      :  <qualifier>   :  rwx \n  \0 */
707                 nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
708
709                 /*
710                  * If this entry would overflow the buffer
711                  * allocate enough additional memory for this
712                  * entry and an estimate of another 20 bytes
713                  * for each entry still to be processed
714                  */
715                 if ((len + nbytes) > maxlen) {
716                         char *oldtext = text;
717
718                         maxlen += nbytes + 20 * (acl_d->count - i);
719
720                         if ((text = SMB_REALLOC(oldtext, maxlen)) == NULL) {
721                                 SAFE_FREE(oldtext);
722                                 errno = ENOMEM;
723                                 return NULL;
724                         }
725                 }
726
727                 slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
728                 len += nbytes - 1;
729         }
730
731         if (len_p)
732                 *len_p = len;
733
734         return text;
735 }
736
737 SMB_ACL_T sys_acl_init(int count)
738 {
739         SMB_ACL_T       a;
740
741         if (count < 0) {
742                 errno = EINVAL;
743                 return NULL;
744         }
745
746         /*
747          * note that since the definition of the structure pointed
748          * to by the SMB_ACL_T includes the first element of the
749          * acl[] array, this actually allocates an ACL with room
750          * for (count+1) entries
751          */
752         if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof(struct SMB_ACL_T) + count * sizeof(struct acl))) == NULL) {
753                 errno = ENOMEM;
754                 return NULL;
755         }
756
757         a->size = count + 1;
758         a->count = 0;
759         a->next = -1;
760
761         return a;
762 }
763
764
765 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
766 {
767         SMB_ACL_T       acl_d;
768         SMB_ACL_ENTRY_T entry_d;
769
770         if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
771                 errno = EINVAL;
772                 return -1;
773         }
774
775         if (acl_d->count >= acl_d->size) {
776                 errno = ENOSPC;
777                 return -1;
778         }
779
780         entry_d         = &acl_d->acl[acl_d->count++];
781         entry_d->a_type = 0;
782         entry_d->a_id   = -1;
783         entry_d->a_perm = 0;
784         *entry_p        = entry_d;
785
786         return 0;
787 }
788
789 int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
790 {
791         switch (tag_type) {
792                 case SMB_ACL_USER:
793                 case SMB_ACL_USER_OBJ:
794                 case SMB_ACL_GROUP:
795                 case SMB_ACL_GROUP_OBJ:
796                 case SMB_ACL_OTHER:
797                 case SMB_ACL_MASK:
798                         entry_d->a_type = tag_type;
799                         break;
800                 default:
801                         errno = EINVAL;
802                         return -1;
803         }
804
805         return 0;
806 }
807
808 int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
809 {
810         if (entry_d->a_type != SMB_ACL_GROUP
811             && entry_d->a_type != SMB_ACL_USER) {
812                 errno = EINVAL;
813                 return -1;
814         }
815
816         entry_d->a_id = *((id_t *)qual_p);
817
818         return 0;
819 }
820
821 int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
822 {
823         if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
824                 return EINVAL;
825         }
826
827         entry_d->a_perm = *permset_d;
828
829         return 0;
830 }
831
832 /*
833  * sort the ACL and check it for validity
834  *
835  * if it's a minimal ACL with only 4 entries then we
836  * need to recalculate the mask permissions to make
837  * sure that they are the same as the GROUP_OBJ
838  * permissions as required by the UnixWare acl() system call.
839  *
840  * (note: since POSIX allows minimal ACLs which only contain
841  * 3 entries - ie there is no mask entry - we should, in theory,
842  * check for this and add a mask entry if necessary - however
843  * we "know" that the caller of this interface always specifies
844  * a mask so, in practice "this never happens" (tm) - if it *does*
845  * happen aclsort() will fail and return an error and someone will
846  * have to fix it ...)
847  */
848
849 static int acl_sort(SMB_ACL_T acl_d)
850 {
851         int     fixmask = (acl_d->count <= 4);
852
853         if (aclsort(acl_d->count, fixmask, acl_d->acl) != 0) {
854                 errno = EINVAL;
855                 return -1;
856         }
857         return 0;
858 }
859  
860 int sys_acl_valid(SMB_ACL_T acl_d)
861 {
862         return acl_sort(acl_d);
863 }
864
865 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
866 {
867         struct stat     s;
868         struct acl      *acl_p;
869         int             acl_count;
870         struct acl      *acl_buf        = NULL;
871         int             ret;
872
873         if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
874                 errno = EINVAL;
875                 return -1;
876         }
877
878         if (acl_sort(acl_d) != 0) {
879                 return -1;
880         }
881
882         acl_p           = &acl_d->acl[0];
883         acl_count       = acl_d->count;
884
885         /*
886          * if it's a directory there is extra work to do
887          * since the acl() system call will replace both
888          * the access ACLs and the default ACLs (if any)
889          */
890         if (stat(name, &s) != 0) {
891                 return -1;
892         }
893         if (S_ISDIR(s.st_mode)) {
894                 SMB_ACL_T       acc_acl;
895                 SMB_ACL_T       def_acl;
896                 SMB_ACL_T       tmp_acl;
897                 int             i;
898
899                 if (type == SMB_ACL_TYPE_ACCESS) {
900                         acc_acl = acl_d;
901                         def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
902
903                 } else {
904                         def_acl = acl_d;
905                         acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
906                 }
907
908                 if (tmp_acl == NULL) {
909                         return -1;
910                 }
911
912                 /*
913                  * allocate a temporary buffer for the complete ACL
914                  */
915                 acl_count = acc_acl->count + def_acl->count;
916                 acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count);
917
918                 if (acl_buf == NULL) {
919                         sys_acl_free_acl(tmp_acl);
920                         errno = ENOMEM;
921                         return -1;
922                 }
923
924                 /*
925                  * copy the access control and default entries into the buffer
926                  */
927                 memcpy(&acl_buf[0], &acc_acl->acl[0],
928                         acc_acl->count * sizeof(acl_buf[0]));
929
930                 memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
931                         def_acl->count * sizeof(acl_buf[0]));
932
933                 /*
934                  * set the ACL_DEFAULT flag on the default entries
935                  */
936                 for (i = acc_acl->count; i < acl_count; i++) {
937                         acl_buf[i].a_type |= ACL_DEFAULT;
938                 }
939
940                 sys_acl_free_acl(tmp_acl);
941
942         } else if (type != SMB_ACL_TYPE_ACCESS) {
943                 errno = EINVAL;
944                 return -1;
945         }
946
947         ret = acl(name, SETACL, acl_count, acl_p);
948
949         SAFE_FREE(acl_buf);
950
951         return ret;
952 }
953
954 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
955 {
956         if (acl_sort(acl_d) != 0) {
957                 return -1;
958         }
959
960         return facl(fd, SETACL, acl_d->count, &acl_d->acl[0]);
961 }
962
963 int sys_acl_delete_def_file(const char *path)
964 {
965         SMB_ACL_T       acl_d;
966         int             ret;
967
968         /*
969          * fetching the access ACL and rewriting it has
970          * the effect of deleting the default ACL
971          */
972         if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
973                 return -1;
974         }
975
976         ret = acl(path, SETACL, acl_d->count, acl_d->acl);
977
978         sys_acl_free_acl(acl_d);
979         
980         return ret;
981 }
982
983 int sys_acl_free_text(char *text)
984 {
985         SAFE_FREE(text);
986         return 0;
987 }
988
989 int sys_acl_free_acl(SMB_ACL_T acl_d) 
990 {
991         SAFE_FREE(acl_d);
992         return 0;
993 }
994
995 int sys_acl_free_qualifier(UNUSED(void *qual), UNUSED(SMB_ACL_TAG_T tagtype))
996 {
997         return 0;
998 }
999
1000 #elif defined(HAVE_HPUX_ACLS)
1001 #include <dl.h>
1002
1003 /*
1004  * Based on the Solaris/SCO code - with modifications.
1005  */
1006
1007 /*
1008  * Note that while this code implements sufficient functionality
1009  * to support the sys_acl_* interfaces it does not provide all
1010  * of the semantics of the POSIX ACL interfaces.
1011  *
1012  * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
1013  * from a call to sys_acl_get_entry() should not be assumed to be
1014  * valid after calling any of the following functions, which may
1015  * reorder the entries in the ACL.
1016  *
1017  *      sys_acl_valid()
1018  *      sys_acl_set_file()
1019  *      sys_acl_set_fd()
1020  */
1021
1022 /* This checks if the POSIX ACL system call is defined */
1023 /* which basically corresponds to whether JFS 3.3 or   */
1024 /* higher is installed. If acl() was called when it    */
1025 /* isn't defined, it causes the process to core dump   */
1026 /* so it is important to check this and avoid acl()    */
1027 /* calls if it isn't there.                            */
1028
1029 static BOOL hpux_acl_call_presence(void)
1030 {
1031
1032         shl_t handle = NULL;
1033         void *value;
1034         int ret_val=0;
1035         static BOOL already_checked=0;
1036
1037         if(already_checked)
1038                 return True;
1039
1040
1041         ret_val = shl_findsym(&handle, "acl", TYPE_PROCEDURE, &value);
1042
1043         if(ret_val != 0) {
1044                 DEBUG(5, ("hpux_acl_call_presence: shl_findsym() returned %d, errno = %d, error %s\n",
1045                         ret_val, errno, strerror(errno)));
1046                 DEBUG(5,("hpux_acl_call_presence: acl() system call is not present. Check if you have JFS 3.3 and above?\n"));
1047                 return False;
1048         }
1049
1050         DEBUG(10,("hpux_acl_call_presence: acl() system call is present. We have JFS 3.3 or above \n"));
1051
1052         already_checked = True;
1053         return True;
1054 }
1055
1056 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
1057 {
1058         if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
1059                 errno = EINVAL;
1060                 return -1;
1061         }
1062
1063         if (entry_p == NULL) {
1064                 errno = EINVAL;
1065                 return -1;
1066         }
1067
1068         if (entry_id == SMB_ACL_FIRST_ENTRY) {
1069                 acl_d->next = 0;
1070         }
1071
1072         if (acl_d->next < 0) {
1073                 errno = EINVAL;
1074                 return -1;
1075         }
1076
1077         if (acl_d->next >= acl_d->count) {
1078                 return 0;
1079         }
1080
1081         *entry_p = &acl_d->acl[acl_d->next++];
1082
1083         return 1;
1084 }
1085
1086 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
1087 {
1088         *type_p = entry_d->a_type;
1089
1090         return 0;
1091 }
1092
1093 int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
1094 {
1095         *permset_p = &entry_d->a_perm;
1096
1097         return 0;
1098 }
1099
1100 void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
1101 {
1102         if (entry_d->a_type != SMB_ACL_USER
1103             && entry_d->a_type != SMB_ACL_GROUP) {
1104                 errno = EINVAL;
1105                 return NULL;
1106         }
1107
1108         return &entry_d->a_id;
1109 }
1110
1111 /*
1112  * There is no way of knowing what size the ACL returned by
1113  * ACL_GET will be unless you first call ACL_CNT which means
1114  * making an additional system call.
1115  *
1116  * In the hope of avoiding the cost of the additional system
1117  * call in most cases, we initially allocate enough space for
1118  * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
1119  * be too small then we use ACL_CNT to find out the actual
1120  * size, reallocate the ACL buffer, and then call ACL_GET again.
1121  */
1122
1123 #define INITIAL_ACL_SIZE        16
1124
1125 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
1126 {
1127         SMB_ACL_T       acl_d;
1128         int             count;          /* # of ACL entries allocated   */
1129         int             naccess;        /* # of access ACL entries      */
1130         int             ndefault;       /* # of default ACL entries     */
1131
1132         if(hpux_acl_call_presence() == False) {
1133                 /* Looks like we don't have the acl() system call on HPUX. 
1134                  * May be the system doesn't have the latest version of JFS.
1135                  */
1136                 return NULL; 
1137         }
1138
1139         if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
1140                 errno = EINVAL;
1141                 return NULL;
1142         }
1143
1144         count = INITIAL_ACL_SIZE;
1145         if ((acl_d = sys_acl_init(count)) == NULL) {
1146                 return NULL;
1147         }
1148
1149         /*
1150          * If there isn't enough space for the ACL entries we use
1151          * ACL_CNT to determine the actual number of ACL entries
1152          * reallocate and try again. This is in a loop because it
1153          * is possible that someone else could modify the ACL and
1154          * increase the number of entries between the call to
1155          * ACL_CNT and the call to ACL_GET.
1156          */
1157         while ((count = acl(path_p, ACL_GET, count, &acl_d->acl[0])) < 0 && errno == ENOSPC) {
1158
1159                 sys_acl_free_acl(acl_d);
1160
1161                 if ((count = acl(path_p, ACL_CNT, 0, NULL)) < 0) {
1162                         return NULL;
1163                 }
1164
1165                 if ((acl_d = sys_acl_init(count)) == NULL) {
1166                         return NULL;
1167                 }
1168         }
1169
1170         if (count < 0) {
1171                 sys_acl_free_acl(acl_d);
1172                 return NULL;
1173         }
1174
1175         /*
1176          * calculate the number of access and default ACL entries
1177          *
1178          * Note: we assume that the acl() system call returned a
1179          * well formed ACL which is sorted so that all of the
1180          * access ACL entries preceed any default ACL entries
1181          */
1182         for (naccess = 0; naccess < count; naccess++) {
1183                 if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
1184                         break;
1185         }
1186         ndefault = count - naccess;
1187         
1188         /*
1189          * if the caller wants the default ACL we have to copy
1190          * the entries down to the start of the acl[] buffer
1191          * and mask out the ACL_DEFAULT flag from the type field
1192          */
1193         if (type == SMB_ACL_TYPE_DEFAULT) {
1194                 int     i, j;
1195
1196                 for (i = 0, j = naccess; i < ndefault; i++, j++) {
1197                         acl_d->acl[i] = acl_d->acl[j];
1198                         acl_d->acl[i].a_type &= ~ACL_DEFAULT;
1199                 }
1200
1201                 acl_d->count = ndefault;
1202         } else {
1203                 acl_d->count = naccess;
1204         }
1205
1206         return acl_d;
1207 }
1208
1209 #if 0
1210 SMB_ACL_T sys_acl_get_fd(int fd)
1211 {
1212         /*
1213          * HPUX doesn't have the facl call. Fake it using the path.... JRA.
1214          */
1215
1216         files_struct *fsp = file_find_fd(fd);
1217
1218         if (fsp == NULL) {
1219                 errno = EBADF;
1220                 return NULL;
1221         }
1222
1223         /*
1224          * We know we're in the same conn context. So we
1225          * can use the relative path.
1226          */
1227
1228         return sys_acl_get_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
1229 }
1230 #endif
1231
1232 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
1233 {
1234         *permset_d = 0;
1235
1236         return 0;
1237 }
1238
1239 int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
1240 {
1241         if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
1242             && perm != SMB_ACL_EXECUTE) {
1243                 errno = EINVAL;
1244                 return -1;
1245         }
1246
1247         if (permset_d == NULL) {
1248                 errno = EINVAL;
1249                 return -1;
1250         }
1251
1252         *permset_d |= perm;
1253
1254         return 0;
1255 }
1256
1257 int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
1258 {
1259         return *permset_d & perm;
1260 }
1261
1262 char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
1263 {
1264         int     i;
1265         int     len, maxlen;
1266         char    *text;
1267
1268         /*
1269          * use an initial estimate of 20 bytes per ACL entry
1270          * when allocating memory for the text representation
1271          * of the ACL
1272          */
1273         len     = 0;
1274         maxlen  = 20 * acl_d->count;
1275         if ((text = SMB_MALLOC(maxlen)) == NULL) {
1276                 errno = ENOMEM;
1277                 return NULL;
1278         }
1279
1280         for (i = 0; i < acl_d->count; i++) {
1281                 struct acl      *ap     = &acl_d->acl[i];
1282                 struct group    *gr;
1283                 char            tagbuf[12];
1284                 char            idbuf[12];
1285                 char            *tag;
1286                 char            *id     = "";
1287                 char            perms[4];
1288                 int             nbytes;
1289
1290                 switch (ap->a_type) {
1291                         /*
1292                          * for debugging purposes it's probably more
1293                          * useful to dump unknown tag types rather
1294                          * than just returning an error
1295                          */
1296                         default:
1297                                 slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
1298                                         ap->a_type);
1299                                 tag = tagbuf;
1300                                 slprintf(idbuf, sizeof(idbuf)-1, "%ld",
1301                                         (long)ap->a_id);
1302                                 id = idbuf;
1303                                 break;
1304
1305                         case SMB_ACL_USER:
1306                                 id = uidtoname(ap->a_id);
1307                         case SMB_ACL_USER_OBJ:
1308                                 tag = "user";
1309                                 break;
1310
1311                         case SMB_ACL_GROUP:
1312                                 if ((gr = getgrgid(ap->a_id)) == NULL) {
1313                                         slprintf(idbuf, sizeof(idbuf)-1, "%ld",
1314                                                 (long)ap->a_id);
1315                                         id = idbuf;
1316                                 } else {
1317                                         id = gr->gr_name;
1318                                 }
1319                         case SMB_ACL_GROUP_OBJ:
1320                                 tag = "group";
1321                                 break;
1322
1323                         case SMB_ACL_OTHER:
1324                                 tag = "other";
1325                                 break;
1326
1327                         case SMB_ACL_MASK:
1328                                 tag = "mask";
1329                                 break;
1330
1331                 }
1332
1333                 perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
1334                 perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
1335                 perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
1336                 perms[3] = '\0';
1337
1338                 /*          <tag>      :  <qualifier>   :  rwx \n  \0 */
1339                 nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
1340
1341                 /*
1342                  * If this entry would overflow the buffer
1343                  * allocate enough additional memory for this
1344                  * entry and an estimate of another 20 bytes
1345                  * for each entry still to be processed
1346                  */
1347                 if ((len + nbytes) > maxlen) {
1348                         char *oldtext = text;
1349
1350                         maxlen += nbytes + 20 * (acl_d->count - i);
1351
1352                         if ((text = SMB_REALLOC(oldtext, maxlen)) == NULL) {
1353                                 free(oldtext);
1354                                 errno = ENOMEM;
1355                                 return NULL;
1356                         }
1357                 }
1358
1359                 slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
1360                 len += nbytes - 1;
1361         }
1362
1363         if (len_p)
1364                 *len_p = len;
1365
1366         return text;
1367 }
1368
1369 SMB_ACL_T sys_acl_init(int count)
1370 {
1371         SMB_ACL_T       a;
1372
1373         if (count < 0) {
1374                 errno = EINVAL;
1375                 return NULL;
1376         }
1377
1378         /*
1379          * note that since the definition of the structure pointed
1380          * to by the SMB_ACL_T includes the first element of the
1381          * acl[] array, this actually allocates an ACL with room
1382          * for (count+1) entries
1383          */
1384         if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + count * sizeof(struct acl))) == NULL) {
1385                 errno = ENOMEM;
1386                 return NULL;
1387         }
1388
1389         a->size = count + 1;
1390         a->count = 0;
1391         a->next = -1;
1392
1393         return a;
1394 }
1395
1396
1397 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
1398 {
1399         SMB_ACL_T       acl_d;
1400         SMB_ACL_ENTRY_T entry_d;
1401
1402         if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
1403                 errno = EINVAL;
1404                 return -1;
1405         }
1406
1407         if (acl_d->count >= acl_d->size) {
1408                 errno = ENOSPC;
1409                 return -1;
1410         }
1411
1412         entry_d         = &acl_d->acl[acl_d->count++];
1413         entry_d->a_type = 0;
1414         entry_d->a_id   = -1;
1415         entry_d->a_perm = 0;
1416         *entry_p        = entry_d;
1417
1418         return 0;
1419 }
1420
1421 int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
1422 {
1423         switch (tag_type) {
1424                 case SMB_ACL_USER:
1425                 case SMB_ACL_USER_OBJ:
1426                 case SMB_ACL_GROUP:
1427                 case SMB_ACL_GROUP_OBJ:
1428                 case SMB_ACL_OTHER:
1429                 case SMB_ACL_MASK:
1430                         entry_d->a_type = tag_type;
1431                         break;
1432                 default:
1433                         errno = EINVAL;
1434                         return -1;
1435         }
1436
1437         return 0;
1438 }
1439
1440 int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
1441 {
1442         if (entry_d->a_type != SMB_ACL_GROUP
1443             && entry_d->a_type != SMB_ACL_USER) {
1444                 errno = EINVAL;
1445                 return -1;
1446         }
1447
1448         entry_d->a_id = *((id_t *)qual_p);
1449
1450         return 0;
1451 }
1452
1453 int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
1454 {
1455         if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
1456                 return EINVAL;
1457         }
1458
1459         entry_d->a_perm = *permset_d;
1460
1461         return 0;
1462 }
1463
1464 /* Structure to capture the count for each type of ACE. */
1465
1466 struct hpux_acl_types {
1467         int n_user;
1468         int n_def_user;
1469         int n_user_obj;
1470         int n_def_user_obj;
1471
1472         int n_group;
1473         int n_def_group;
1474         int n_group_obj;
1475         int n_def_group_obj;
1476
1477         int n_other;
1478         int n_other_obj;
1479         int n_def_other_obj;
1480
1481         int n_class_obj;
1482         int n_def_class_obj;
1483
1484         int n_illegal_obj;
1485 };
1486
1487 /* count_obj:
1488  * Counts the different number of objects in a given array of ACL
1489  * structures.
1490  * Inputs:
1491  *
1492  * acl_count      - Count of ACLs in the array of ACL strucutres.
1493  * aclp           - Array of ACL structures.
1494  * acl_type_count - Pointer to acl_types structure. Should already be
1495  *                  allocated.
1496  * Output: 
1497  *
1498  * acl_type_count - This structure is filled up with counts of various 
1499  *                  acl types.
1500  */
1501
1502 static int hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_types *acl_type_count)
1503 {
1504         int i;
1505
1506         memset(acl_type_count, 0, sizeof(struct hpux_acl_types));
1507
1508         for(i=0;i<acl_count;i++) {
1509                 switch(aclp[i].a_type) {
1510                 case USER: 
1511                         acl_type_count->n_user++;
1512                         break;
1513                 case USER_OBJ: 
1514                         acl_type_count->n_user_obj++;
1515                         break;
1516                 case DEF_USER_OBJ: 
1517                         acl_type_count->n_def_user_obj++;
1518                         break;
1519                 case GROUP: 
1520                         acl_type_count->n_group++;
1521                         break;
1522                 case GROUP_OBJ: 
1523                         acl_type_count->n_group_obj++;
1524                         break;
1525                 case DEF_GROUP_OBJ: 
1526                         acl_type_count->n_def_group_obj++;
1527                         break;
1528                 case OTHER_OBJ: 
1529                         acl_type_count->n_other_obj++;
1530                         break;
1531                 case DEF_OTHER_OBJ: 
1532                         acl_type_count->n_def_other_obj++;
1533                         break;
1534                 case CLASS_OBJ:
1535                         acl_type_count->n_class_obj++;
1536                         break;
1537                 case DEF_CLASS_OBJ:
1538                         acl_type_count->n_def_class_obj++;
1539                         break;
1540                 case DEF_USER:
1541                         acl_type_count->n_def_user++;
1542                         break;
1543                 case DEF_GROUP:
1544                         acl_type_count->n_def_group++;
1545                         break;
1546                 default: 
1547                         acl_type_count->n_illegal_obj++;
1548                         break;
1549                 }
1550         }
1551 }
1552
1553 /* swap_acl_entries:  Swaps two ACL entries. 
1554  *
1555  * Inputs: aclp0, aclp1 - ACL entries to be swapped.
1556  */
1557
1558 static void hpux_swap_acl_entries(struct acl *aclp0, struct acl *aclp1)
1559 {
1560         struct acl temp_acl;
1561
1562         temp_acl.a_type = aclp0->a_type;
1563         temp_acl.a_id = aclp0->a_id;
1564         temp_acl.a_perm = aclp0->a_perm;
1565
1566         aclp0->a_type = aclp1->a_type;
1567         aclp0->a_id = aclp1->a_id;
1568         aclp0->a_perm = aclp1->a_perm;
1569
1570         aclp1->a_type = temp_acl.a_type;
1571         aclp1->a_id = temp_acl.a_id;
1572         aclp1->a_perm = temp_acl.a_perm;
1573 }
1574
1575 /* prohibited_duplicate_type
1576  * Identifies if given ACL type can have duplicate entries or 
1577  * not.
1578  *
1579  * Inputs: acl_type - ACL Type.
1580  *
1581  * Outputs: 
1582  *
1583  * Return.. 
1584  *
1585  * True - If the ACL type matches any of the prohibited types.
1586  * False - If the ACL type doesn't match any of the prohibited types.
1587  */ 
1588
1589 static BOOL hpux_prohibited_duplicate_type(int acl_type)
1590 {
1591         switch(acl_type) {
1592                 case USER:
1593                 case GROUP:
1594                 case DEF_USER: 
1595                 case DEF_GROUP:
1596                         return True;
1597                 default:
1598                         return False;
1599         }
1600 }
1601
1602 /* get_needed_class_perm
1603  * Returns the permissions of a ACL structure only if the ACL
1604  * type matches one of the pre-determined types for computing 
1605  * CLASS_OBJ permissions.
1606  *
1607  * Inputs: aclp - Pointer to ACL structure.
1608  */
1609
1610 static int hpux_get_needed_class_perm(struct acl *aclp)
1611 {
1612         switch(aclp->a_type) {
1613                 case USER: 
1614                 case GROUP_OBJ: 
1615                 case GROUP: 
1616                 case DEF_USER_OBJ: 
1617                 case DEF_USER:
1618                 case DEF_GROUP_OBJ: 
1619                 case DEF_GROUP:
1620                 case DEF_CLASS_OBJ:
1621                 case DEF_OTHER_OBJ: 
1622                         return aclp->a_perm;
1623                 default: 
1624                         return 0;
1625         }
1626 }
1627
1628 /* acl_sort for HPUX.
1629  * Sorts the array of ACL structures as per the description in
1630  * aclsort man page. Refer to aclsort man page for more details
1631  *
1632  * Inputs:
1633  *
1634  * acl_count - Count of ACLs in the array of ACL structures.
1635  * calclass  - If this is not zero, then we compute the CLASS_OBJ
1636  *             permissions.
1637  * aclp      - Array of ACL structures.
1638  *
1639  * Outputs:
1640  *
1641  * aclp     - Sorted array of ACL structures.
1642  *
1643  * Outputs:
1644  *
1645  * Returns 0 for success -1 for failure. Prints a message to the Samba
1646  * debug log in case of failure.
1647  */
1648
1649 static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
1650 {
1651 #if !defined(HAVE_HPUX_ACLSORT)
1652         /*
1653          * The aclsort() system call is availabe on the latest HPUX General
1654          * Patch Bundles. So for HPUX, we developed our version of acl_sort 
1655          * function. Because, we don't want to update to a new 
1656          * HPUX GR bundle just for aclsort() call.
1657          */
1658
1659         struct hpux_acl_types acl_obj_count;
1660         int n_class_obj_perm = 0;
1661         int i, j;
1662  
1663         if(!acl_count) {
1664                 DEBUG(10,("Zero acl count passed. Returning Success\n"));
1665                 return 0;
1666         }
1667
1668         if(aclp == NULL) {
1669                 DEBUG(0,("Null ACL pointer in hpux_acl_sort. Returning Failure. \n"));
1670                 return -1;
1671         }
1672
1673         /* Count different types of ACLs in the ACLs array */
1674
1675         hpux_count_obj(acl_count, aclp, &acl_obj_count);
1676
1677         /* There should be only one entry each of type USER_OBJ, GROUP_OBJ, 
1678          * CLASS_OBJ and OTHER_OBJ 
1679          */
1680
1681         if( (acl_obj_count.n_user_obj  != 1) || 
1682                 (acl_obj_count.n_group_obj != 1) || 
1683                 (acl_obj_count.n_class_obj != 1) ||
1684                 (acl_obj_count.n_other_obj != 1) 
1685         ) {
1686                 DEBUG(0,("hpux_acl_sort: More than one entry or no entries for \
1687 USER OBJ or GROUP_OBJ or OTHER_OBJ or CLASS_OBJ\n"));
1688                 return -1;
1689         }
1690
1691         /* If any of the default objects are present, there should be only
1692          * one of them each.
1693          */
1694
1695         if( (acl_obj_count.n_def_user_obj  > 1) || (acl_obj_count.n_def_group_obj > 1) || 
1696                         (acl_obj_count.n_def_other_obj > 1) || (acl_obj_count.n_def_class_obj > 1) ) {
1697                 DEBUG(0,("hpux_acl_sort: More than one entry for DEF_CLASS_OBJ \
1698 or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
1699                 return -1;
1700         }
1701
1702         /* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl 
1703          * structures.  
1704          *
1705          * Sorting crieteria - First sort by ACL type. If there are multiple entries of
1706          * same ACL type, sort by ACL id.
1707          *
1708          * I am using the trival kind of sorting method here because, performance isn't 
1709          * really effected by the ACLs feature. More over there aren't going to be more
1710          * than 17 entries on HPUX. 
1711          */
1712
1713         for(i=0; i<acl_count;i++) {
1714                 for (j=i+1; j<acl_count; j++) {
1715                         if( aclp[i].a_type > aclp[j].a_type ) {
1716                                 /* ACL entries out of order, swap them */
1717
1718                                 hpux_swap_acl_entries((aclp+i), (aclp+j));
1719
1720                         } else if ( aclp[i].a_type == aclp[j].a_type ) {
1721
1722                                 /* ACL entries of same type, sort by id */
1723
1724                                 if(aclp[i].a_id > aclp[j].a_id) {
1725                                         hpux_swap_acl_entries((aclp+i), (aclp+j));
1726                                 } else if (aclp[i].a_id == aclp[j].a_id) {
1727                                         /* We have a duplicate entry. */
1728                                         if(hpux_prohibited_duplicate_type(aclp[i].a_type)) {
1729                                                 DEBUG(0, ("hpux_acl_sort: Duplicate entry: Type(hex): %x Id: %d\n",
1730                                                         aclp[i].a_type, aclp[i].a_id));
1731                                                 return -1;
1732                                         }
1733                                 }
1734
1735                         }
1736                 }
1737         }
1738
1739         /* set the class obj permissions to the computed one. */
1740         if(calclass) {
1741                 int n_class_obj_index = -1;
1742
1743                 for(i=0;i<acl_count;i++) {
1744                         n_class_obj_perm |= hpux_get_needed_class_perm((aclp+i));
1745
1746                         if(aclp[i].a_type == CLASS_OBJ)
1747                                 n_class_obj_index = i;
1748                 }
1749                 aclp[n_class_obj_index].a_perm = n_class_obj_perm;
1750         }
1751
1752         return 0;
1753 #else
1754         return aclsort(acl_count, calclass, aclp);
1755 #endif
1756 }
1757
1758 /*
1759  * sort the ACL and check it for validity
1760  *
1761  * if it's a minimal ACL with only 4 entries then we
1762  * need to recalculate the mask permissions to make
1763  * sure that they are the same as the GROUP_OBJ
1764  * permissions as required by the UnixWare acl() system call.
1765  *
1766  * (note: since POSIX allows minimal ACLs which only contain
1767  * 3 entries - ie there is no mask entry - we should, in theory,
1768  * check for this and add a mask entry if necessary - however
1769  * we "know" that the caller of this interface always specifies
1770  * a mask so, in practice "this never happens" (tm) - if it *does*
1771  * happen aclsort() will fail and return an error and someone will
1772  * have to fix it ...)
1773  */
1774
1775 static int acl_sort(SMB_ACL_T acl_d)
1776 {
1777         int fixmask = (acl_d->count <= 4);
1778
1779         if (hpux_acl_sort(acl_d->count, fixmask, acl_d->acl) != 0) {
1780                 errno = EINVAL;
1781                 return -1;
1782         }
1783         return 0;
1784 }
1785  
1786 int sys_acl_valid(SMB_ACL_T acl_d)
1787 {
1788         return acl_sort(acl_d);
1789 }
1790
1791 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
1792 {
1793         struct stat     s;
1794         struct acl      *acl_p;
1795         int             acl_count;
1796         struct acl      *acl_buf        = NULL;
1797         int             ret;
1798
1799         if(hpux_acl_call_presence() == False) {
1800                 /* Looks like we don't have the acl() system call on HPUX. 
1801                  * May be the system doesn't have the latest version of JFS.
1802                  */
1803                 errno=ENOSYS;
1804                 return -1; 
1805         }
1806
1807         if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
1808                 errno = EINVAL;
1809                 return -1;
1810         }
1811
1812         if (acl_sort(acl_d) != 0) {
1813                 return -1;
1814         }
1815
1816         acl_p           = &acl_d->acl[0];
1817         acl_count       = acl_d->count;
1818
1819         /*
1820          * if it's a directory there is extra work to do
1821          * since the acl() system call will replace both
1822          * the access ACLs and the default ACLs (if any)
1823          */
1824         if (stat(name, &s) != 0) {
1825                 return -1;
1826         }
1827         if (S_ISDIR(s.st_mode)) {
1828                 SMB_ACL_T       acc_acl;
1829                 SMB_ACL_T       def_acl;
1830                 SMB_ACL_T       tmp_acl;
1831                 int             i;
1832
1833                 if (type == SMB_ACL_TYPE_ACCESS) {
1834                         acc_acl = acl_d;
1835                         def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
1836
1837                 } else {
1838                         def_acl = acl_d;
1839                         acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
1840                 }
1841
1842                 if (tmp_acl == NULL) {
1843                         return -1;
1844                 }
1845
1846                 /*
1847                  * allocate a temporary buffer for the complete ACL
1848                  */
1849                 acl_count = acc_acl->count + def_acl->count;
1850                 acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count);
1851
1852                 if (acl_buf == NULL) {
1853                         sys_acl_free_acl(tmp_acl);
1854                         errno = ENOMEM;
1855                         return -1;
1856                 }
1857
1858                 /*
1859                  * copy the access control and default entries into the buffer
1860                  */
1861                 memcpy(&acl_buf[0], &acc_acl->acl[0],
1862                         acc_acl->count * sizeof(acl_buf[0]));
1863
1864                 memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
1865                         def_acl->count * sizeof(acl_buf[0]));
1866
1867                 /*
1868                  * set the ACL_DEFAULT flag on the default entries
1869                  */
1870                 for (i = acc_acl->count; i < acl_count; i++) {
1871                         acl_buf[i].a_type |= ACL_DEFAULT;
1872                 }
1873
1874                 sys_acl_free_acl(tmp_acl);
1875
1876         } else if (type != SMB_ACL_TYPE_ACCESS) {
1877                 errno = EINVAL;
1878                 return -1;
1879         }
1880
1881         ret = acl(name, ACL_SET, acl_count, acl_p);
1882
1883         if (acl_buf) {
1884                 free(acl_buf);
1885         }
1886
1887         return ret;
1888 }
1889
1890 #if 0
1891 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
1892 {
1893         /*
1894          * HPUX doesn't have the facl call. Fake it using the path.... JRA.
1895          */
1896
1897         files_struct *fsp = file_find_fd(fd);
1898
1899         if (fsp == NULL) {
1900                 errno = EBADF;
1901                 return NULL;
1902         }
1903
1904         if (acl_sort(acl_d) != 0) {
1905                 return -1;
1906         }
1907
1908         /*
1909          * We know we're in the same conn context. So we
1910          * can use the relative path.
1911          */
1912
1913         return sys_acl_set_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS, acl_d);
1914 }
1915 #endif
1916
1917 int sys_acl_delete_def_file(const char *path)
1918 {
1919         SMB_ACL_T       acl_d;
1920         int             ret;
1921
1922         /*
1923          * fetching the access ACL and rewriting it has
1924          * the effect of deleting the default ACL
1925          */
1926         if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
1927                 return -1;
1928         }
1929
1930         ret = acl(path, ACL_SET, acl_d->count, acl_d->acl);
1931
1932         sys_acl_free_acl(acl_d);
1933         
1934         return ret;
1935 }
1936
1937 int sys_acl_free_text(char *text)
1938 {
1939         free(text);
1940         return 0;
1941 }
1942
1943 int sys_acl_free_acl(SMB_ACL_T acl_d) 
1944 {
1945         free(acl_d);
1946         return 0;
1947 }
1948
1949 int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
1950 {
1951         return 0;
1952 }
1953
1954 #elif defined(HAVE_IRIX_ACLS)
1955
1956 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
1957 {
1958         if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
1959                 errno = EINVAL;
1960                 return -1;
1961         }
1962
1963         if (entry_p == NULL) {
1964                 errno = EINVAL;
1965                 return -1;
1966         }
1967
1968         if (entry_id == SMB_ACL_FIRST_ENTRY) {
1969                 acl_d->next = 0;
1970         }
1971
1972         if (acl_d->next < 0) {
1973                 errno = EINVAL;
1974                 return -1;
1975         }
1976
1977         if (acl_d->next >= acl_d->aclp->acl_cnt) {
1978                 return 0;
1979         }
1980
1981         *entry_p = &acl_d->aclp->acl_entry[acl_d->next++];
1982
1983         return 1;
1984 }
1985
1986 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
1987 {
1988         *type_p = entry_d->ae_tag;
1989
1990         return 0;
1991 }
1992
1993 int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
1994 {
1995         *permset_p = entry_d;
1996
1997         return 0;
1998 }
1999
2000 void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
2001 {
2002         if (entry_d->ae_tag != SMB_ACL_USER
2003             && entry_d->ae_tag != SMB_ACL_GROUP) {
2004                 errno = EINVAL;
2005                 return NULL;
2006         }
2007
2008         return &entry_d->ae_id;
2009 }
2010
2011 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
2012 {
2013         SMB_ACL_T       a;
2014
2015         if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
2016                 errno = ENOMEM;
2017                 return NULL;
2018         }
2019         if ((a->aclp = acl_get_file(path_p, type)) == NULL) {
2020                 SAFE_FREE(a);
2021                 return NULL;
2022         }
2023         a->next = -1;
2024         a->freeaclp = True;
2025         return a;
2026 }
2027
2028 SMB_ACL_T sys_acl_get_fd(int fd)
2029 {
2030         SMB_ACL_T       a;
2031
2032         if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
2033                 errno = ENOMEM;
2034                 return NULL;
2035         }
2036         if ((a->aclp = acl_get_fd(fd)) == NULL) {
2037                 SAFE_FREE(a);
2038                 return NULL;
2039         }
2040         a->next = -1;
2041         a->freeaclp = True;
2042         return a;
2043 }
2044
2045 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
2046 {
2047         permset_d->ae_perm = 0;
2048
2049         return 0;
2050 }
2051
2052 int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
2053 {
2054         if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
2055             && perm != SMB_ACL_EXECUTE) {
2056                 errno = EINVAL;
2057                 return -1;
2058         }
2059
2060         if (permset_d == NULL) {
2061                 errno = EINVAL;
2062                 return -1;
2063         }
2064
2065         permset_d->ae_perm |= perm;
2066
2067         return 0;
2068 }
2069
2070 int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
2071 {
2072         return permset_d->ae_perm & perm;
2073 }
2074
2075 char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
2076 {
2077         return acl_to_text(acl_d->aclp, len_p);
2078 }
2079
2080 SMB_ACL_T sys_acl_init(int count)
2081 {
2082         SMB_ACL_T       a;
2083
2084         if (count < 0) {
2085                 errno = EINVAL;
2086                 return NULL;
2087         }
2088
2089         if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + sizeof(struct acl))) == NULL) {
2090                 errno = ENOMEM;
2091                 return NULL;
2092         }
2093
2094         a->next = -1;
2095         a->freeaclp = False;
2096         a->aclp = (struct acl *)(&a->aclp + sizeof(struct acl *));
2097         a->aclp->acl_cnt = 0;
2098
2099         return a;
2100 }
2101
2102
2103 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
2104 {
2105         SMB_ACL_T       acl_d;
2106         SMB_ACL_ENTRY_T entry_d;
2107
2108         if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
2109                 errno = EINVAL;
2110                 return -1;
2111         }
2112
2113         if (acl_d->aclp->acl_cnt >= ACL_MAX_ENTRIES) {
2114                 errno = ENOSPC;
2115                 return -1;
2116         }
2117
2118         entry_d         = &acl_d->aclp->acl_entry[acl_d->aclp->acl_cnt++];
2119         entry_d->ae_tag = 0;
2120         entry_d->ae_id  = 0;
2121         entry_d->ae_perm        = 0;
2122         *entry_p        = entry_d;
2123
2124         return 0;
2125 }
2126
2127 int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
2128 {
2129         switch (tag_type) {
2130                 case SMB_ACL_USER:
2131                 case SMB_ACL_USER_OBJ:
2132                 case SMB_ACL_GROUP:
2133                 case SMB_ACL_GROUP_OBJ:
2134                 case SMB_ACL_OTHER:
2135                 case SMB_ACL_MASK:
2136                         entry_d->ae_tag = tag_type;
2137                         break;
2138                 default:
2139                         errno = EINVAL;
2140                         return -1;
2141         }
2142
2143         return 0;
2144 }
2145
2146 int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
2147 {
2148         if (entry_d->ae_tag != SMB_ACL_GROUP
2149             && entry_d->ae_tag != SMB_ACL_USER) {
2150                 errno = EINVAL;
2151                 return -1;
2152         }
2153
2154         entry_d->ae_id = *((id_t *)qual_p);
2155
2156         return 0;
2157 }
2158
2159 int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
2160 {
2161         if (permset_d->ae_perm & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
2162                 return EINVAL;
2163         }
2164
2165         entry_d->ae_perm = permset_d->ae_perm;
2166
2167         return 0;
2168 }
2169
2170 int sys_acl_valid(SMB_ACL_T acl_d)
2171 {
2172         return acl_valid(acl_d->aclp);
2173 }
2174
2175 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
2176 {
2177         return acl_set_file(name, type, acl_d->aclp);
2178 }
2179
2180 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
2181 {
2182         return acl_set_fd(fd, acl_d->aclp);
2183 }
2184
2185 int sys_acl_delete_def_file(const char *name)
2186 {
2187         return acl_delete_def_file(name);
2188 }
2189
2190 int sys_acl_free_text(char *text)
2191 {
2192         return acl_free(text);
2193 }
2194
2195 int sys_acl_free_acl(SMB_ACL_T acl_d) 
2196 {
2197         if (acl_d->freeaclp) {
2198                 acl_free(acl_d->aclp);
2199         }
2200         acl_free(acl_d);
2201         return 0;
2202 }
2203
2204 int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
2205 {
2206         return 0;
2207 }
2208
2209 #elif defined(HAVE_AIX_ACLS)
2210
2211 /* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
2212
2213 int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
2214 {
2215         struct acl_entry_link *link;
2216         struct new_acl_entry *entry;
2217         int keep_going;
2218
2219         DEBUG(10,("This is the count: %d\n",theacl->count));
2220
2221         /* Check if count was previously set to -1. *
2222          * If it was, that means we reached the end *
2223          * of the acl last time.                    */
2224         if(theacl->count == -1)
2225                 return(0);
2226
2227         link = theacl;
2228         /* To get to the next acl, traverse linked list until index *
2229          * of acl matches the count we are keeping.  This count is  *
2230          * incremented each time we return an acl entry.            */
2231
2232         for(keep_going = 0; keep_going < theacl->count; keep_going++)
2233                 link = link->nextp;
2234
2235         entry = *entry_p =  link->entryp;
2236
2237         DEBUG(10,("*entry_p is %d\n",entry_p));
2238         DEBUG(10,("*entry_p->ace_access is %d\n",entry->ace_access));
2239
2240         /* Increment count */
2241         theacl->count++;
2242         if(link->nextp == NULL)
2243                 theacl->count = -1;
2244
2245         return(1);
2246 }
2247
2248 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
2249 {
2250         /* Initialize tag type */
2251
2252         *tag_type_p = -1;
2253         DEBUG(10,("the tagtype is %d\n",entry_d->ace_id->id_type));
2254
2255         /* Depending on what type of entry we have, *
2256          * return tag type.                         */
2257         switch(entry_d->ace_id->id_type) {
2258         case ACEID_USER:
2259                 *tag_type_p = SMB_ACL_USER;
2260                 break;
2261         case ACEID_GROUP:
2262                 *tag_type_p = SMB_ACL_GROUP;
2263                 break;
2264
2265         case SMB_ACL_USER_OBJ:
2266         case SMB_ACL_GROUP_OBJ:
2267         case SMB_ACL_OTHER:
2268                 *tag_type_p = entry_d->ace_id->id_type;
2269                 break;
2270  
2271         default:
2272                 return(-1);
2273         }
2274
2275         return(0);
2276 }
2277
2278 int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
2279 {
2280         DEBUG(10,("Starting AIX sys_acl_get_permset\n"));
2281         *permset_p = &entry_d->ace_access;
2282         DEBUG(10,("**permset_p is %d\n",**permset_p));
2283         if(!(**permset_p & S_IXUSR) &&
2284                 !(**permset_p & S_IWUSR) &&
2285                 !(**permset_p & S_IRUSR) &&
2286                 (**permset_p != 0))
2287                         return(-1);
2288
2289         DEBUG(10,("Ending AIX sys_acl_get_permset\n"));
2290         return(0);
2291 }
2292
2293 void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
2294 {
2295         return(entry_d->ace_id->id_data);
2296 }
2297
2298 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
2299 {
2300         struct acl *file_acl = (struct acl *)NULL;
2301         struct acl_entry *acl_entry;
2302         struct new_acl_entry *new_acl_entry;
2303         struct ace_id *idp;
2304         struct acl_entry_link *acl_entry_link;
2305         struct acl_entry_link *acl_entry_link_head;
2306         int i;
2307         int rc = 0;
2308         uid_t user_id;
2309
2310         /* AIX has no DEFAULT */
2311         if  ( type == SMB_ACL_TYPE_DEFAULT ) {
2312                 errno = ENOTSUP;
2313                 return NULL;
2314         }
2315
2316         /* Get the acl using statacl */
2317  
2318         DEBUG(10,("Entering sys_acl_get_file\n"));
2319         DEBUG(10,("path_p is %s\n",path_p));
2320
2321         file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2322  
2323         if(file_acl == NULL) {
2324                 errno=ENOMEM;
2325                 DEBUG(0,("Error in AIX sys_acl_get_file: %d\n",errno));
2326                 return(NULL);
2327         }
2328
2329         memset(file_acl,0,BUFSIZ);
2330
2331         rc = statacl((char *)path_p,0,file_acl,BUFSIZ);
2332         if(rc == -1) {
2333                 DEBUG(0,("statacl returned %d with errno %d\n",rc,errno));
2334                 SAFE_FREE(file_acl);
2335                 return(NULL);
2336         }
2337
2338         DEBUG(10,("Got facl and returned it\n"));
2339
2340         /* Point to the first acl entry in the acl */
2341         acl_entry =  file_acl->acl_ext;
2342
2343         /* Begin setting up the head of the linked list *
2344          * that will be used for the storing the acl    *
2345          * in a way that is useful for the posix_acls.c *
2346          * code.                                          */
2347
2348         acl_entry_link_head = acl_entry_link = sys_acl_init(0);
2349         if(acl_entry_link_head == NULL)
2350                 return(NULL);
2351
2352         acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2353         if(acl_entry_link->entryp == NULL) {
2354                 SAFE_FREE(file_acl);
2355                 errno = ENOMEM;
2356                 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
2357                 return(NULL);
2358         }
2359
2360         DEBUG(10,("acl_entry is %d\n",acl_entry));
2361         DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
2362
2363         /* Check if the extended acl bit is on.   *
2364          * If it isn't, do not show the           *
2365          * contents of the acl since AIX intends *
2366          * the extended info to remain unused     */
2367
2368         if(file_acl->acl_mode & S_IXACL){
2369                 /* while we are not pointing to the very end */
2370                 while(acl_entry < acl_last(file_acl)) {
2371                         /* before we malloc anything, make sure this is  */
2372                         /* a valid acl entry and one that we want to map */
2373                         idp = id_nxt(acl_entry->ace_id);
2374                         if((acl_entry->ace_type == ACC_SPECIFY ||
2375                                 (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
2376                                         acl_entry = acl_nxt(acl_entry);
2377                                         continue;
2378                         }
2379
2380                         idp = acl_entry->ace_id;
2381
2382                         /* Check if this is the first entry in the linked list. *
2383                          * The first entry needs to keep prevp pointing to NULL *
2384                          * and already has entryp allocated.                  */
2385
2386                         if(acl_entry_link_head->count != 0) {
2387                                 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2388
2389                                 if(acl_entry_link->nextp == NULL) {
2390                                         SAFE_FREE(file_acl);
2391                                         errno = ENOMEM;
2392                                         DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
2393                                         return(NULL);
2394                                 }
2395
2396                                 acl_entry_link->nextp->prevp = acl_entry_link;
2397                                 acl_entry_link = acl_entry_link->nextp;
2398                                 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2399                                 if(acl_entry_link->entryp == NULL) {
2400                                         SAFE_FREE(file_acl);
2401                                         errno = ENOMEM;
2402                                         DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
2403                                         return(NULL);
2404                                 }
2405                                 acl_entry_link->nextp = NULL;
2406                         }
2407
2408                         acl_entry_link->entryp->ace_len = acl_entry->ace_len;
2409
2410                         /* Don't really need this since all types are going *
2411                          * to be specified but, it's better than leaving it 0 */
2412
2413                         acl_entry_link->entryp->ace_type = acl_entry->ace_type;
2414  
2415                         acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2416  
2417                         memcpy(acl_entry_link->entryp->ace_id,idp,sizeof(struct ace_id));
2418
2419                         /* The access in the acl entries must be left shifted by *
2420                          * three bites, because they will ultimately be compared *
2421                          * to S_IRUSR, S_IWUSR, and S_IXUSR.                  */
2422
2423                         switch(acl_entry->ace_type){
2424                         case ACC_PERMIT:
2425                         case ACC_SPECIFY:
2426                                 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2427                                 acl_entry_link->entryp->ace_access <<= 6;
2428                                 acl_entry_link_head->count++;
2429                                 break;
2430                         case ACC_DENY:
2431                                 /* Since there is no way to return a DENY acl entry *
2432                                  * change to PERMIT and then shift.                 */
2433                                 DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
2434                                 acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
2435                                 DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
2436                                 acl_entry_link->entryp->ace_access <<= 6;
2437                                 acl_entry_link_head->count++;
2438                                 break;
2439                         default:
2440                                 return(0);
2441                         }
2442
2443                         DEBUG(10,("acl_entry = %d\n",acl_entry));
2444                         DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
2445  
2446                         acl_entry = acl_nxt(acl_entry);
2447                 }
2448         } /* end of if enabled */
2449
2450         /* Since owner, group, other acl entries are not *
2451          * part of the acl entries in an acl, they must  *
2452          * be dummied up to become part of the list.     */
2453
2454         for( i = 1; i < 4; i++) {
2455                 DEBUG(10,("i is %d\n",i));
2456                 if(acl_entry_link_head->count != 0) {
2457                         acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2458                         if(acl_entry_link->nextp == NULL) {
2459                                 SAFE_FREE(file_acl);
2460                                 errno = ENOMEM;
2461                                 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
2462                                 return(NULL);
2463                         }
2464
2465                         acl_entry_link->nextp->prevp = acl_entry_link;
2466                         acl_entry_link = acl_entry_link->nextp;
2467                         acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2468                         if(acl_entry_link->entryp == NULL) {
2469                                 SAFE_FREE(file_acl);
2470                                 errno = ENOMEM;
2471                                 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
2472                                 return(NULL);
2473                         }
2474                 }
2475
2476                 acl_entry_link->nextp = NULL;
2477
2478                 new_acl_entry = acl_entry_link->entryp;
2479                 idp = new_acl_entry->ace_id;
2480
2481                 new_acl_entry->ace_len = sizeof(struct acl_entry);
2482                 new_acl_entry->ace_type = ACC_PERMIT;
2483                 idp->id_len = sizeof(struct ace_id);
2484                 DEBUG(10,("idp->id_len = %d\n",idp->id_len));
2485                 memset(idp->id_data,0,sizeof(uid_t));
2486
2487                 switch(i) {
2488                 case 2:
2489                         new_acl_entry->ace_access = file_acl->g_access << 6;
2490                         idp->id_type = SMB_ACL_GROUP_OBJ;
2491                         break;
2492
2493                 case 3:
2494                         new_acl_entry->ace_access = file_acl->o_access << 6;
2495                         idp->id_type = SMB_ACL_OTHER;
2496                         break;
2497  
2498                 case 1:
2499                         new_acl_entry->ace_access = file_acl->u_access << 6;
2500                         idp->id_type = SMB_ACL_USER_OBJ;
2501                         break;
2502  
2503                 default:
2504                         return(NULL);
2505
2506                 }
2507
2508                 acl_entry_link_head->count++;
2509                 DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
2510         }
2511
2512         acl_entry_link_head->count = 0;
2513         SAFE_FREE(file_acl);
2514
2515         return(acl_entry_link_head);
2516 }
2517
2518 SMB_ACL_T sys_acl_get_fd(int fd)
2519 {
2520         struct acl *file_acl = (struct acl *)NULL;
2521         struct acl_entry *acl_entry;
2522         struct new_acl_entry *new_acl_entry;
2523         struct ace_id *idp;
2524         struct acl_entry_link *acl_entry_link;
2525         struct acl_entry_link *acl_entry_link_head;
2526         int i;
2527         int rc = 0;
2528         uid_t user_id;
2529
2530         /* Get the acl using fstatacl */
2531    
2532         DEBUG(10,("Entering sys_acl_get_fd\n"));
2533         DEBUG(10,("fd is %d\n",fd));
2534         file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2535
2536         if(file_acl == NULL) {
2537                 errno=ENOMEM;
2538                 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2539                 return(NULL);
2540         }
2541
2542         memset(file_acl,0,BUFSIZ);
2543
2544         rc = fstatacl(fd,0,file_acl,BUFSIZ);
2545         if(rc == -1) {
2546                 DEBUG(0,("The fstatacl call returned %d with errno %d\n",rc,errno));
2547                 SAFE_FREE(file_acl);
2548                 return(NULL);
2549         }
2550
2551         DEBUG(10,("Got facl and returned it\n"));
2552
2553         /* Point to the first acl entry in the acl */
2554
2555         acl_entry =  file_acl->acl_ext;
2556         /* Begin setting up the head of the linked list *
2557          * that will be used for the storing the acl    *
2558          * in a way that is useful for the posix_acls.c *
2559          * code.                                        */
2560
2561         acl_entry_link_head = acl_entry_link = sys_acl_init(0);
2562         if(acl_entry_link_head == NULL){
2563                 SAFE_FREE(file_acl);
2564                 return(NULL);
2565         }
2566
2567         acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2568
2569         if(acl_entry_link->entryp == NULL) {
2570                 errno = ENOMEM;
2571                 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2572                 SAFE_FREE(file_acl);
2573                 return(NULL);
2574         }
2575
2576         DEBUG(10,("acl_entry is %d\n",acl_entry));
2577         DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
2578  
2579         /* Check if the extended acl bit is on.   *
2580          * If it isn't, do not show the           *
2581          * contents of the acl since AIX intends  *
2582          * the extended info to remain unused     */
2583  
2584         if(file_acl->acl_mode & S_IXACL){
2585                 /* while we are not pointing to the very end */
2586                 while(acl_entry < acl_last(file_acl)) {
2587                         /* before we malloc anything, make sure this is  */
2588                         /* a valid acl entry and one that we want to map */
2589
2590                         idp = id_nxt(acl_entry->ace_id);
2591                         if((acl_entry->ace_type == ACC_SPECIFY ||
2592                                 (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
2593                                         acl_entry = acl_nxt(acl_entry);
2594                                         continue;
2595                         }
2596
2597                         idp = acl_entry->ace_id;
2598  
2599                         /* Check if this is the first entry in the linked list. *
2600                          * The first entry needs to keep prevp pointing to NULL *
2601                          * and already has entryp allocated.                 */
2602
2603                         if(acl_entry_link_head->count != 0) {
2604                                 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2605                                 if(acl_entry_link->nextp == NULL) {
2606                                         errno = ENOMEM;
2607                                         DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2608                                         SAFE_FREE(file_acl);
2609                                         return(NULL);
2610                                 }
2611                                 acl_entry_link->nextp->prevp = acl_entry_link;
2612                                 acl_entry_link = acl_entry_link->nextp;
2613                                 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2614                                 if(acl_entry_link->entryp == NULL) {
2615                                         errno = ENOMEM;
2616                                         DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2617                                         SAFE_FREE(file_acl);
2618                                         return(NULL);
2619                                 }
2620
2621                                 acl_entry_link->nextp = NULL;
2622                         }
2623
2624                         acl_entry_link->entryp->ace_len = acl_entry->ace_len;
2625
2626                         /* Don't really need this since all types are going *
2627                          * to be specified but, it's better than leaving it 0 */
2628
2629                         acl_entry_link->entryp->ace_type = acl_entry->ace_type;
2630                         acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2631
2632                         memcpy(acl_entry_link->entryp->ace_id, idp, sizeof(struct ace_id));
2633
2634                         /* The access in the acl entries must be left shifted by *
2635                          * three bites, because they will ultimately be compared *
2636                          * to S_IRUSR, S_IWUSR, and S_IXUSR.                  */
2637
2638                         switch(acl_entry->ace_type){
2639                         case ACC_PERMIT:
2640                         case ACC_SPECIFY:
2641                                 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2642                                 acl_entry_link->entryp->ace_access <<= 6;
2643                                 acl_entry_link_head->count++;
2644                                 break;
2645                         case ACC_DENY:
2646                                 /* Since there is no way to return a DENY acl entry *
2647                                  * change to PERMIT and then shift.                 */
2648                                 DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
2649                                 acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
2650                                 DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
2651                                 acl_entry_link->entryp->ace_access <<= 6;
2652                                 acl_entry_link_head->count++;
2653                                 break;
2654                         default:
2655                                 return(0);
2656                         }
2657
2658                         DEBUG(10,("acl_entry = %d\n",acl_entry));
2659                         DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
2660  
2661                         acl_entry = acl_nxt(acl_entry);
2662                 }
2663         } /* end of if enabled */
2664
2665         /* Since owner, group, other acl entries are not *
2666          * part of the acl entries in an acl, they must  *
2667          * be dummied up to become part of the list.     */
2668
2669         for( i = 1; i < 4; i++) {
2670                 DEBUG(10,("i is %d\n",i));
2671                 if(acl_entry_link_head->count != 0){
2672                         acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2673                         if(acl_entry_link->nextp == NULL) {
2674                                 errno = ENOMEM;
2675                                 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2676                                 SAFE_FREE(file_acl);
2677                                 return(NULL);
2678                         }
2679
2680                         acl_entry_link->nextp->prevp = acl_entry_link;
2681                         acl_entry_link = acl_entry_link->nextp;
2682                         acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2683
2684                         if(acl_entry_link->entryp == NULL) {
2685                                 SAFE_FREE(file_acl);
2686                                 errno = ENOMEM;
2687                                 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2688                                 return(NULL);
2689                         }
2690                 }
2691
2692                 acl_entry_link->nextp = NULL;
2693  
2694                 new_acl_entry = acl_entry_link->entryp;
2695                 idp = new_acl_entry->ace_id;
2696  
2697                 new_acl_entry->ace_len = sizeof(struct acl_entry);
2698                 new_acl_entry->ace_type = ACC_PERMIT;
2699                 idp->id_len = sizeof(struct ace_id);
2700                 DEBUG(10,("idp->id_len = %d\n",idp->id_len));
2701                 memset(idp->id_data,0,sizeof(uid_t));
2702  
2703                 switch(i) {
2704                 case 2:
2705                         new_acl_entry->ace_access = file_acl->g_access << 6;
2706                         idp->id_type = SMB_ACL_GROUP_OBJ;
2707                         break;
2708  
2709                 case 3:
2710                         new_acl_entry->ace_access = file_acl->o_access << 6;
2711                         idp->id_type = SMB_ACL_OTHER;
2712                         break;
2713  
2714                 case 1:
2715                         new_acl_entry->ace_access = file_acl->u_access << 6;
2716                         idp->id_type = SMB_ACL_USER_OBJ;
2717                         break;
2718  
2719                 default:
2720                         return(NULL);
2721                 }
2722  
2723                 acl_entry_link_head->count++;
2724                 DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
2725         }
2726
2727         acl_entry_link_head->count = 0;
2728         SAFE_FREE(file_acl);
2729  
2730         return(acl_entry_link_head);
2731 }
2732
2733 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
2734 {
2735         *permset = *permset & ~0777;
2736         return(0);
2737 }
2738
2739 int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
2740 {
2741         if((perm != 0) &&
2742                         (perm & (S_IXUSR | S_IWUSR | S_IRUSR)) == 0)
2743                 return(-1);
2744
2745         *permset |= perm;
2746         DEBUG(10,("This is the permset now: %d\n",*permset));
2747         return(0);
2748 }
2749
2750 char *sys_acl_to_text( SMB_ACL_T theacl, ssize_t *plen)
2751 {
2752         return(NULL);
2753 }
2754
2755 SMB_ACL_T sys_acl_init( int count)
2756 {
2757         struct acl_entry_link *theacl = NULL;
2758  
2759         DEBUG(10,("Entering sys_acl_init\n"));
2760
2761         theacl = SMB_MALLOC_P(struct acl_entry_link);
2762         if(theacl == NULL) {
2763                 errno = ENOMEM;
2764                 DEBUG(0,("Error in sys_acl_init is %d\n",errno));
2765                 return(NULL);
2766         }
2767
2768         theacl->count = 0;
2769         theacl->nextp = NULL;
2770         theacl->prevp = NULL;
2771         theacl->entryp = NULL;
2772         DEBUG(10,("Exiting sys_acl_init\n"));
2773         return(theacl);
2774 }
2775
2776 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
2777 {
2778         struct acl_entry_link *theacl;
2779         struct acl_entry_link *acl_entryp;
2780         struct acl_entry_link *temp_entry;
2781         int counting;
2782
2783         DEBUG(10,("Entering the sys_acl_create_entry\n"));
2784
2785         theacl = acl_entryp = *pacl;
2786
2787         /* Get to the end of the acl before adding entry */
2788
2789         for(counting=0; counting < theacl->count; counting++){
2790                 DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
2791                 temp_entry = acl_entryp;
2792                 acl_entryp = acl_entryp->nextp;
2793         }
2794
2795         if(theacl->count != 0){
2796                 temp_entry->nextp = acl_entryp = SMB_MALLOC_P(struct acl_entry_link);
2797                 if(acl_entryp == NULL) {
2798                         errno = ENOMEM;
2799                         DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
2800                         return(-1);
2801                 }
2802
2803                 DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
2804                 acl_entryp->prevp = temp_entry;
2805                 DEBUG(10,("The acl_entryp->prevp is %d\n",acl_entryp->prevp));
2806         }
2807
2808         *pentry = acl_entryp->entryp = SMB_MALLOC_P(struct new_acl_entry);
2809         if(*pentry == NULL) {
2810                 errno = ENOMEM;
2811                 DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
2812                 return(-1);
2813         }
2814
2815         memset(*pentry,0,sizeof(struct new_acl_entry));
2816         acl_entryp->entryp->ace_len = sizeof(struct acl_entry);
2817         acl_entryp->entryp->ace_type = ACC_PERMIT;
2818         acl_entryp->entryp->ace_id->id_len = sizeof(struct ace_id);
2819         acl_entryp->nextp = NULL;
2820         theacl->count++;
2821         DEBUG(10,("Exiting sys_acl_create_entry\n"));
2822         return(0);
2823 }
2824
2825 int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
2826 {
2827         DEBUG(10,("Starting AIX sys_acl_set_tag_type\n"));
2828         entry->ace_id->id_type = tagtype;
2829         DEBUG(10,("The tag type is %d\n",entry->ace_id->id_type));
2830         DEBUG(10,("Ending AIX sys_acl_set_tag_type\n"));
2831 }
2832
2833 int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
2834 {
2835         DEBUG(10,("Starting AIX sys_acl_set_qualifier\n"));
2836         memcpy(entry->ace_id->id_data,qual,sizeof(uid_t));
2837         DEBUG(10,("Ending AIX sys_acl_set_qualifier\n"));
2838         return(0);
2839 }
2840
2841 int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
2842 {
2843         DEBUG(10,("Starting AIX sys_acl_set_permset\n"));
2844         if(!(*permset & S_IXUSR) &&
2845                 !(*permset & S_IWUSR) &&
2846                 !(*permset & S_IRUSR) &&
2847                 (*permset != 0))
2848                         return(-1);
2849
2850         entry->ace_access = *permset;
2851         DEBUG(10,("entry->ace_access = %d\n",entry->ace_access));
2852         DEBUG(10,("Ending AIX sys_acl_set_permset\n"));
2853         return(0);
2854 }
2855
2856 int sys_acl_valid( SMB_ACL_T theacl )
2857 {
2858         int user_obj = 0;
2859         int group_obj = 0;
2860         int other_obj = 0;
2861         struct acl_entry_link *acl_entry;
2862
2863         for(acl_entry=theacl; acl_entry != NULL; acl_entry = acl_entry->nextp) {
2864                 user_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_USER_OBJ);
2865                 group_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_GROUP_OBJ);
2866                 other_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_OTHER);
2867         }
2868
2869         DEBUG(10,("user_obj=%d, group_obj=%d, other_obj=%d\n",user_obj,group_obj,other_obj));
2870  
2871         if(user_obj != 1 || group_obj != 1 || other_obj != 1)
2872                 return(-1); 
2873
2874         return(0);
2875 }
2876
2877 int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2878 {
2879         struct acl_entry_link *acl_entry_link = NULL;
2880         struct acl *file_acl = NULL;
2881         struct acl *file_acl_temp = NULL;
2882         struct acl_entry *acl_entry = NULL;
2883         struct ace_id *ace_id = NULL;
2884         uint id_type;
2885         uint ace_access;
2886         uint user_id;
2887         uint acl_length;
2888         uint rc;
2889
2890         DEBUG(10,("Entering sys_acl_set_file\n"));
2891         DEBUG(10,("File name is %s\n",name));
2892  
2893         /* AIX has no default ACL */
2894         if(acltype == SMB_ACL_TYPE_DEFAULT)
2895                 return(0);
2896
2897         acl_length = BUFSIZ;
2898         file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2899
2900         if(file_acl == NULL) {
2901                 errno = ENOMEM;
2902                 DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
2903                 return(-1);
2904         }
2905
2906         memset(file_acl,0,BUFSIZ);
2907
2908         file_acl->acl_len = ACL_SIZ;
2909         file_acl->acl_mode = S_IXACL;
2910
2911         for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
2912                 acl_entry_link->entryp->ace_access >>= 6;
2913                 id_type = acl_entry_link->entryp->ace_id->id_type;
2914
2915                 switch(id_type) {
2916                 case SMB_ACL_USER_OBJ:
2917                         file_acl->u_access = acl_entry_link->entryp->ace_access;
2918                         continue;
2919                 case SMB_ACL_GROUP_OBJ:
2920                         file_acl->g_access = acl_entry_link->entryp->ace_access;
2921                         continue;
2922                 case SMB_ACL_OTHER:
2923                         file_acl->o_access = acl_entry_link->entryp->ace_access;
2924                         continue;
2925                 case SMB_ACL_MASK:
2926                         continue;
2927                 }
2928
2929                 if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
2930                         acl_length += sizeof(struct acl_entry);
2931                         file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
2932                         if(file_acl_temp == NULL) {
2933                                 SAFE_FREE(file_acl);
2934                                 errno = ENOMEM;
2935                                 DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
2936                                 return(-1);
2937                         }  
2938
2939                         memcpy(file_acl_temp,file_acl,file_acl->acl_len);
2940                         SAFE_FREE(file_acl);
2941                         file_acl = file_acl_temp;
2942                 }
2943
2944                 acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
2945                 file_acl->acl_len += sizeof(struct acl_entry);
2946                 acl_entry->ace_len = acl_entry_link->entryp->ace_len;
2947                 acl_entry->ace_access = acl_entry_link->entryp->ace_access;
2948  
2949                 /* In order to use this, we'll need to wait until we can get denies */
2950                 /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
2951                 acl_entry->ace_type = ACC_SPECIFY; */
2952
2953                 acl_entry->ace_type = ACC_SPECIFY;
2954  
2955                 ace_id = acl_entry->ace_id;
2956  
2957                 ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
2958                 DEBUG(10,("The id type is %d\n",ace_id->id_type));
2959                 ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
2960                 memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
2961                 memcpy(acl_entry->ace_id->id_data, &user_id, sizeof(uid_t));
2962         }
2963
2964         rc = chacl(name,file_acl,file_acl->acl_len);
2965         DEBUG(10,("errno is %d\n",errno));
2966         DEBUG(10,("return code is %d\n",rc));
2967         SAFE_FREE(file_acl);
2968         DEBUG(10,("Exiting the sys_acl_set_file\n"));
2969         return(rc);
2970 }
2971
2972 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
2973 {
2974         struct acl_entry_link *acl_entry_link = NULL;
2975         struct acl *file_acl = NULL;
2976         struct acl *file_acl_temp = NULL;
2977         struct acl_entry *acl_entry = NULL;
2978         struct ace_id *ace_id = NULL;
2979         uint id_type;
2980         uint user_id;
2981         uint acl_length;
2982         uint rc;
2983  
2984         DEBUG(10,("Entering sys_acl_set_fd\n"));
2985         acl_length = BUFSIZ;
2986         file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2987
2988         if(file_acl == NULL) {
2989                 errno = ENOMEM;
2990                 DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
2991                 return(-1);
2992         }
2993
2994         memset(file_acl,0,BUFSIZ);
2995  
2996         file_acl->acl_len = ACL_SIZ;
2997         file_acl->acl_mode = S_IXACL;
2998
2999         for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
3000                 acl_entry_link->entryp->ace_access >>= 6;
3001                 id_type = acl_entry_link->entryp->ace_id->id_type;
3002                 DEBUG(10,("The id_type is %d\n",id_type));
3003
3004                 switch(id_type) {
3005                 case SMB_ACL_USER_OBJ:
3006                         file_acl->u_access = acl_entry_link->entryp->ace_access;
3007                         continue;
3008                 case SMB_ACL_GROUP_OBJ:
3009                         file_acl->g_access = acl_entry_link->entryp->ace_access;
3010                         continue;
3011                 case SMB_ACL_OTHER:
3012                         file_acl->o_access = acl_entry_link->entryp->ace_access;
3013                         continue;
3014                 case SMB_ACL_MASK:
3015                         continue;
3016                 }
3017
3018                 if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
3019                         acl_length += sizeof(struct acl_entry);
3020                         file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
3021                         if(file_acl_temp == NULL) {
3022                                 SAFE_FREE(file_acl);
3023                                 errno = ENOMEM;
3024                                 DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
3025                                 return(-1);
3026                         }
3027
3028                         memcpy(file_acl_temp,file_acl,file_acl->acl_len);
3029                         SAFE_FREE(file_acl);
3030                         file_acl = file_acl_temp;
3031                 }
3032
3033                 acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
3034                 file_acl->acl_len += sizeof(struct acl_entry);
3035                 acl_entry->ace_len = acl_entry_link->entryp->ace_len;
3036                 acl_entry->ace_access = acl_entry_link->entryp->ace_access;
3037  
3038                 /* In order to use this, we'll need to wait until we can get denies */
3039                 /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
3040                         acl_entry->ace_type = ACC_SPECIFY; */
3041  
3042                 acl_entry->ace_type = ACC_SPECIFY;
3043  
3044                 ace_id = acl_entry->ace_id;
3045  
3046                 ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
3047                 DEBUG(10,("The id type is %d\n",ace_id->id_type));
3048                 ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
3049                 memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
3050                 memcpy(ace_id->id_data, &user_id, sizeof(uid_t));
3051         }
3052  
3053         rc = fchacl(fd,file_acl,file_acl->acl_len);
3054         DEBUG(10,("errno is %d\n",errno));
3055         DEBUG(10,("return code is %d\n",rc));
3056         SAFE_FREE(file_acl);
3057         DEBUG(10,("Exiting sys_acl_set_fd\n"));
3058         return(rc);
3059 }
3060
3061 int sys_acl_delete_def_file(const char *name)
3062 {
3063         /* AIX has no default ACL */
3064         return 0;
3065 }
3066
3067 int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
3068 {
3069         return(*permset & perm);
3070 }
3071
3072 int sys_acl_free_text(char *text)
3073 {
3074         return(0);
3075 }
3076
3077 int sys_acl_free_acl(SMB_ACL_T posix_acl)
3078 {
3079         struct acl_entry_link *acl_entry_link;
3080
3081         for(acl_entry_link = posix_acl->nextp; acl_entry_link->nextp != NULL; acl_entry_link = acl_entry_link->nextp) {
3082                 SAFE_FREE(acl_entry_link->prevp->entryp);
3083                 SAFE_FREE(acl_entry_link->prevp);
3084         }
3085
3086         SAFE_FREE(acl_entry_link->prevp->entryp);
3087         SAFE_FREE(acl_entry_link->prevp);
3088         SAFE_FREE(acl_entry_link->entryp);
3089         SAFE_FREE(acl_entry_link);
3090  
3091         return(0);
3092 }
3093
3094 int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
3095 {
3096         return(0);
3097 }
3098
3099 #else /* No ACLs. */
3100
3101 int sys_acl_get_entry(UNUSED(SMB_ACL_T the_acl), UNUSED(int entry_id), UNUSED(SMB_ACL_ENTRY_T *entry_p))
3102 {
3103         errno = ENOSYS;
3104         return -1;
3105 }
3106
3107 int sys_acl_get_tag_type(UNUSED(SMB_ACL_ENTRY_T entry_d), UNUSED(SMB_ACL_TAG_T *tag_type_p))
3108 {
3109         errno = ENOSYS;
3110         return -1;
3111 }
3112
3113 int sys_acl_get_permset(UNUSED(SMB_ACL_ENTRY_T entry_d), UNUSED(SMB_ACL_PERMSET_T *permset_p))
3114 {
3115         errno = ENOSYS;
3116         return -1;
3117 }
3118
3119 void *sys_acl_get_qualifier(UNUSED(SMB_ACL_ENTRY_T entry_d))
3120 {
3121         errno = ENOSYS;
3122         return NULL;
3123 }
3124
3125 SMB_ACL_T sys_acl_get_file(UNUSED(const char *path_p), UNUSED(SMB_ACL_TYPE_T type))
3126 {
3127         errno = ENOSYS;
3128         return (SMB_ACL_T)NULL;
3129 }
3130
3131 SMB_ACL_T sys_acl_get_fd(UNUSED(int fd))
3132 {
3133         errno = ENOSYS;
3134         return (SMB_ACL_T)NULL;
3135 }
3136
3137 int sys_acl_clear_perms(UNUSED(SMB_ACL_PERMSET_T permset))
3138 {
3139         errno = ENOSYS;
3140         return -1;
3141 }
3142
3143 int sys_acl_add_perm( UNUSED(SMB_ACL_PERMSET_T permset), UNUSED(SMB_ACL_PERM_T perm))
3144 {
3145         errno = ENOSYS;
3146         return -1;
3147 }
3148
3149 int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
3150 {
3151         errno = ENOSYS;
3152         return (permset & perm) ? 1 : 0;
3153 }
3154
3155 char *sys_acl_to_text(UNUSED(SMB_ACL_T the_acl), UNUSED(ssize_t *plen))
3156 {
3157         errno = ENOSYS;
3158         return NULL;
3159 }
3160
3161 int sys_acl_free_text(UNUSED(char *text))
3162 {
3163         errno = ENOSYS;
3164         return -1;
3165 }
3166
3167 SMB_ACL_T sys_acl_init(UNUSED(int count))
3168 {
3169         errno = ENOSYS;
3170         return NULL;
3171 }
3172
3173 int sys_acl_create_entry(UNUSED(SMB_ACL_T *pacl), UNUSED(SMB_ACL_ENTRY_T *pentry))
3174 {
3175         errno = ENOSYS;
3176         return -1;
3177 }
3178
3179 int sys_acl_set_tag_type(UNUSED(SMB_ACL_ENTRY_T entry), UNUSED(SMB_ACL_TAG_T tagtype))
3180 {
3181         errno = ENOSYS;
3182         return -1;
3183 }
3184
3185 int sys_acl_set_qualifier(UNUSED(SMB_ACL_ENTRY_T entry), UNUSED(void *qual))
3186 {
3187         errno = ENOSYS;
3188         return -1;
3189 }
3190
3191 int sys_acl_set_permset(UNUSED(SMB_ACL_ENTRY_T entry), UNUSED(SMB_ACL_PERMSET_T permset))
3192 {
3193         errno = ENOSYS;
3194         return -1;
3195 }
3196
3197 int sys_acl_valid(UNUSED(SMB_ACL_T theacl))
3198 {
3199         errno = ENOSYS;
3200         return -1;
3201 }
3202
3203 int sys_acl_set_file(UNUSED(const char *name), UNUSED(SMB_ACL_TYPE_T acltype), UNUSED(SMB_ACL_T theacl))
3204 {
3205         errno = ENOSYS;
3206         return -1;
3207 }
3208
3209 int sys_acl_set_fd(UNUSED(int fd), UNUSED(SMB_ACL_T theacl))
3210 {
3211         errno = ENOSYS;
3212         return -1;
3213 }
3214
3215 int sys_acl_delete_def_file(UNUSED(const char *name))
3216 {
3217         errno = ENOSYS;
3218         return -1;
3219 }
3220
3221 int sys_acl_free_acl(UNUSED(SMB_ACL_T the_acl))
3222 {
3223         errno = ENOSYS;
3224         return -1;
3225 }
3226
3227 int sys_acl_free_qualifier(UNUSED(void *qual), UNUSED(SMB_ACL_TAG_T tagtype))
3228 {
3229         errno = ENOSYS;
3230         return -1;
3231 }
3232
3233 #endif /* No ACLs. */
3234
3235 /************************************************************************
3236  Deliberately outside the ACL defines. Return 1 if this is a "no acls"
3237  errno, 0 if not.
3238 ************************************************************************/
3239
3240 int no_acl_syscall_error(int err)
3241 {
3242 #if defined(ENOSYS)
3243         if (err == ENOSYS) {
3244                 return 1;
3245         }
3246 #endif
3247 #if defined(ENOTSUP)
3248         if (err == ENOTSUP) {
3249                 return 1;
3250         }
3251 #endif
3252         return 0;
3253 }
3254
3255 #endif /* SUPPORT_ACLS */