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