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