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