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