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