Allow a failure of EINVAL to mean no ACLs are available.
[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 a[0] + 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_ACL_T)SMB_MALLOC(sizeof a[0] + 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_ACL_T)SMB_MALLOC(sizeof a[0] + 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 *)((char *)a + sizeof a[0]);
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 #ifdef ENOTSUP
1819                 errno = ENOTSUP;
1820 #else
1821                 errno = ENOSYS;
1822 #endif
1823                 return NULL;
1824         }
1825
1826         /* Get the acl using statacl */
1827  
1828         DEBUG(10,("Entering sys_acl_get_file\n"));
1829         DEBUG(10,("path_p is %s\n",path_p));
1830
1831         file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
1832  
1833         if(file_acl == NULL) {
1834                 errno=ENOMEM;
1835                 DEBUG(0,("Error in AIX sys_acl_get_file: %d\n",errno));
1836                 return(NULL);
1837         }
1838
1839         memset(file_acl,0,BUFSIZ);
1840
1841         rc = statacl((char *)path_p,0,file_acl,BUFSIZ);
1842         if(rc == -1) {
1843                 DEBUG(0,("statacl returned %d with errno %d\n",rc,errno));
1844                 SAFE_FREE(file_acl);
1845                 return(NULL);
1846         }
1847
1848         DEBUG(10,("Got facl and returned it\n"));
1849
1850         /* Point to the first acl entry in the acl */
1851         acl_entry =  file_acl->acl_ext;
1852
1853         /* Begin setting up the head of the linked list *
1854          * that will be used for the storing the acl    *
1855          * in a way that is useful for the posix_acls.c *
1856          * code.                                          */
1857
1858         acl_entry_link_head = acl_entry_link = sys_acl_init(0);
1859         if(acl_entry_link_head == NULL)
1860                 return(NULL);
1861
1862         acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
1863         if(acl_entry_link->entryp == NULL) {
1864                 SAFE_FREE(file_acl);
1865                 errno = ENOMEM;
1866                 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1867                 return(NULL);
1868         }
1869
1870         DEBUG(10,("acl_entry is %d\n",acl_entry));
1871         DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
1872
1873         /* Check if the extended acl bit is on.   *
1874          * If it isn't, do not show the           *
1875          * contents of the acl since AIX intends *
1876          * the extended info to remain unused     */
1877
1878         if(file_acl->acl_mode & S_IXACL){
1879                 /* while we are not pointing to the very end */
1880                 while(acl_entry < acl_last(file_acl)) {
1881                         /* before we malloc anything, make sure this is  */
1882                         /* a valid acl entry and one that we want to map */
1883                         idp = id_nxt(acl_entry->ace_id);
1884                         if((acl_entry->ace_type == ACC_SPECIFY ||
1885                                 (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
1886                                         acl_entry = acl_nxt(acl_entry);
1887                                         continue;
1888                         }
1889
1890                         idp = acl_entry->ace_id;
1891
1892                         /* Check if this is the first entry in the linked list. *
1893                          * The first entry needs to keep prevp pointing to NULL *
1894                          * and already has entryp allocated.                  */
1895
1896                         if(acl_entry_link_head->count != 0) {
1897                                 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
1898
1899                                 if(acl_entry_link->nextp == NULL) {
1900                                         SAFE_FREE(file_acl);
1901                                         errno = ENOMEM;
1902                                         DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1903                                         return(NULL);
1904                                 }
1905
1906                                 acl_entry_link->nextp->prevp = acl_entry_link;
1907                                 acl_entry_link = acl_entry_link->nextp;
1908                                 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
1909                                 if(acl_entry_link->entryp == NULL) {
1910                                         SAFE_FREE(file_acl);
1911                                         errno = ENOMEM;
1912                                         DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1913                                         return(NULL);
1914                                 }
1915                                 acl_entry_link->nextp = NULL;
1916                         }
1917
1918                         acl_entry_link->entryp->ace_len = acl_entry->ace_len;
1919
1920                         /* Don't really need this since all types are going *
1921                          * to be specified but, it's better than leaving it 0 */
1922
1923                         acl_entry_link->entryp->ace_type = acl_entry->ace_type;
1924  
1925                         acl_entry_link->entryp->ace_access = acl_entry->ace_access;
1926  
1927                         memcpy(acl_entry_link->entryp->ace_id,idp,sizeof(struct ace_id));
1928
1929                         /* The access in the acl entries must be left shifted by *
1930                          * three bites, because they will ultimately be compared *
1931                          * to S_IRUSR, S_IWUSR, and S_IXUSR.                  */
1932
1933                         switch(acl_entry->ace_type){
1934                         case ACC_PERMIT:
1935                         case ACC_SPECIFY:
1936                                 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
1937                                 acl_entry_link->entryp->ace_access <<= 6;
1938                                 acl_entry_link_head->count++;
1939                                 break;
1940                         case ACC_DENY:
1941                                 /* Since there is no way to return a DENY acl entry *
1942                                  * change to PERMIT and then shift.                 */
1943                                 DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
1944                                 acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
1945                                 DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
1946                                 acl_entry_link->entryp->ace_access <<= 6;
1947                                 acl_entry_link_head->count++;
1948                                 break;
1949                         default:
1950                                 return(0);
1951                         }
1952
1953                         DEBUG(10,("acl_entry = %d\n",acl_entry));
1954                         DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
1955  
1956                         acl_entry = acl_nxt(acl_entry);
1957                 }
1958         } /* end of if enabled */
1959
1960         /* Since owner, group, other acl entries are not *
1961          * part of the acl entries in an acl, they must  *
1962          * be dummied up to become part of the list.     */
1963
1964         for( i = 1; i < 4; i++) {
1965                 DEBUG(10,("i is %d\n",i));
1966                 if(acl_entry_link_head->count != 0) {
1967                         acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
1968                         if(acl_entry_link->nextp == NULL) {
1969                                 SAFE_FREE(file_acl);
1970                                 errno = ENOMEM;
1971                                 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1972                                 return(NULL);
1973                         }
1974
1975                         acl_entry_link->nextp->prevp = acl_entry_link;
1976                         acl_entry_link = acl_entry_link->nextp;
1977                         acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
1978                         if(acl_entry_link->entryp == NULL) {
1979                                 SAFE_FREE(file_acl);
1980                                 errno = ENOMEM;
1981                                 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1982                                 return(NULL);
1983                         }
1984                 }
1985
1986                 acl_entry_link->nextp = NULL;
1987
1988                 new_acl_entry = acl_entry_link->entryp;
1989                 idp = new_acl_entry->ace_id;
1990
1991                 new_acl_entry->ace_len = sizeof(struct acl_entry);
1992                 new_acl_entry->ace_type = ACC_PERMIT;
1993                 idp->id_len = sizeof(struct ace_id);
1994                 DEBUG(10,("idp->id_len = %d\n",idp->id_len));
1995                 memset(idp->id_data,0,sizeof(uid_t));
1996
1997                 switch(i) {
1998                 case 2:
1999                         new_acl_entry->ace_access = file_acl->g_access << 6;
2000                         idp->id_type = SMB_ACL_GROUP_OBJ;
2001                         break;
2002
2003                 case 3:
2004                         new_acl_entry->ace_access = file_acl->o_access << 6;
2005                         idp->id_type = SMB_ACL_OTHER;
2006                         break;
2007  
2008                 case 1:
2009                         new_acl_entry->ace_access = file_acl->u_access << 6;
2010                         idp->id_type = SMB_ACL_USER_OBJ;
2011                         break;
2012  
2013                 default:
2014                         return(NULL);
2015
2016                 }
2017
2018                 acl_entry_link_head->count++;
2019                 DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
2020         }
2021
2022         acl_entry_link_head->count = 0;
2023         SAFE_FREE(file_acl);
2024
2025         return(acl_entry_link_head);
2026 }
2027
2028 #if 0
2029 SMB_ACL_T sys_acl_get_fd(int fd)
2030 {
2031         struct acl *file_acl = (struct acl *)NULL;
2032         struct acl_entry *acl_entry;
2033         struct new_acl_entry *new_acl_entry;
2034         struct ace_id *idp;
2035         struct acl_entry_link *acl_entry_link;
2036         struct acl_entry_link *acl_entry_link_head;
2037         int i;
2038         int rc = 0;
2039
2040         /* Get the acl using fstatacl */
2041    
2042         DEBUG(10,("Entering sys_acl_get_fd\n"));
2043         DEBUG(10,("fd is %d\n",fd));
2044         file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2045
2046         if(file_acl == NULL) {
2047                 errno=ENOMEM;
2048                 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2049                 return(NULL);
2050         }
2051
2052         memset(file_acl,0,BUFSIZ);
2053
2054         rc = fstatacl(fd,0,file_acl,BUFSIZ);
2055         if(rc == -1) {
2056                 DEBUG(0,("The fstatacl call returned %d with errno %d\n",rc,errno));
2057                 SAFE_FREE(file_acl);
2058                 return(NULL);
2059         }
2060
2061         DEBUG(10,("Got facl and returned it\n"));
2062
2063         /* Point to the first acl entry in the acl */
2064
2065         acl_entry =  file_acl->acl_ext;
2066         /* Begin setting up the head of the linked list *
2067          * that will be used for the storing the acl    *
2068          * in a way that is useful for the posix_acls.c *
2069          * code.                                        */
2070
2071         acl_entry_link_head = acl_entry_link = sys_acl_init(0);
2072         if(acl_entry_link_head == NULL){
2073                 SAFE_FREE(file_acl);
2074                 return(NULL);
2075         }
2076
2077         acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2078
2079         if(acl_entry_link->entryp == NULL) {
2080                 errno = ENOMEM;
2081                 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2082                 SAFE_FREE(file_acl);
2083                 return(NULL);
2084         }
2085
2086         DEBUG(10,("acl_entry is %d\n",acl_entry));
2087         DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
2088  
2089         /* Check if the extended acl bit is on.   *
2090          * If it isn't, do not show the           *
2091          * contents of the acl since AIX intends  *
2092          * the extended info to remain unused     */
2093  
2094         if(file_acl->acl_mode & S_IXACL){
2095                 /* while we are not pointing to the very end */
2096                 while(acl_entry < acl_last(file_acl)) {
2097                         /* before we malloc anything, make sure this is  */
2098                         /* a valid acl entry and one that we want to map */
2099
2100                         idp = id_nxt(acl_entry->ace_id);
2101                         if((acl_entry->ace_type == ACC_SPECIFY ||
2102                                 (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
2103                                         acl_entry = acl_nxt(acl_entry);
2104                                         continue;
2105                         }
2106
2107                         idp = acl_entry->ace_id;
2108  
2109                         /* Check if this is the first entry in the linked list. *
2110                          * The first entry needs to keep prevp pointing to NULL *
2111                          * and already has entryp allocated.                 */
2112
2113                         if(acl_entry_link_head->count != 0) {
2114                                 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2115                                 if(acl_entry_link->nextp == NULL) {
2116                                         errno = ENOMEM;
2117                                         DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2118                                         SAFE_FREE(file_acl);
2119                                         return(NULL);
2120                                 }
2121                                 acl_entry_link->nextp->prevp = acl_entry_link;
2122                                 acl_entry_link = acl_entry_link->nextp;
2123                                 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2124                                 if(acl_entry_link->entryp == NULL) {
2125                                         errno = ENOMEM;
2126                                         DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2127                                         SAFE_FREE(file_acl);
2128                                         return(NULL);
2129                                 }
2130
2131                                 acl_entry_link->nextp = NULL;
2132                         }
2133
2134                         acl_entry_link->entryp->ace_len = acl_entry->ace_len;
2135
2136                         /* Don't really need this since all types are going *
2137                          * to be specified but, it's better than leaving it 0 */
2138
2139                         acl_entry_link->entryp->ace_type = acl_entry->ace_type;
2140                         acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2141
2142                         memcpy(acl_entry_link->entryp->ace_id, idp, sizeof(struct ace_id));
2143
2144                         /* The access in the acl entries must be left shifted by *
2145                          * three bites, because they will ultimately be compared *
2146                          * to S_IRUSR, S_IWUSR, and S_IXUSR.                  */
2147
2148                         switch(acl_entry->ace_type){
2149                         case ACC_PERMIT:
2150                         case ACC_SPECIFY:
2151                                 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2152                                 acl_entry_link->entryp->ace_access <<= 6;
2153                                 acl_entry_link_head->count++;
2154                                 break;
2155                         case ACC_DENY:
2156                                 /* Since there is no way to return a DENY acl entry *
2157                                  * change to PERMIT and then shift.                 */
2158                                 DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
2159                                 acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
2160                                 DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
2161                                 acl_entry_link->entryp->ace_access <<= 6;
2162                                 acl_entry_link_head->count++;
2163                                 break;
2164                         default:
2165                                 return(0);
2166                         }
2167
2168                         DEBUG(10,("acl_entry = %d\n",acl_entry));
2169                         DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
2170  
2171                         acl_entry = acl_nxt(acl_entry);
2172                 }
2173         } /* end of if enabled */
2174
2175         /* Since owner, group, other acl entries are not *
2176          * part of the acl entries in an acl, they must  *
2177          * be dummied up to become part of the list.     */
2178
2179         for( i = 1; i < 4; i++) {
2180                 DEBUG(10,("i is %d\n",i));
2181                 if(acl_entry_link_head->count != 0){
2182                         acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2183                         if(acl_entry_link->nextp == NULL) {
2184                                 errno = ENOMEM;
2185                                 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2186                                 SAFE_FREE(file_acl);
2187                                 return(NULL);
2188                         }
2189
2190                         acl_entry_link->nextp->prevp = acl_entry_link;
2191                         acl_entry_link = acl_entry_link->nextp;
2192                         acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2193
2194                         if(acl_entry_link->entryp == NULL) {
2195                                 SAFE_FREE(file_acl);
2196                                 errno = ENOMEM;
2197                                 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2198                                 return(NULL);
2199                         }
2200                 }
2201
2202                 acl_entry_link->nextp = NULL;
2203  
2204                 new_acl_entry = acl_entry_link->entryp;
2205                 idp = new_acl_entry->ace_id;
2206  
2207                 new_acl_entry->ace_len = sizeof(struct acl_entry);
2208                 new_acl_entry->ace_type = ACC_PERMIT;
2209                 idp->id_len = sizeof(struct ace_id);
2210                 DEBUG(10,("idp->id_len = %d\n",idp->id_len));
2211                 memset(idp->id_data,0,sizeof(uid_t));
2212  
2213                 switch(i) {
2214                 case 2:
2215                         new_acl_entry->ace_access = file_acl->g_access << 6;
2216                         idp->id_type = SMB_ACL_GROUP_OBJ;
2217                         break;
2218  
2219                 case 3:
2220                         new_acl_entry->ace_access = file_acl->o_access << 6;
2221                         idp->id_type = SMB_ACL_OTHER;
2222                         break;
2223  
2224                 case 1:
2225                         new_acl_entry->ace_access = file_acl->u_access << 6;
2226                         idp->id_type = SMB_ACL_USER_OBJ;
2227                         break;
2228  
2229                 default:
2230                         return(NULL);
2231                 }
2232  
2233                 acl_entry_link_head->count++;
2234                 DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
2235         }
2236
2237         acl_entry_link_head->count = 0;
2238         SAFE_FREE(file_acl);
2239  
2240         return(acl_entry_link_head);
2241 }
2242 #endif
2243
2244 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)
2245 {
2246         uint *permset;
2247
2248         if (sys_acl_get_tag_type(entry, tag_type_p) != 0)
2249                 return -1;
2250
2251         if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP)
2252                 memcpy(u_g_id_p, entry->ace_id->id_data, sizeof (id_t));
2253
2254         permset = &entry->ace_access;
2255
2256         DEBUG(10,("*permset is %d\n",*permset));
2257         *bits_p = (*permset & S_IRUSR ? 4 : 0)
2258                 | (*permset & S_IWUSR ? 2 : 0)
2259                 | (*permset & S_IXUSR ? 1 : 0);
2260
2261         return 0;
2262 }
2263
2264 SMB_ACL_T sys_acl_init( int count)
2265 {
2266         struct acl_entry_link *theacl = NULL;
2267  
2268         if (count < 0) {
2269                 errno = EINVAL;
2270                 return NULL;
2271         }
2272
2273         DEBUG(10,("Entering sys_acl_init\n"));
2274
2275         theacl = SMB_MALLOC_P(struct acl_entry_link);
2276         if(theacl == NULL) {
2277                 errno = ENOMEM;
2278                 DEBUG(0,("Error in sys_acl_init is %d\n",errno));
2279                 return(NULL);
2280         }
2281
2282         theacl->count = 0;
2283         theacl->nextp = NULL;
2284         theacl->prevp = NULL;
2285         theacl->entryp = NULL;
2286         DEBUG(10,("Exiting sys_acl_init\n"));
2287         return(theacl);
2288 }
2289
2290 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
2291 {
2292         struct acl_entry_link *theacl;
2293         struct acl_entry_link *acl_entryp;
2294         struct acl_entry_link *temp_entry;
2295         int counting;
2296
2297         DEBUG(10,("Entering the sys_acl_create_entry\n"));
2298
2299         theacl = acl_entryp = *pacl;
2300
2301         /* Get to the end of the acl before adding entry */
2302
2303         for(counting=0; counting < theacl->count; counting++){
2304                 DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
2305                 temp_entry = acl_entryp;
2306                 acl_entryp = acl_entryp->nextp;
2307         }
2308
2309         if(theacl->count != 0){
2310                 temp_entry->nextp = acl_entryp = SMB_MALLOC_P(struct acl_entry_link);
2311                 if(acl_entryp == NULL) {
2312                         errno = ENOMEM;
2313                         DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
2314                         return(-1);
2315                 }
2316
2317                 DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
2318                 acl_entryp->prevp = temp_entry;
2319                 DEBUG(10,("The acl_entryp->prevp is %d\n",acl_entryp->prevp));
2320         }
2321
2322         *pentry = acl_entryp->entryp = SMB_MALLOC_P(struct new_acl_entry);
2323         if(*pentry == NULL) {
2324                 errno = ENOMEM;
2325                 DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
2326                 return(-1);
2327         }
2328
2329         memset(*pentry,0,sizeof(struct new_acl_entry));
2330         acl_entryp->entryp->ace_len = sizeof(struct acl_entry);
2331         acl_entryp->entryp->ace_type = ACC_PERMIT;
2332         acl_entryp->entryp->ace_id->id_len = sizeof(struct ace_id);
2333         acl_entryp->nextp = NULL;
2334         theacl->count++;
2335         DEBUG(10,("Exiting sys_acl_create_entry\n"));
2336         return(0);
2337 }
2338
2339 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
2340 {
2341         entry->ace_id->id_type = tag_type;
2342         DEBUG(10,("The tag type is %d\n",entry->ace_id->id_type));
2343
2344         if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP)
2345                 memcpy(entry->ace_id->id_data, &u_g_id, sizeof (id_t));
2346
2347         entry->ace_access = bits;
2348         DEBUG(10,("entry->ace_access = %d\n",entry->ace_access));
2349
2350         return 0;
2351 }
2352
2353 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits)
2354 {
2355         DEBUG(10,("Starting AIX sys_acl_set_permset\n"));
2356         entry->ace_access = bits;
2357         DEBUG(10,("entry->ace_access = %d\n",entry->ace_access));
2358         DEBUG(10,("Ending AIX sys_acl_set_permset\n"));
2359         return(0);
2360 }
2361
2362 int sys_acl_valid( SMB_ACL_T theacl )
2363 {
2364         int user_obj = 0;
2365         int group_obj = 0;
2366         int other_obj = 0;
2367         struct acl_entry_link *acl_entry;
2368
2369         for(acl_entry=theacl; acl_entry != NULL; acl_entry = acl_entry->nextp) {
2370                 user_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_USER_OBJ);
2371                 group_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_GROUP_OBJ);
2372                 other_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_OTHER);
2373         }
2374
2375         DEBUG(10,("user_obj=%d, group_obj=%d, other_obj=%d\n",user_obj,group_obj,other_obj));
2376  
2377         if(user_obj != 1 || group_obj != 1 || other_obj != 1)
2378                 return(-1); 
2379
2380         return(0);
2381 }
2382
2383 int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2384 {
2385         struct acl_entry_link *acl_entry_link = NULL;
2386         struct acl *file_acl = NULL;
2387         struct acl *file_acl_temp = NULL;
2388         struct acl_entry *acl_entry = NULL;
2389         struct ace_id *ace_id = NULL;
2390         uint id_type;
2391         uint user_id;
2392         uint acl_length;
2393         uint rc;
2394
2395         DEBUG(10,("Entering sys_acl_set_file\n"));
2396         DEBUG(10,("File name is %s\n",name));
2397  
2398         /* AIX has no default ACL */
2399         if(acltype == SMB_ACL_TYPE_DEFAULT)
2400                 return(0);
2401
2402         acl_length = BUFSIZ;
2403         file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2404
2405         if(file_acl == NULL) {
2406                 errno = ENOMEM;
2407                 DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
2408                 return(-1);
2409         }
2410
2411         memset(file_acl,0,BUFSIZ);
2412
2413         file_acl->acl_len = ACL_SIZ;
2414         file_acl->acl_mode = S_IXACL;
2415
2416         for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
2417                 acl_entry_link->entryp->ace_access >>= 6;
2418                 id_type = acl_entry_link->entryp->ace_id->id_type;
2419
2420                 switch(id_type) {
2421                 case SMB_ACL_USER_OBJ:
2422                         file_acl->u_access = acl_entry_link->entryp->ace_access;
2423                         continue;
2424                 case SMB_ACL_GROUP_OBJ:
2425                         file_acl->g_access = acl_entry_link->entryp->ace_access;
2426                         continue;
2427                 case SMB_ACL_OTHER:
2428                         file_acl->o_access = acl_entry_link->entryp->ace_access;
2429                         continue;
2430                 case SMB_ACL_MASK:
2431                         continue;
2432                 }
2433
2434                 if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
2435                         acl_length += sizeof(struct acl_entry);
2436                         file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
2437                         if(file_acl_temp == NULL) {
2438                                 SAFE_FREE(file_acl);
2439                                 errno = ENOMEM;
2440                                 DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
2441                                 return(-1);
2442                         }  
2443
2444                         memcpy(file_acl_temp,file_acl,file_acl->acl_len);
2445                         SAFE_FREE(file_acl);
2446                         file_acl = file_acl_temp;
2447                 }
2448
2449                 acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
2450                 file_acl->acl_len += sizeof(struct acl_entry);
2451                 acl_entry->ace_len = acl_entry_link->entryp->ace_len;
2452                 acl_entry->ace_access = acl_entry_link->entryp->ace_access;
2453  
2454                 /* In order to use this, we'll need to wait until we can get denies */
2455                 /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
2456                 acl_entry->ace_type = ACC_SPECIFY; */
2457
2458                 acl_entry->ace_type = ACC_SPECIFY;
2459  
2460                 ace_id = acl_entry->ace_id;
2461  
2462                 ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
2463                 DEBUG(10,("The id type is %d\n",ace_id->id_type));
2464                 ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
2465                 memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
2466                 memcpy(acl_entry->ace_id->id_data, &user_id, sizeof(uid_t));
2467         }
2468
2469         rc = chacl((char*)name,file_acl,file_acl->acl_len);
2470         DEBUG(10,("errno is %d\n",errno));
2471         DEBUG(10,("return code is %d\n",rc));
2472         SAFE_FREE(file_acl);
2473         DEBUG(10,("Exiting the sys_acl_set_file\n"));
2474         return(rc);
2475 }
2476
2477 #if 0
2478 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
2479 {
2480         struct acl_entry_link *acl_entry_link = NULL;
2481         struct acl *file_acl = NULL;
2482         struct acl *file_acl_temp = NULL;
2483         struct acl_entry *acl_entry = NULL;
2484         struct ace_id *ace_id = NULL;
2485         uint id_type;
2486         uint user_id;
2487         uint acl_length;
2488         uint rc;
2489  
2490         DEBUG(10,("Entering sys_acl_set_fd\n"));
2491         acl_length = BUFSIZ;
2492         file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2493
2494         if(file_acl == NULL) {
2495                 errno = ENOMEM;
2496                 DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
2497                 return(-1);
2498         }
2499
2500         memset(file_acl,0,BUFSIZ);
2501  
2502         file_acl->acl_len = ACL_SIZ;
2503         file_acl->acl_mode = S_IXACL;
2504
2505         for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
2506                 acl_entry_link->entryp->ace_access >>= 6;
2507                 id_type = acl_entry_link->entryp->ace_id->id_type;
2508                 DEBUG(10,("The id_type is %d\n",id_type));
2509
2510                 switch(id_type) {
2511                 case SMB_ACL_USER_OBJ:
2512                         file_acl->u_access = acl_entry_link->entryp->ace_access;
2513                         continue;
2514                 case SMB_ACL_GROUP_OBJ:
2515                         file_acl->g_access = acl_entry_link->entryp->ace_access;
2516                         continue;
2517                 case SMB_ACL_OTHER:
2518                         file_acl->o_access = acl_entry_link->entryp->ace_access;
2519                         continue;
2520                 case SMB_ACL_MASK:
2521                         continue;
2522                 }
2523
2524                 if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
2525                         acl_length += sizeof(struct acl_entry);
2526                         file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
2527                         if(file_acl_temp == NULL) {
2528                                 SAFE_FREE(file_acl);
2529                                 errno = ENOMEM;
2530                                 DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
2531                                 return(-1);
2532                         }
2533
2534                         memcpy(file_acl_temp,file_acl,file_acl->acl_len);
2535                         SAFE_FREE(file_acl);
2536                         file_acl = file_acl_temp;
2537                 }
2538
2539                 acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
2540                 file_acl->acl_len += sizeof(struct acl_entry);
2541                 acl_entry->ace_len = acl_entry_link->entryp->ace_len;
2542                 acl_entry->ace_access = acl_entry_link->entryp->ace_access;
2543  
2544                 /* In order to use this, we'll need to wait until we can get denies */
2545                 /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
2546                         acl_entry->ace_type = ACC_SPECIFY; */
2547  
2548                 acl_entry->ace_type = ACC_SPECIFY;
2549  
2550                 ace_id = acl_entry->ace_id;
2551  
2552                 ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
2553                 DEBUG(10,("The id type is %d\n",ace_id->id_type));
2554                 ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
2555                 memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
2556                 memcpy(ace_id->id_data, &user_id, sizeof(uid_t));
2557         }
2558  
2559         rc = fchacl(fd,file_acl,file_acl->acl_len);
2560         DEBUG(10,("errno is %d\n",errno));
2561         DEBUG(10,("return code is %d\n",rc));
2562         SAFE_FREE(file_acl);
2563         DEBUG(10,("Exiting sys_acl_set_fd\n"));
2564         return(rc);
2565 }
2566 #endif
2567
2568 int sys_acl_delete_def_file(UNUSED(const char *name))
2569 {
2570         /* AIX has no default ACL */
2571         return 0;
2572 }
2573
2574 int sys_acl_free_acl(SMB_ACL_T posix_acl)
2575 {
2576         struct acl_entry_link *acl_entry_link;
2577
2578         for(acl_entry_link = posix_acl->nextp; acl_entry_link->nextp != NULL; acl_entry_link = acl_entry_link->nextp) {
2579                 SAFE_FREE(acl_entry_link->prevp->entryp);
2580                 SAFE_FREE(acl_entry_link->prevp);
2581         }
2582
2583         SAFE_FREE(acl_entry_link->prevp->entryp);
2584         SAFE_FREE(acl_entry_link->prevp);
2585         SAFE_FREE(acl_entry_link->entryp);
2586         SAFE_FREE(acl_entry_link);
2587  
2588         return(0);
2589 }
2590
2591 #elif defined(HAVE_OSX_ACLS) /*----------------------------------------------*/
2592
2593 #define OSX_BROKEN_GETENTRY /* returns 0 instead of 1 */
2594
2595 #include <membership.h>
2596
2597 int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
2598 {
2599         int ret = acl_get_entry(the_acl, entry_id, entry_p);
2600 #ifdef OSX_BROKEN_GETENTRY
2601         if (ret == 0)
2602                 ret = 1;
2603         else if (ret == -1 && errno == 22)
2604                 ret = 0;
2605 #endif
2606         return ret;
2607 }
2608
2609 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
2610 {
2611         if (type == ACL_TYPE_DEFAULT) {
2612                 errno = ENOTSUP;
2613                 return NULL;
2614         }
2615         errno = 0;
2616         return acl_get_file(path_p, type);
2617 }
2618
2619 #if 0
2620 SMB_ACL_T sys_acl_get_fd(int fd)
2621 {
2622         return acl_get_fd(fd);
2623 }
2624 #endif
2625
2626 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)
2627 {
2628         uuid_t *uup;
2629         acl_tag_t tag;
2630         acl_flagset_t flagset;
2631         acl_permset_t permset;
2632         uint32 bits, fb, bb, pb;
2633         int id_type = -1;
2634         int rc;
2635
2636         if (acl_get_tag_type(entry, &tag) != 0
2637          || acl_get_flagset_np(entry, &flagset) != 0
2638          || acl_get_permset(entry, &permset) != 0
2639          || (uup = acl_get_qualifier(entry)) == NULL)
2640                 return -1;
2641
2642         rc = mbr_uuid_to_id(*uup, u_g_id_p, &id_type);
2643         acl_free(uup);
2644         if (rc != 0)
2645                 return rc;
2646
2647         if (id_type == ID_TYPE_UID)
2648                 *tag_type_p = SMB_ACL_USER;
2649         else
2650                 *tag_type_p = SMB_ACL_GROUP;
2651
2652         bits = tag == ACL_EXTENDED_ALLOW ? 1 : 0;
2653
2654         for (fb = (1u<<4), bb = (1u<<1); bb < (1u<<12); fb *= 2, bb *= 2) {
2655                 if (acl_get_flag_np(flagset, fb) == 1)
2656                         bits |= bb;
2657         }
2658
2659         for (pb = (1u<<1), bb = (1u<<12); bb < (1u<<25); pb *= 2, bb *= 2) {
2660                 if (acl_get_perm_np(permset, pb) == 1)
2661                         bits |= bb;
2662         }
2663
2664         *bits_p = bits;
2665
2666         return 0;
2667 }
2668
2669 SMB_ACL_T sys_acl_init(int count)
2670 {
2671         return acl_init(count);
2672 }
2673
2674 int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
2675 {
2676         return acl_create_entry(pacl, pentry);
2677 }
2678
2679 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
2680 {
2681         acl_flagset_t flagset;
2682         acl_permset_t permset;
2683         uint32 fb, bb, pb;
2684         int is_user = tag_type == SMB_ACL_USER;
2685         uuid_t uu;
2686         int rc;
2687
2688         tag_type = bits & 1 ? ACL_EXTENDED_ALLOW : ACL_EXTENDED_DENY;
2689
2690         if (acl_get_flagset_np(entry, &flagset) != 0
2691          || acl_get_permset(entry, &permset) != 0)
2692                 return -1;
2693
2694         acl_clear_flags_np(flagset);
2695         acl_clear_perms(permset);
2696
2697         for (fb = (1u<<4), bb = (1u<<1); bb < (1u<<12); fb *= 2, bb *= 2) {
2698                 if (bits & bb)
2699                         acl_add_flag_np(flagset, fb);
2700         }
2701
2702         for (pb = (1u<<1), bb = (1u<<12); bb < (1u<<25); pb *= 2, bb *= 2) {
2703                 if (bits & bb)
2704                         acl_add_perm(permset, pb);
2705         }
2706
2707         if (is_user)
2708                 rc = mbr_uid_to_uuid(u_g_id, uu);
2709         else
2710                 rc = mbr_gid_to_uuid(u_g_id, uu);
2711         if (rc != 0)
2712                 return rc;
2713
2714         if (acl_set_tag_type(entry, tag_type) != 0
2715          || acl_set_qualifier(entry, &uu) != 0
2716          || acl_set_permset(entry, permset) != 0
2717          || acl_set_flagset_np(entry, flagset) != 0)
2718                 return -1;
2719
2720         return 0;
2721 }
2722
2723 #if 0
2724 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits)
2725 {
2726         return -1; /* Not needed for OS X. */
2727 }
2728 #endif
2729
2730 int sys_acl_valid(SMB_ACL_T theacl)
2731 {
2732         return acl_valid(theacl);
2733 }
2734
2735 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2736 {
2737         return acl_set_file(name, acltype, theacl);
2738 }
2739
2740 #if 0
2741 int sys_acl_set_fd(int fd, SMB_ACL_T theacl)
2742 {
2743         return acl_set_fd(fd, theacl);
2744 }
2745 #endif
2746
2747 int sys_acl_delete_def_file(const char *name)
2748 {
2749         return acl_delete_def_file(name);
2750 }
2751
2752 int sys_acl_free_acl(SMB_ACL_T the_acl)
2753 {
2754         return acl_free(the_acl);
2755 }
2756
2757 #else /* No ACLs. */
2758
2759 #error No ACL functions defined for this platform!
2760
2761 #endif
2762
2763 /************************************************************************
2764  Deliberately outside the ACL defines. Return 1 if this is a "no acls"
2765  errno, 0 if not.
2766 ************************************************************************/
2767
2768 int no_acl_syscall_error(int err)
2769 {
2770 #ifdef HAVE_OSX_ACLS
2771         if (err == ENOENT)
2772                 return 1; /* Weird problem with directory ACLs. */
2773 #endif
2774 #if defined(ENOSYS)
2775         if (err == ENOSYS) {
2776                 return 1;
2777         }
2778 #endif
2779 #if defined(ENOTSUP)
2780         if (err == ENOTSUP) {
2781                 return 1;
2782         }
2783 #endif
2784         if (err == EINVAL) {
2785                 /* If the type of SMB_ACL_TYPE_ACCESS or SMB_ACL_TYPE_DEFAULT
2786                  * isn't valid, then the ACLs must be non-POSIX. */
2787                 return 1;
2788         }
2789         return 0;
2790 }
2791
2792 #endif /* SUPPORT_ACLS */