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