Added POSIX_ACL support for *BSD. Patch from jedgar@fxp.org. Changed
[abartlet/samba.git/.git] / source / lib / sysacls.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 2.2.
4    Samba system utilities for ACL support.
5    Copyright (C) Jeremy Allison 2000.
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 extern int DEBUGLEVEL;
25
26 /*
27  This file wraps all differing system ACL interfaces into a consistent
28  one based on the POSIX interface. It also returns the correct errors
29  for older UNIX systems that don't support ACLs.
30
31  The interfaces that each ACL implementation must support are as follows :
32
33  int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
34  int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
35  int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p
36  void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
37  SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
38  SMB_ACL_T sys_acl_get_fd(int fd)
39  int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset);
40  int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm);
41  char *sys_acl_to_text( SMB_ACL_T theacl, ssize_t *plen)
42  SMB_ACL_T sys_acl_init( int count)
43  int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
44  int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
45  int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
46  int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
47  int sys_acl_valid( SMB_ACL_T theacl )
48  int sys_acl_set_file( char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
49  int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
50
51  This next one is not POSIX complient - but we *have* to have it !
52  More POSIX braindamage.
53
54  int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
55
56  The generic POSIX free is the following call. We split this into
57  several different free functions as we may need to add tag info
58  to structures when emulating the POSIX interface.
59
60  int sys_acl_free( void *obj_p)
61
62  The calls we actually use are :
63
64  int sys_acl_free_text(char *text) - free acl_to_text
65  int sys_acl_free_acl(SMB_ACL_T posix_acl)
66  int sys_acl_free_qualifier(SMB_ACL_T posix_acl)
67
68 */
69
70 #if defined(HAVE_POSIX_ACLS)
71
72 /* Identity mapping - easy. */
73
74 int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
75 {
76         return acl_get_entry( the_acl, entry_id, entry_p);
77 }
78
79 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
80 {
81         return acl_get_tag_type( entry_d, tag_type_p);
82 }
83
84 int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
85 {
86         return acl_get_permset( entry_d, permset_p);
87 }
88
89 void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
90 {
91         return acl_get_qualifier( entry_d);
92 }
93
94 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
95 {
96         return acl_get_file( path_p, type);
97 }
98
99 SMB_ACL_T sys_acl_get_fd(int fd)
100 {
101         return acl_get_fd(fd);
102 }
103
104 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
105 {
106         return acl_clear_perms(permset);
107 }
108
109 int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
110 {
111         return acl_add_perm(permset, perm);
112 }
113
114 int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
115 {
116 #if defined(HAVE_ACL_GET_PERM_NP)
117         /*
118          * Required for TrustedBSD-based ACL implementations where
119          * non-POSIX.1e functions are denoted by a _np (non-portable)
120          * suffix.
121          */
122         return acl_get_perm_np(permset, perm);
123 #else
124         return acl_get_perm(permset, perm);
125 #endif
126 }
127
128 char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
129 {
130         return acl_to_text( the_acl, plen);
131 }
132
133 SMB_ACL_T sys_acl_init( int count)
134 {
135         return acl_init(count);
136 }
137
138 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
139 {
140         return acl_create_entry(pacl, pentry);
141 }
142
143 int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
144 {
145         return acl_set_tag_type(entry, tagtype);
146 }
147
148 int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
149 {
150         return acl_set_qualifier(entry, qual);
151 }
152
153 int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
154 {
155         return acl_set_permset(entry, permset);
156 }
157
158 int sys_acl_valid( SMB_ACL_T theacl )
159 {
160         return acl_valid(theacl);
161 }
162
163 int sys_acl_set_file( char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
164 {
165         return acl_set_file(name, acltype, theacl);
166 }
167
168 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
169 {
170         return acl_set_fd(fd, theacl);
171 }
172
173 int sys_acl_free_text(char *text)
174 {
175         return acl_free(text);
176 }
177
178 int sys_acl_free_acl(SMB_ACL_T the_acl) 
179 {
180         return acl_free(the_acl);
181 }
182
183 int sys_acl_free_qualifier(void *qual) 
184 {
185         return acl_free(qual);
186 }
187
188 #elif defined(HAVE_UNIXWARE_ACLS) || defined(HAVE_SOLARIS_ACLS)
189
190 /*
191  * Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX.
192  * Modified by Toomas Soome <tsoome@ut.ee> for Solaris.
193  */
194
195 /*
196  * Note that while this code implements sufficient functionality
197  * to support the sys_acl_* interfaces it does not provide all
198  * of the semantics of the POSIX ACL interfaces.
199  *
200  * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
201  * from a call to sys_acl_get_entry() should not be assumed to be
202  * valid after calling any of the following functions, which may
203  * reorder the entries in the ACL.
204  *
205  *      sys_acl_valid()
206  *      sys_acl_set_file()
207  *      sys_acl_set_fd()
208  */
209
210 /*
211  * The only difference between Solaris and UnixWare / OpenUNIX is
212  * that the #defines for the ACL operations have different names
213  */
214 #if defined(HAVE_UNIXWARE_ACLS)
215
216 #define SETACL          ACL_SET
217 #define GETACL          ACL_GET
218 #define GETACLCNT       ACL_CNT
219
220 #endif
221
222
223 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
224 {
225         if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
226                 errno = EINVAL;
227                 return -1;
228         }
229
230         if (entry_p == NULL) {
231                 errno = EINVAL;
232                 return -1;
233         }
234
235         if (entry_id == SMB_ACL_FIRST_ENTRY) {
236                 acl_d->next = 0;
237         }
238
239         if (acl_d->next < 0) {
240                 errno = EINVAL;
241                 return -1;
242         }
243
244         if (acl_d->next >= acl_d->count) {
245                 return 0;
246         }
247
248         *entry_p = &acl_d->acl[acl_d->next++];
249
250         return 1;
251 }
252
253 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
254 {
255         *type_p = entry_d->a_type;
256
257         return 0;
258 }
259
260 int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
261 {
262         *permset_p = &entry_d->a_perm;
263
264         return 0;
265 }
266
267 void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
268 {
269         if (entry_d->a_type != SMB_ACL_USER
270             && entry_d->a_type != SMB_ACL_GROUP) {
271                 errno = EINVAL;
272                 return NULL;
273         }
274
275         return &entry_d->a_id;
276 }
277
278 /*
279  * There is no way of knowing what size the ACL returned by
280  * GETACL will be unless you first call GETACLCNT which means
281  * making an additional system call.
282  *
283  * In the hope of avoiding the cost of the additional system
284  * call in most cases, we initially allocate enough space for
285  * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
286  * be too small then we use GETACLCNT to find out the actual
287  * size, reallocate the ACL buffer, and then call GETACL again.
288  */
289
290 #define INITIAL_ACL_SIZE        16
291
292 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
293 {
294         SMB_ACL_T       acl_d;
295         int             count;          /* # of ACL entries allocated   */
296         int             naccess;        /* # of access ACL entries      */
297         int             ndefault;       /* # of default ACL entries     */
298
299         if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
300                 errno = EINVAL;
301                 return NULL;
302         }
303
304         count = INITIAL_ACL_SIZE;
305         if ((acl_d = sys_acl_init(count)) == NULL) {
306                 return NULL;
307         }
308
309         /*
310          * If there isn't enough space for the ACL entries we use
311          * GETACLCNT to determine the actual number of ACL entries
312          * reallocate and try again. This is in a loop because it
313          * is possible that someone else could modify the ACL and
314          * increase the number of entries between the call to
315          * GETACLCNT and the call to GETACL.
316          */
317         while ((count = acl(path_p, GETACL, count, &acl_d->acl[0])) < 0
318             && errno == ENOSPC) {
319
320                 sys_acl_free_acl(acl_d);
321
322                 if ((count = acl(path_p, GETACLCNT, 0, NULL)) < 0) {
323                         return NULL;
324                 }
325
326                 if ((acl_d = sys_acl_init(count)) == NULL) {
327                         return NULL;
328                 }
329         }
330
331         if (count < 0) {
332                 sys_acl_free_acl(acl_d);
333                 return NULL;
334         }
335
336         /*
337          * calculate the number of access and default ACL entries
338          *
339          * Note: we assume that the acl() system call returned a
340          * well formed ACL which is sorted so that all of the
341          * access ACL entries preceed any default ACL entries
342          */
343         for (naccess = 0; naccess < count; naccess++) {
344                 if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
345                         break;
346         }
347         ndefault = count - naccess;
348         
349         /*
350          * if the caller wants the default ACL we have to copy
351          * the entries down to the start of the acl[] buffer
352          * and mask out the ACL_DEFAULT flag from the type field
353          */
354         if (type == SMB_ACL_TYPE_DEFAULT) {
355                 int     i, j;
356
357                 for (i = 0, j = naccess; i < ndefault; i++, j++) {
358                         acl_d->acl[i] = acl_d->acl[j];
359                         acl_d->acl[i].a_type &= ~ACL_DEFAULT;
360                 }
361
362                 acl_d->count = ndefault;
363         } else {
364                 acl_d->count = naccess;
365         }
366
367         return acl_d;
368 }
369
370 SMB_ACL_T sys_acl_get_fd(int fd)
371 {
372         SMB_ACL_T       acl_d;
373         int             count;          /* # of ACL entries allocated   */
374         int             naccess;        /* # of access ACL entries      */
375
376         count = INITIAL_ACL_SIZE;
377         if ((acl_d = sys_acl_init(count)) == NULL) {
378                 return NULL;
379         }
380
381         while ((count = facl(fd, GETACL, count, &acl_d->acl[0])) < 0
382             && errno == ENOSPC) {
383
384                 sys_acl_free_acl(acl_d);
385
386                 if ((count = facl(fd, GETACLCNT, 0, NULL)) < 0) {
387                         return NULL;
388                 }
389
390                 if ((acl_d = sys_acl_init(count)) == NULL) {
391                         return NULL;
392                 }
393         }
394
395         if (count < 0) {
396                 sys_acl_free_acl(acl_d);
397                 return NULL;
398         }
399
400         /*
401          * calculate the number of access ACL entries
402          */
403         for (naccess = 0; naccess < count; naccess++) {
404                 if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
405                         break;
406         }
407         
408         acl_d->count = naccess;
409
410         return acl_d;
411 }
412
413 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
414 {
415         *permset_d = 0;
416
417         return 0;
418 }
419
420 int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
421 {
422         if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
423             && perm != SMB_ACL_EXECUTE) {
424                 errno = EINVAL;
425                 return -1;
426         }
427
428         if (permset_d == NULL) {
429                 errno = EINVAL;
430                 return -1;
431         }
432
433         *permset_d |= perm;
434
435         return 0;
436 }
437
438 int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
439 {
440         return *permset_d & perm;
441 }
442
443 char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
444 {
445         int     i;
446         int     len, maxlen;
447         char    *text;
448
449         /*
450          * use an initial estimate of 20 bytes per ACL entry
451          * when allocating memory for the text representation
452          * of the ACL
453          */
454         len     = 0;
455         maxlen  = 20 * acl_d->count;
456         if ((text = malloc(maxlen)) == NULL) {
457                 errno = ENOMEM;
458                 return NULL;
459         }
460
461         for (i = 0; i < acl_d->count; i++) {
462                 struct acl      *ap     = &acl_d->acl[i];
463                 struct passwd   *pw;
464                 struct group    *gr;
465                 char            tagbuf[12];
466                 char            idbuf[12];
467                 char            *tag;
468                 char            *id     = "";
469                 char            perms[4];
470                 int             nbytes;
471
472                 switch (ap->a_type) {
473                         /*
474                          * for debugging purposes it's probably more
475                          * useful to dump unknown tag types rather
476                          * than just returning an error
477                          */
478                         default:
479                                 slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
480                                         ap->a_type);
481                                 tag = tagbuf;
482                                 slprintf(idbuf, sizeof(idbuf)-1, "%ld",
483                                         (long)ap->a_id);
484                                 id = idbuf;
485                                 break;
486
487                         case SMB_ACL_USER:
488                                 if ((pw = sys_getpwuid(ap->a_id)) == NULL) {
489                                         slprintf(idbuf, sizeof(idbuf)-1, "%ld",
490                                                 (long)ap->a_id);
491                                         id = idbuf;
492                                 } else {
493                                         id = pw->pw_name;
494                                 }
495                         case SMB_ACL_USER_OBJ:
496                                 tag = "user";
497                                 break;
498
499                         case SMB_ACL_GROUP:
500                                 if ((gr = getgrgid(ap->a_id)) == NULL) {
501                                         slprintf(idbuf, sizeof(idbuf)-1, "%ld",
502                                                 (long)ap->a_id);
503                                         id = idbuf;
504                                 } else {
505                                         id = gr->gr_name;
506                                 }
507                         case SMB_ACL_GROUP_OBJ:
508                                 tag = "group";
509                                 break;
510
511                         case SMB_ACL_OTHER:
512                                 tag = "other";
513                                 break;
514
515                         case SMB_ACL_MASK:
516                                 tag = "mask";
517                                 break;
518
519                 }
520
521                 perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
522                 perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
523                 perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
524                 perms[3] = '\0';
525
526                 /*          <tag>      :  <qualifier>   :  rwx \n  \0 */
527                 nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
528
529                 /*
530                  * If this entry would overflow the buffer
531                  * allocate enough additional memory for this
532                  * entry and an estimate of another 20 bytes
533                  * for each entry still to be processed
534                  */
535                 if ((len + nbytes) > maxlen) {
536                         char *oldtext = text;
537
538                         maxlen += nbytes + 20 * (acl_d->count - i);
539
540                         if ((text = realloc(oldtext, maxlen)) == NULL) {
541                                 free(oldtext);
542                                 errno = ENOMEM;
543                                 return NULL;
544                         }
545                 }
546
547                 slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
548                 len += nbytes - 1;
549         }
550
551         if (len_p)
552                 *len_p = len;
553
554         return text;
555 }
556
557 SMB_ACL_T sys_acl_init(int count)
558 {
559         SMB_ACL_T       a;
560
561         if (count < 0) {
562                 errno = EINVAL;
563                 return NULL;
564         }
565
566         /*
567          * note that since the definition of the structure pointed
568          * to by the SMB_ACL_T includes the first element of the
569          * acl[] array, this actually allocates an ACL with room
570          * for (count+1) entries
571          */
572         if ((a = malloc(sizeof(*a) + count * sizeof(struct acl))) == NULL) {
573                 errno = ENOMEM;
574                 return NULL;
575         }
576
577         a->size = count + 1;
578         a->count = 0;
579         a->next = -1;
580
581         return a;
582 }
583
584
585 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
586 {
587         SMB_ACL_T       acl_d;
588         SMB_ACL_ENTRY_T entry_d;
589
590         if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
591                 errno = EINVAL;
592                 return -1;
593         }
594
595         if (acl_d->count >= acl_d->size) {
596                 errno = ENOSPC;
597                 return -1;
598         }
599
600         entry_d         = &acl_d->acl[acl_d->count++];
601         entry_d->a_type = 0;
602         entry_d->a_id   = -1;
603         entry_d->a_perm = 0;
604         *entry_p        = entry_d;
605
606         return 0;
607 }
608
609 int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
610 {
611         switch (tag_type) {
612                 case SMB_ACL_USER:
613                 case SMB_ACL_USER_OBJ:
614                 case SMB_ACL_GROUP:
615                 case SMB_ACL_GROUP_OBJ:
616                 case SMB_ACL_OTHER:
617                 case SMB_ACL_MASK:
618                         entry_d->a_type = tag_type;
619                         break;
620                 default:
621                         errno = EINVAL;
622                         return -1;
623         }
624
625         return 0;
626 }
627
628 int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
629 {
630         if (entry_d->a_type != SMB_ACL_GROUP
631             && entry_d->a_type != SMB_ACL_USER) {
632                 errno = EINVAL;
633                 return -1;
634         }
635
636         entry_d->a_id = *((id_t *)qual_p);
637
638         return 0;
639 }
640
641 int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
642 {
643         if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
644                 return EINVAL;
645         }
646
647         entry_d->a_perm = *permset_d;
648
649         return 0;
650 }
651
652 int sys_acl_valid(SMB_ACL_T acl_d)
653 {
654         if (aclsort(acl_d->count, 1, acl_d->acl) != 0) {
655                 errno = EINVAL;
656                 return -1;
657         }
658
659         return 0;
660 }
661
662 int sys_acl_set_file(char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
663 {
664         struct stat     s;
665         struct acl      *acl_p;
666         int             acl_count;
667         struct acl      *acl_buf        = NULL;
668         int             ret;
669
670         if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
671                 errno = EINVAL;
672                 return -1;
673         }
674
675         if (stat(name, &s) != 0) {
676                 return -1;
677         }
678
679         acl_p           = &acl_d->acl[0];
680         acl_count       = acl_d->count;
681
682         /*
683          * if it's a directory there is extra work to do
684          * since the acl() system call will replace both
685          * the access ACLs and the default ACLs (if any)
686          */
687         if (S_ISDIR(s.st_mode)) {
688                 SMB_ACL_T       acc_acl;
689                 SMB_ACL_T       def_acl;
690                 SMB_ACL_T       tmp_acl;
691                 int             i;
692
693                 if (type == SMB_ACL_TYPE_ACCESS) {
694                         acc_acl = acl_d;
695                         def_acl = 
696                         tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
697
698                 } else {
699                         def_acl = acl_d;
700                         acc_acl = 
701                         tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
702                 }
703
704                 if (tmp_acl == NULL) {
705                         return -1;
706                 }
707
708                 /*
709                  * allocate a temporary buffer for the complete ACL
710                  */
711                 acl_count       = acc_acl->count + def_acl->count;
712                 acl_p           =
713                 acl_buf         = malloc(acl_count * sizeof(acl_buf[0]));
714
715                 if (acl_buf == NULL) {
716                         sys_acl_free_acl(tmp_acl);
717                         errno = ENOMEM;
718                         return -1;
719                 }
720
721                 /*
722                  * copy the access control and default entries into the buffer
723                  */
724                 memcpy(&acl_buf[0], &acc_acl->acl[0],
725                         acc_acl->count * sizeof(acl_buf[0]));
726
727                 memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
728                         def_acl->count * sizeof(acl_buf[0]));
729
730                 /*
731                  * set the ACL_DEFAULT flag on the default entries
732                  */
733                 for (i = acc_acl->count; i < acl_count; i++) {
734                         acl_buf[i].a_type |= ACL_DEFAULT;
735                 }
736
737                 sys_acl_free_acl(tmp_acl);
738
739         } else if (type != SMB_ACL_TYPE_ACCESS) {
740                 errno = EINVAL;
741                 return -1;
742         }
743
744         if (aclsort(acl_count, 1, acl_p) != 0) {
745                 errno = EINVAL;
746                 ret = -1;
747         } else {
748                 ret = acl(name, SETACL, acl_count, acl_p);
749         }
750
751         if (acl_buf) {
752                 free(acl_buf);
753         }
754
755         return ret;
756 }
757
758 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
759 {
760         if (aclsort(acl_d->count, 1, acl_d->acl) != 0) {
761                 errno = EINVAL;
762                 return -1;
763         }
764
765         return facl(fd, SETACL, acl_d->count, &acl_d->acl[0]);
766 }
767
768 int sys_acl_free_text(char *text)
769 {
770         free(text);
771         return 0;
772 }
773
774 int sys_acl_free_acl(SMB_ACL_T acl_d) 
775 {
776         free(acl_d);
777         return 0;
778 }
779
780 int sys_acl_free_qualifier(void *qual) 
781 {
782         return 0;
783 }
784
785 #elif defined(HAVE_IRIX_ACLS)
786
787 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
788 {
789         if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
790                 errno = EINVAL;
791                 return -1;
792         }
793
794         if (entry_p == NULL) {
795                 errno = EINVAL;
796                 return -1;
797         }
798
799         if (entry_id == SMB_ACL_FIRST_ENTRY) {
800                 acl_d->next = 0;
801         }
802
803         if (acl_d->next < 0) {
804                 errno = EINVAL;
805                 return -1;
806         }
807
808         if (acl_d->next >= acl_d->aclp->acl_cnt) {
809                 return 0;
810         }
811
812         *entry_p = &acl_d->aclp->acl_entry[acl_d->next++];
813
814         return 1;
815 }
816
817 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
818 {
819         *type_p = entry_d->ae_tag;
820
821         return 0;
822 }
823
824 int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
825 {
826         *permset_p = entry_d;
827
828         return 0;
829 }
830
831 void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
832 {
833         if (entry_d->ae_tag != SMB_ACL_USER
834             && entry_d->ae_tag != SMB_ACL_GROUP) {
835                 errno = EINVAL;
836                 return NULL;
837         }
838
839         return &entry_d->ae_id;
840 }
841
842 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
843 {
844         SMB_ACL_T       a;
845
846         if ((a = malloc(sizeof(*a))) == NULL) {
847                 errno = ENOMEM;
848                 return NULL;
849         }
850         if ((a->aclp = acl_get_file(path_p, type)) == NULL) {
851                 free(a);
852                 return NULL;
853         }
854         a->next = -1;
855         a->freeaclp = True;
856         return a;
857 }
858
859 SMB_ACL_T sys_acl_get_fd(int fd)
860 {
861         SMB_ACL_T       a;
862
863         if ((a = malloc(sizeof(*a))) == NULL) {
864                 errno = ENOMEM;
865                 return NULL;
866         }
867         if ((a->aclp = acl_get_fd(fd)) == NULL) {
868                 free(a);
869                 return NULL;
870         }
871         a->next = -1;
872         a->freeaclp = True;
873         return a;
874 }
875
876 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
877 {
878         permset_d->ae_perm = 0;
879
880         return 0;
881 }
882
883 int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
884 {
885         if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
886             && perm != SMB_ACL_EXECUTE) {
887                 errno = EINVAL;
888                 return -1;
889         }
890
891         if (permset_d == NULL) {
892                 errno = EINVAL;
893                 return -1;
894         }
895
896         permset_d->ae_perm |= perm;
897
898         return 0;
899 }
900
901 int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
902 {
903         return permset_d->ae_perm & perm;
904 }
905
906 char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
907 {
908         return acl_to_text(acl_d->aclp, len_p);
909 }
910
911 SMB_ACL_T sys_acl_init(int count)
912 {
913         SMB_ACL_T       a;
914
915         if (count < 0) {
916                 errno = EINVAL;
917                 return NULL;
918         }
919
920         if ((a = malloc(sizeof(*a) + sizeof(struct acl))) == NULL) {
921                 errno = ENOMEM;
922                 return NULL;
923         }
924
925         a->next = -1;
926         a->freeaclp = False;
927         a->aclp = (struct acl *)(&a->aclp + sizeof(struct acl *));
928         a->aclp->acl_cnt = 0;
929
930         return a;
931 }
932
933
934 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
935 {
936         SMB_ACL_T       acl_d;
937         SMB_ACL_ENTRY_T entry_d;
938
939         if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
940                 errno = EINVAL;
941                 return -1;
942         }
943
944         if (acl_d->aclp->acl_cnt >= ACL_MAX_ENTRIES) {
945                 errno = ENOSPC;
946                 return -1;
947         }
948
949         entry_d         = &acl_d->aclp->acl_entry[acl_d->aclp->acl_cnt++];
950         entry_d->ae_tag = 0;
951         entry_d->ae_id  = 0;
952         entry_d->ae_perm        = 0;
953         *entry_p        = entry_d;
954
955         return 0;
956 }
957
958 int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
959 {
960         switch (tag_type) {
961                 case SMB_ACL_USER:
962                 case SMB_ACL_USER_OBJ:
963                 case SMB_ACL_GROUP:
964                 case SMB_ACL_GROUP_OBJ:
965                 case SMB_ACL_OTHER:
966                 case SMB_ACL_MASK:
967                         entry_d->ae_tag = tag_type;
968                         break;
969                 default:
970                         errno = EINVAL;
971                         return -1;
972         }
973
974         return 0;
975 }
976
977 int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
978 {
979         if (entry_d->ae_tag != SMB_ACL_GROUP
980             && entry_d->ae_tag != SMB_ACL_USER) {
981                 errno = EINVAL;
982                 return -1;
983         }
984
985         entry_d->ae_id = *((id_t *)qual_p);
986
987         return 0;
988 }
989
990 int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
991 {
992         if (permset_d->ae_perm & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
993                 return EINVAL;
994         }
995
996         entry_d->ae_perm = permset_d->ae_perm;
997
998         return 0;
999 }
1000
1001 int sys_acl_valid(SMB_ACL_T acl_d)
1002 {
1003         return acl_valid(acl_d->aclp);
1004 }
1005
1006 int sys_acl_set_file(char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
1007 {
1008         return acl_set_file(name, type, acl_d->aclp);
1009 }
1010
1011 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
1012 {
1013         return acl_set_fd(fd, acl_d->aclp);
1014 }
1015
1016 int sys_acl_free_text(char *text)
1017 {
1018         return acl_free(text);
1019 }
1020
1021 int sys_acl_free_acl(SMB_ACL_T acl_d) 
1022 {
1023         if (acl_d->freeaclp) {
1024                 acl_free(acl_d->aclp);
1025         }
1026         acl_free(acl_d);
1027         return 0;
1028 }
1029
1030 int sys_acl_free_qualifier(void *qual) 
1031 {
1032         return 0;
1033 }
1034
1035 #elif defined(HAVE_XFS_ACLS)
1036 /* For Linux SGI/XFS Filesystems    
1037  * contributed by J Trostel, Connex 
1038  *                                  */
1039
1040 /* based on the implementation for Solaris by Toomas Soome.. which is 
1041  * based on the implementation  by Micheal Davidson for Unixware...
1042  *
1043  * Linux XFS is a 'work-in-progress'
1044  * This interface may change...  
1045  * You've been warned ;->           */
1046
1047 /* First, do the identity mapping */
1048
1049 int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
1050 {
1051         if( acl_get_entry( the_acl, entry_id, entry_p) >= 0) {
1052                 return 1;
1053         }
1054         else {
1055                 return -1;
1056         }
1057 }
1058
1059 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
1060 {
1061         return acl_get_file( path_p, type);
1062 }
1063
1064 SMB_ACL_T sys_acl_get_fd(int fd)
1065 {
1066         return acl_get_fd(fd);
1067 }
1068
1069 char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
1070 {
1071         return acl_to_text( the_acl, plen);
1072 }
1073
1074 int sys_acl_valid( SMB_ACL_T theacl )
1075 {
1076         return acl_valid(theacl);
1077 }
1078
1079 int sys_acl_set_file( char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
1080 {
1081         return acl_set_file(name, acltype, theacl);
1082 }
1083
1084 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
1085 {
1086         return acl_set_fd(fd, theacl);
1087 }
1088
1089 /* Now the functions I need to define for XFS */
1090
1091 int sys_acl_create_entry( SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
1092 {
1093         acl_t acl, newacl;
1094         acl_entry_t ace;
1095         int cnt;
1096
1097         acl = *acl_p;
1098         ace = *entry_p;
1099
1100         if((*acl_p == NULL) || (ace == NULL)){
1101                 errno = EINVAL;
1102                 return -1;
1103         }
1104         
1105         cnt = acl->acl_cnt;     
1106         if( (cnt + 1) > ACL_MAX_ENTRIES  ){
1107                 errno = ENOSPC;
1108                 return -1;
1109         }
1110
1111         newacl = (acl_t)malloc(sizeof(struct acl));
1112         if(newacl == NULL){
1113                 errno = ENOMEM;
1114                 return -1;
1115         }
1116         
1117         *newacl = *acl;
1118         newacl->acl_entry[cnt] = *ace;
1119         newacl->acl_cnt = cnt + 1;
1120
1121         acl_free(*acl_p);
1122         *acl_p = newacl;
1123         *entry_p = &newacl->acl_entry[cnt];
1124         return 0;
1125 }
1126
1127
1128 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
1129 {
1130         *tag_type_p = entry_d->ae_tag;
1131         return 0;
1132 }
1133
1134 int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
1135 {
1136         *permset_p = &entry_d->ae_perm;
1137         return 0;
1138 }
1139
1140 void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
1141 {
1142         if (entry_d->ae_tag != SMB_ACL_USER
1143                 && entry_d->ae_tag != SMB_ACL_GROUP) {
1144                 errno = EINVAL;
1145                 return NULL;
1146         }       
1147         return &entry_d->ae_id;
1148 }
1149
1150 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
1151 {
1152         *permset = 0;
1153         return 0;
1154 }
1155
1156 int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
1157 {
1158         return (*permset & perm);
1159 }
1160
1161 int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
1162 {
1163
1164 // TO DO: Add in ALL possible permissions here
1165 // TO DO: Include extended ones!!
1166
1167         if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE && perm != SMB_ACL_EXECUTE) {
1168                 errno = EINVAL;
1169                 return -1;
1170         }
1171         
1172         if(permset == NULL) {
1173                 errno = EINVAL;
1174                 return -1;
1175         }
1176         
1177         *permset |= perm;
1178         
1179         return 0;
1180 }
1181
1182 SMB_ACL_T sys_acl_init( int count)
1183 {
1184         SMB_ACL_T a;
1185         if((count > ACL_MAX_ENTRIES) || (count < 0)) {
1186                 errno = EINVAL;
1187                 return NULL;
1188         }
1189         else {
1190                 a = (struct acl *)malloc(sizeof(struct acl)); // where is this memory freed?
1191                 a->acl_cnt = 0;
1192                 return a;
1193         }
1194 }
1195
1196 int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
1197 {
1198         
1199         switch (tag_type) {
1200                 case SMB_ACL_USER:
1201                 case SMB_ACL_USER_OBJ:
1202                 case SMB_ACL_GROUP:
1203                 case SMB_ACL_GROUP_OBJ:
1204                 case SMB_ACL_OTHER:
1205                 case SMB_ACL_MASK:
1206                         entry_d->ae_tag = tag_type;
1207                         break;
1208                 default:
1209                         errno = EINVAL;
1210                         return -1;
1211         }
1212         return 0;
1213 }
1214
1215 int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry_d, void *qual_p)
1216 {
1217         if(entry_d->ae_tag != SMB_ACL_GROUP &&
1218                 entry_d->ae_tag != SMB_ACL_USER) {
1219                 errno = EINVAL;
1220                 return -1;
1221         }
1222         
1223         entry_d->ae_id = *((uid_t *)qual_p);
1224
1225         return 0;
1226 }
1227
1228 int sys_acl_set_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
1229 {
1230 // TO DO: expand to extended permissions eventually!
1231
1232         if(*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
1233                 return EINVAL;
1234         }
1235
1236         return 0;
1237 }
1238
1239 int sys_acl_free_text(char *text)
1240 {
1241         return acl_free(text);
1242 }
1243
1244 int sys_acl_free_acl(SMB_ACL_T the_acl) 
1245 {
1246         return acl_free(the_acl);
1247 }
1248
1249 int sys_acl_free_qualifier(void *qual) 
1250 {
1251         return 0;
1252 }
1253
1254 #else /* No ACLs. */
1255
1256 int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
1257 {
1258         errno = ENOSYS;
1259         return -1;
1260 }
1261
1262 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
1263 {
1264         errno = ENOSYS;
1265         return -1;
1266 }
1267
1268 int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
1269 {
1270         errno = ENOSYS;
1271         return -1;
1272 }
1273
1274 void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
1275 {
1276         errno = ENOSYS;
1277         return NULL;
1278 }
1279
1280 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
1281 {
1282         errno = ENOSYS;
1283         return (SMB_ACL_T)NULL;
1284 }
1285
1286 SMB_ACL_T sys_acl_get_fd(int fd)
1287 {
1288         errno = ENOSYS;
1289         return (SMB_ACL_T)NULL;
1290 }
1291
1292 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
1293 {
1294         errno = ENOSYS;
1295         return -1;
1296 }
1297
1298 int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
1299 {
1300         errno = ENOSYS;
1301         return -1;
1302 }
1303
1304 int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
1305 {
1306         errno = ENOSYS;
1307         return (permset & perm) ? 1 : 0;
1308 }
1309
1310 char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
1311 {
1312         errno = ENOSYS;
1313         return NULL;
1314 }
1315
1316 int sys_acl_free_text(char *text)
1317 {
1318         errno = ENOSYS;
1319         return -1;
1320 }
1321
1322 SMB_ACL_T sys_acl_init( int count)
1323 {
1324         errno = ENOSYS;
1325         return NULL;
1326 }
1327
1328 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
1329 {
1330         errno = ENOSYS;
1331         return -1;
1332 }
1333
1334 int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
1335 {
1336         errno = ENOSYS;
1337         return -1;
1338 }
1339
1340 int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
1341 {
1342         errno = ENOSYS;
1343         return -1;
1344 }
1345
1346 int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
1347 {
1348         errno = ENOSYS;
1349         return -1;
1350 }
1351
1352 int sys_acl_valid( SMB_ACL_T theacl )
1353 {
1354         errno = ENOSYS;
1355         return -1;
1356 }
1357
1358 int sys_acl_set_file( char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
1359 {
1360         errno = ENOSYS;
1361         return -1;
1362 }
1363
1364 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
1365 {
1366         errno = ENOSYS;
1367         return -1;
1368 }
1369
1370 int sys_acl_free_acl(SMB_ACL_T the_acl) 
1371 {
1372         errno = ENOSYS;
1373         return -1;
1374 }
1375
1376 int sys_acl_free_qualifier(void *qual) 
1377 {
1378         errno = ENOSYS;
1379         return -1;
1380 }
1381
1382 #endif /* No ACLs. */