Initial import
[samba] / source / lib / sysacls.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba system utilities for ACL support.
4    Copyright (C) Jeremy Allison 2000.
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 #undef  DBGC_CLASS
24 #define DBGC_CLASS DBGC_ACLS
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( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
49  int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
50  int sys_acl_delete_def_file(const char *path)
51
52  This next one is not POSIX complient - but we *have* to have it !
53  More POSIX braindamage.
54
55  int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
56
57  The generic POSIX free is the following call. We split this into
58  several different free functions as we may need to add tag info
59  to structures when emulating the POSIX interface.
60
61  int sys_acl_free( void *obj_p)
62
63  The calls we actually use are :
64
65  int sys_acl_free_text(char *text) - free acl_to_text
66  int sys_acl_free_acl(SMB_ACL_T posix_acl)
67  int sys_acl_free_qualifier(void *qualifier, SMB_ACL_TAG_T tagtype)
68
69 */
70
71 #if defined(HAVE_POSIX_ACLS)
72
73 /* Identity mapping - easy. */
74
75 int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
76 {
77         return acl_get_entry( the_acl, entry_id, entry_p);
78 }
79
80 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
81 {
82         return acl_get_tag_type( entry_d, tag_type_p);
83 }
84
85 int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
86 {
87         return acl_get_permset( entry_d, permset_p);
88 }
89
90 void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
91 {
92         return acl_get_qualifier( entry_d);
93 }
94
95 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
96 {
97         return acl_get_file( path_p, type);
98 }
99
100 SMB_ACL_T sys_acl_get_fd(int fd)
101 {
102         return acl_get_fd(fd);
103 }
104
105 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
106 {
107         return acl_clear_perms(permset);
108 }
109
110 int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
111 {
112         return acl_add_perm(permset, perm);
113 }
114
115 int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
116 {
117 #if defined(HAVE_ACL_GET_PERM_NP)
118         /*
119          * Required for TrustedBSD-based ACL implementations where
120          * non-POSIX.1e functions are denoted by a _np (non-portable)
121          * suffix.
122          */
123         return acl_get_perm_np(permset, perm);
124 #else
125         return acl_get_perm(permset, perm);
126 #endif
127 }
128
129 char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
130 {
131         return acl_to_text( the_acl, plen);
132 }
133
134 SMB_ACL_T sys_acl_init( int count)
135 {
136         return acl_init(count);
137 }
138
139 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
140 {
141         return acl_create_entry(pacl, pentry);
142 }
143
144 int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
145 {
146         return acl_set_tag_type(entry, tagtype);
147 }
148
149 int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
150 {
151         return acl_set_qualifier(entry, qual);
152 }
153
154 int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
155 {
156         return acl_set_permset(entry, permset);
157 }
158
159 int sys_acl_valid( SMB_ACL_T theacl )
160 {
161         return acl_valid(theacl);
162 }
163
164 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
165 {
166         return acl_set_file(name, acltype, theacl);
167 }
168
169 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
170 {
171         return acl_set_fd(fd, theacl);
172 }
173
174 int sys_acl_delete_def_file(const char *name)
175 {
176         return acl_delete_def_file(name);
177 }
178
179 int sys_acl_free_text(char *text)
180 {
181         return acl_free(text);
182 }
183
184 int sys_acl_free_acl(SMB_ACL_T the_acl) 
185 {
186         return acl_free(the_acl);
187 }
188
189 int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
190 {
191         return acl_free(qual);
192 }
193
194 #elif defined(HAVE_TRU64_ACLS)
195 /*
196  * The interface to DEC/Compaq Tru64 UNIX ACLs
197  * is based on Draft 13 of the POSIX spec which is
198  * slightly different from the Draft 16 interface.
199  * 
200  * Also, some of the permset manipulation functions
201  * such as acl_clear_perm() and acl_add_perm() appear
202  * to be broken on Tru64 so we have to manipulate
203  * the permission bits in the permset directly.
204  */
205 int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
206 {
207         SMB_ACL_ENTRY_T entry;
208
209         if (entry_id == SMB_ACL_FIRST_ENTRY && acl_first_entry(the_acl) != 0) {
210                 return -1;
211         }
212
213         errno = 0;
214         if ((entry = acl_get_entry(the_acl)) != NULL) {
215                 *entry_p = entry;
216                 return 1;
217         }
218
219         return errno ? -1 : 0;
220 }
221
222 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
223 {
224         return acl_get_tag_type( entry_d, tag_type_p);
225 }
226
227 int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
228 {
229         return acl_get_permset( entry_d, permset_p);
230 }
231
232 void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
233 {
234         return acl_get_qualifier( entry_d);
235 }
236
237 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
238 {
239         return acl_get_file((char *)path_p, type);
240 }
241
242 SMB_ACL_T sys_acl_get_fd(int fd)
243 {
244         return acl_get_fd(fd, ACL_TYPE_ACCESS);
245 }
246
247 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
248 {
249         *permset = 0;           /* acl_clear_perm() is broken on Tru64  */
250
251         return 0;
252 }
253
254 int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
255 {
256         if (perm & ~(SMB_ACL_READ | SMB_ACL_WRITE | SMB_ACL_EXECUTE)) {
257                 errno = EINVAL;
258                 return -1;
259         }
260
261         *permset |= perm;       /* acl_add_perm() is broken on Tru64    */
262
263         return 0;
264 }
265
266 int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
267 {
268         return *permset & perm; /* Tru64 doesn't have acl_get_perm() */
269 }
270
271 char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
272 {
273         return acl_to_text( the_acl, plen);
274 }
275
276 SMB_ACL_T sys_acl_init( int count)
277 {
278         return acl_init(count);
279 }
280
281 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
282 {
283         SMB_ACL_ENTRY_T entry;
284
285         if ((entry = acl_create_entry(pacl)) == NULL) {
286                 return -1;
287         }
288
289         *pentry = entry;
290         return 0;
291 }
292
293 int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
294 {
295         return acl_set_tag_type(entry, tagtype);
296 }
297
298 int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
299 {
300         return acl_set_qualifier(entry, qual);
301 }
302
303 int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
304 {
305         return acl_set_permset(entry, permset);
306 }
307
308 int sys_acl_valid( SMB_ACL_T theacl )
309 {
310         acl_entry_t     entry;
311
312         return acl_valid(theacl, &entry);
313 }
314
315 int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
316 {
317         return acl_set_file((char *)name, acltype, theacl);
318 }
319
320 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
321 {
322         return acl_set_fd(fd, ACL_TYPE_ACCESS, theacl);
323 }
324
325 int sys_acl_delete_def_file(const char *name)
326 {
327         return acl_delete_def_file((char *)name);
328 }
329
330 int sys_acl_free_text(char *text)
331 {
332         /*
333          * (void) cast and explicit return 0 are for DEC UNIX
334          *  which just #defines acl_free_text() to be free()
335          */
336         (void) acl_free_text(text);
337         return 0;
338 }
339
340 int sys_acl_free_acl(SMB_ACL_T the_acl) 
341 {
342         return acl_free(the_acl);
343 }
344
345 int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
346 {
347         return acl_free_qualifier(qual, tagtype);
348 }
349
350 #elif defined(HAVE_UNIXWARE_ACLS) || defined(HAVE_SOLARIS_ACLS)
351
352 /*
353  * Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX.
354  * Modified by Toomas Soome <tsoome@ut.ee> for Solaris.
355  */
356
357 /*
358  * Note that while this code implements sufficient functionality
359  * to support the sys_acl_* interfaces it does not provide all
360  * of the semantics of the POSIX ACL interfaces.
361  *
362  * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
363  * from a call to sys_acl_get_entry() should not be assumed to be
364  * valid after calling any of the following functions, which may
365  * reorder the entries in the ACL.
366  *
367  *      sys_acl_valid()
368  *      sys_acl_set_file()
369  *      sys_acl_set_fd()
370  */
371
372 /*
373  * The only difference between Solaris and UnixWare / OpenUNIX is
374  * that the #defines for the ACL operations have different names
375  */
376 #if defined(HAVE_UNIXWARE_ACLS)
377
378 #define SETACL          ACL_SET
379 #define GETACL          ACL_GET
380 #define GETACLCNT       ACL_CNT
381
382 #endif
383
384
385 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
386 {
387         if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
388                 errno = EINVAL;
389                 return -1;
390         }
391
392         if (entry_p == NULL) {
393                 errno = EINVAL;
394                 return -1;
395         }
396
397         if (entry_id == SMB_ACL_FIRST_ENTRY) {
398                 acl_d->next = 0;
399         }
400
401         if (acl_d->next < 0) {
402                 errno = EINVAL;
403                 return -1;
404         }
405
406         if (acl_d->next >= acl_d->count) {
407                 return 0;
408         }
409
410         *entry_p = &acl_d->acl[acl_d->next++];
411
412         return 1;
413 }
414
415 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
416 {
417         *type_p = entry_d->a_type;
418
419         return 0;
420 }
421
422 int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
423 {
424         *permset_p = &entry_d->a_perm;
425
426         return 0;
427 }
428
429 void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
430 {
431         if (entry_d->a_type != SMB_ACL_USER
432             && entry_d->a_type != SMB_ACL_GROUP) {
433                 errno = EINVAL;
434                 return NULL;
435         }
436
437         return &entry_d->a_id;
438 }
439
440 /*
441  * There is no way of knowing what size the ACL returned by
442  * GETACL will be unless you first call GETACLCNT which means
443  * making an additional system call.
444  *
445  * In the hope of avoiding the cost of the additional system
446  * call in most cases, we initially allocate enough space for
447  * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
448  * be too small then we use GETACLCNT to find out the actual
449  * size, reallocate the ACL buffer, and then call GETACL again.
450  */
451
452 #define INITIAL_ACL_SIZE        16
453
454 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
455 {
456         SMB_ACL_T       acl_d;
457         int             count;          /* # of ACL entries allocated   */
458         int             naccess;        /* # of access ACL entries      */
459         int             ndefault;       /* # of default ACL entries     */
460
461         if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
462                 errno = EINVAL;
463                 return NULL;
464         }
465
466         count = INITIAL_ACL_SIZE;
467         if ((acl_d = sys_acl_init(count)) == NULL) {
468                 return NULL;
469         }
470
471         /*
472          * If there isn't enough space for the ACL entries we use
473          * GETACLCNT to determine the actual number of ACL entries
474          * reallocate and try again. This is in a loop because it
475          * is possible that someone else could modify the ACL and
476          * increase the number of entries between the call to
477          * GETACLCNT and the call to GETACL.
478          */
479         while ((count = acl(path_p, GETACL, count, &acl_d->acl[0])) < 0
480             && errno == ENOSPC) {
481
482                 sys_acl_free_acl(acl_d);
483
484                 if ((count = acl(path_p, GETACLCNT, 0, NULL)) < 0) {
485                         return NULL;
486                 }
487
488                 if ((acl_d = sys_acl_init(count)) == NULL) {
489                         return NULL;
490                 }
491         }
492
493         if (count < 0) {
494                 sys_acl_free_acl(acl_d);
495                 return NULL;
496         }
497
498         /*
499          * calculate the number of access and default ACL entries
500          *
501          * Note: we assume that the acl() system call returned a
502          * well formed ACL which is sorted so that all of the
503          * access ACL entries preceed any default ACL entries
504          */
505         for (naccess = 0; naccess < count; naccess++) {
506                 if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
507                         break;
508         }
509         ndefault = count - naccess;
510         
511         /*
512          * if the caller wants the default ACL we have to copy
513          * the entries down to the start of the acl[] buffer
514          * and mask out the ACL_DEFAULT flag from the type field
515          */
516         if (type == SMB_ACL_TYPE_DEFAULT) {
517                 int     i, j;
518
519                 for (i = 0, j = naccess; i < ndefault; i++, j++) {
520                         acl_d->acl[i] = acl_d->acl[j];
521                         acl_d->acl[i].a_type &= ~ACL_DEFAULT;
522                 }
523
524                 acl_d->count = ndefault;
525         } else {
526                 acl_d->count = naccess;
527         }
528
529         return acl_d;
530 }
531
532 SMB_ACL_T sys_acl_get_fd(int fd)
533 {
534         SMB_ACL_T       acl_d;
535         int             count;          /* # of ACL entries allocated   */
536         int             naccess;        /* # of access ACL entries      */
537
538         count = INITIAL_ACL_SIZE;
539         if ((acl_d = sys_acl_init(count)) == NULL) {
540                 return NULL;
541         }
542
543         while ((count = facl(fd, GETACL, count, &acl_d->acl[0])) < 0
544             && errno == ENOSPC) {
545
546                 sys_acl_free_acl(acl_d);
547
548                 if ((count = facl(fd, GETACLCNT, 0, NULL)) < 0) {
549                         return NULL;
550                 }
551
552                 if ((acl_d = sys_acl_init(count)) == NULL) {
553                         return NULL;
554                 }
555         }
556
557         if (count < 0) {
558                 sys_acl_free_acl(acl_d);
559                 return NULL;
560         }
561
562         /*
563          * calculate the number of access ACL entries
564          */
565         for (naccess = 0; naccess < count; naccess++) {
566                 if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
567                         break;
568         }
569         
570         acl_d->count = naccess;
571
572         return acl_d;
573 }
574
575 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
576 {
577         *permset_d = 0;
578
579         return 0;
580 }
581
582 int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
583 {
584         if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
585             && perm != SMB_ACL_EXECUTE) {
586                 errno = EINVAL;
587                 return -1;
588         }
589
590         if (permset_d == NULL) {
591                 errno = EINVAL;
592                 return -1;
593         }
594
595         *permset_d |= perm;
596
597         return 0;
598 }
599
600 int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
601 {
602         return *permset_d & perm;
603 }
604
605 char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
606 {
607         int     i;
608         int     len, maxlen;
609         char    *text;
610
611         /*
612          * use an initial estimate of 20 bytes per ACL entry
613          * when allocating memory for the text representation
614          * of the ACL
615          */
616         len     = 0;
617         maxlen  = 20 * acl_d->count;
618         if ((text = SMB_MALLOC(maxlen)) == NULL) {
619                 errno = ENOMEM;
620                 return NULL;
621         }
622
623         for (i = 0; i < acl_d->count; i++) {
624                 struct acl      *ap     = &acl_d->acl[i];
625                 struct passwd   *pw;
626                 struct group    *gr;
627                 char            tagbuf[12];
628                 char            idbuf[12];
629                 char            *tag;
630                 char            *id     = "";
631                 char            perms[4];
632                 int             nbytes;
633
634                 switch (ap->a_type) {
635                         /*
636                          * for debugging purposes it's probably more
637                          * useful to dump unknown tag types rather
638                          * than just returning an error
639                          */
640                         default:
641                                 slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
642                                         ap->a_type);
643                                 tag = tagbuf;
644                                 slprintf(idbuf, sizeof(idbuf)-1, "%ld",
645                                         (long)ap->a_id);
646                                 id = idbuf;
647                                 break;
648
649                         case SMB_ACL_USER:
650                                 id = uidtoname(ap->a_id);
651                         case SMB_ACL_USER_OBJ:
652                                 tag = "user";
653                                 break;
654
655                         case SMB_ACL_GROUP:
656                                 if ((gr = getgrgid(ap->a_id)) == NULL) {
657                                         slprintf(idbuf, sizeof(idbuf)-1, "%ld",
658                                                 (long)ap->a_id);
659                                         id = idbuf;
660                                 } else {
661                                         id = gr->gr_name;
662                                 }
663                         case SMB_ACL_GROUP_OBJ:
664                                 tag = "group";
665                                 break;
666
667                         case SMB_ACL_OTHER:
668                                 tag = "other";
669                                 break;
670
671                         case SMB_ACL_MASK:
672                                 tag = "mask";
673                                 break;
674
675                 }
676
677                 perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
678                 perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
679                 perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
680                 perms[3] = '\0';
681
682                 /*          <tag>      :  <qualifier>   :  rwx \n  \0 */
683                 nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
684
685                 /*
686                  * If this entry would overflow the buffer
687                  * allocate enough additional memory for this
688                  * entry and an estimate of another 20 bytes
689                  * for each entry still to be processed
690                  */
691                 if ((len + nbytes) > maxlen) {
692                         char *oldtext = text;
693
694                         maxlen += nbytes + 20 * (acl_d->count - i);
695
696                         if ((text = SMB_REALLOC(oldtext, maxlen)) == NULL) {
697                                 SAFE_FREE(oldtext);
698                                 errno = ENOMEM;
699                                 return NULL;
700                         }
701                 }
702
703                 slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
704                 len += nbytes - 1;
705         }
706
707         if (len_p)
708                 *len_p = len;
709
710         return text;
711 }
712
713 SMB_ACL_T sys_acl_init(int count)
714 {
715         SMB_ACL_T       a;
716
717         if (count < 0) {
718                 errno = EINVAL;
719                 return NULL;
720         }
721
722         /*
723          * note that since the definition of the structure pointed
724          * to by the SMB_ACL_T includes the first element of the
725          * acl[] array, this actually allocates an ACL with room
726          * for (count+1) entries
727          */
728         if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + count * sizeof(struct acl))) == NULL) {
729                 errno = ENOMEM;
730                 return NULL;
731         }
732
733         a->size = count + 1;
734         a->count = 0;
735         a->next = -1;
736
737         return a;
738 }
739
740
741 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
742 {
743         SMB_ACL_T       acl_d;
744         SMB_ACL_ENTRY_T entry_d;
745
746         if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
747                 errno = EINVAL;
748                 return -1;
749         }
750
751         if (acl_d->count >= acl_d->size) {
752                 errno = ENOSPC;
753                 return -1;
754         }
755
756         entry_d         = &acl_d->acl[acl_d->count++];
757         entry_d->a_type = 0;
758         entry_d->a_id   = -1;
759         entry_d->a_perm = 0;
760         *entry_p        = entry_d;
761
762         return 0;
763 }
764
765 int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
766 {
767         switch (tag_type) {
768                 case SMB_ACL_USER:
769                 case SMB_ACL_USER_OBJ:
770                 case SMB_ACL_GROUP:
771                 case SMB_ACL_GROUP_OBJ:
772                 case SMB_ACL_OTHER:
773                 case SMB_ACL_MASK:
774                         entry_d->a_type = tag_type;
775                         break;
776                 default:
777                         errno = EINVAL;
778                         return -1;
779         }
780
781         return 0;
782 }
783
784 int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
785 {
786         if (entry_d->a_type != SMB_ACL_GROUP
787             && entry_d->a_type != SMB_ACL_USER) {
788                 errno = EINVAL;
789                 return -1;
790         }
791
792         entry_d->a_id = *((id_t *)qual_p);
793
794         return 0;
795 }
796
797 int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
798 {
799         if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
800                 return EINVAL;
801         }
802
803         entry_d->a_perm = *permset_d;
804
805         return 0;
806 }
807
808 /*
809  * sort the ACL and check it for validity
810  *
811  * if it's a minimal ACL with only 4 entries then we
812  * need to recalculate the mask permissions to make
813  * sure that they are the same as the GROUP_OBJ
814  * permissions as required by the UnixWare acl() system call.
815  *
816  * (note: since POSIX allows minimal ACLs which only contain
817  * 3 entries - ie there is no mask entry - we should, in theory,
818  * check for this and add a mask entry if necessary - however
819  * we "know" that the caller of this interface always specifies
820  * a mask so, in practice "this never happens" (tm) - if it *does*
821  * happen aclsort() will fail and return an error and someone will
822  * have to fix it ...)
823  */
824
825 static int acl_sort(SMB_ACL_T acl_d)
826 {
827         int     fixmask = (acl_d->count <= 4);
828
829         if (aclsort(acl_d->count, fixmask, acl_d->acl) != 0) {
830                 errno = EINVAL;
831                 return -1;
832         }
833         return 0;
834 }
835  
836 int sys_acl_valid(SMB_ACL_T acl_d)
837 {
838         return acl_sort(acl_d);
839 }
840
841 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
842 {
843         struct stat     s;
844         struct acl      *acl_p;
845         int             acl_count;
846         struct acl      *acl_buf        = NULL;
847         int             ret;
848
849         if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
850                 errno = EINVAL;
851                 return -1;
852         }
853
854         if (acl_sort(acl_d) != 0) {
855                 return -1;
856         }
857
858         acl_p           = &acl_d->acl[0];
859         acl_count       = acl_d->count;
860
861         /*
862          * if it's a directory there is extra work to do
863          * since the acl() system call will replace both
864          * the access ACLs and the default ACLs (if any)
865          */
866         if (stat(name, &s) != 0) {
867                 return -1;
868         }
869         if (S_ISDIR(s.st_mode)) {
870                 SMB_ACL_T       acc_acl;
871                 SMB_ACL_T       def_acl;
872                 SMB_ACL_T       tmp_acl;
873                 int             i;
874
875                 if (type == SMB_ACL_TYPE_ACCESS) {
876                         acc_acl = acl_d;
877                         def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
878
879                 } else {
880                         def_acl = acl_d;
881                         acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
882                 }
883
884                 if (tmp_acl == NULL) {
885                         return -1;
886                 }
887
888                 /*
889                  * allocate a temporary buffer for the complete ACL
890                  */
891                 acl_count = acc_acl->count + def_acl->count;
892                 acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count);
893
894                 if (acl_buf == NULL) {
895                         sys_acl_free_acl(tmp_acl);
896                         errno = ENOMEM;
897                         return -1;
898                 }
899
900                 /*
901                  * copy the access control and default entries into the buffer
902                  */
903                 memcpy(&acl_buf[0], &acc_acl->acl[0],
904                         acc_acl->count * sizeof(acl_buf[0]));
905
906                 memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
907                         def_acl->count * sizeof(acl_buf[0]));
908
909                 /*
910                  * set the ACL_DEFAULT flag on the default entries
911                  */
912                 for (i = acc_acl->count; i < acl_count; i++) {
913                         acl_buf[i].a_type |= ACL_DEFAULT;
914                 }
915
916                 sys_acl_free_acl(tmp_acl);
917
918         } else if (type != SMB_ACL_TYPE_ACCESS) {
919                 errno = EINVAL;
920                 return -1;
921         }
922
923         ret = acl(name, SETACL, acl_count, acl_p);
924
925         SAFE_FREE(acl_buf);
926
927         return ret;
928 }
929
930 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
931 {
932         if (acl_sort(acl_d) != 0) {
933                 return -1;
934         }
935
936         return facl(fd, SETACL, acl_d->count, &acl_d->acl[0]);
937 }
938
939 int sys_acl_delete_def_file(const char *path)
940 {
941         SMB_ACL_T       acl_d;
942         int             ret;
943
944         /*
945          * fetching the access ACL and rewriting it has
946          * the effect of deleting the default ACL
947          */
948         if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
949                 return -1;
950         }
951
952         ret = acl(path, SETACL, acl_d->count, acl_d->acl);
953
954         sys_acl_free_acl(acl_d);
955         
956         return ret;
957 }
958
959 int sys_acl_free_text(char *text)
960 {
961         SAFE_FREE(text);
962         return 0;
963 }
964
965 int sys_acl_free_acl(SMB_ACL_T acl_d) 
966 {
967         SAFE_FREE(acl_d);
968         return 0;
969 }
970
971 int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
972 {
973         return 0;
974 }
975
976 #elif defined(HAVE_HPUX_ACLS)
977 #include <dl.h>
978
979 /*
980  * Based on the Solaris/SCO code - with modifications.
981  */
982
983 /*
984  * Note that while this code implements sufficient functionality
985  * to support the sys_acl_* interfaces it does not provide all
986  * of the semantics of the POSIX ACL interfaces.
987  *
988  * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
989  * from a call to sys_acl_get_entry() should not be assumed to be
990  * valid after calling any of the following functions, which may
991  * reorder the entries in the ACL.
992  *
993  *      sys_acl_valid()
994  *      sys_acl_set_file()
995  *      sys_acl_set_fd()
996  */
997
998 /* This checks if the POSIX ACL system call is defined */
999 /* which basically corresponds to whether JFS 3.3 or   */
1000 /* higher is installed. If acl() was called when it    */
1001 /* isn't defined, it causes the process to core dump   */
1002 /* so it is important to check this and avoid acl()    */
1003 /* calls if it isn't there.                            */
1004
1005 static BOOL hpux_acl_call_presence(void)
1006 {
1007
1008         shl_t handle = NULL;
1009         void *value;
1010         int ret_val=0;
1011         static BOOL already_checked=0;
1012
1013         if(already_checked)
1014                 return True;
1015
1016
1017         ret_val = shl_findsym(&handle, "acl", TYPE_PROCEDURE, &value);
1018
1019         if(ret_val != 0) {
1020                 DEBUG(5, ("hpux_acl_call_presence: shl_findsym() returned %d, errno = %d, error %s\n",
1021                         ret_val, errno, strerror(errno)));
1022                 DEBUG(5,("hpux_acl_call_presence: acl() system call is not present. Check if you have JFS 3.3 and above?\n"));
1023                 return False;
1024         }
1025
1026         DEBUG(10,("hpux_acl_call_presence: acl() system call is present. We have JFS 3.3 or above \n"));
1027
1028         already_checked = True;
1029         return True;
1030 }
1031
1032 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
1033 {
1034         if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
1035                 errno = EINVAL;
1036                 return -1;
1037         }
1038
1039         if (entry_p == NULL) {
1040                 errno = EINVAL;
1041                 return -1;
1042         }
1043
1044         if (entry_id == SMB_ACL_FIRST_ENTRY) {
1045                 acl_d->next = 0;
1046         }
1047
1048         if (acl_d->next < 0) {
1049                 errno = EINVAL;
1050                 return -1;
1051         }
1052
1053         if (acl_d->next >= acl_d->count) {
1054                 return 0;
1055         }
1056
1057         *entry_p = &acl_d->acl[acl_d->next++];
1058
1059         return 1;
1060 }
1061
1062 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
1063 {
1064         *type_p = entry_d->a_type;
1065
1066         return 0;
1067 }
1068
1069 int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
1070 {
1071         *permset_p = &entry_d->a_perm;
1072
1073         return 0;
1074 }
1075
1076 void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
1077 {
1078         if (entry_d->a_type != SMB_ACL_USER
1079             && entry_d->a_type != SMB_ACL_GROUP) {
1080                 errno = EINVAL;
1081                 return NULL;
1082         }
1083
1084         return &entry_d->a_id;
1085 }
1086
1087 /*
1088  * There is no way of knowing what size the ACL returned by
1089  * ACL_GET will be unless you first call ACL_CNT which means
1090  * making an additional system call.
1091  *
1092  * In the hope of avoiding the cost of the additional system
1093  * call in most cases, we initially allocate enough space for
1094  * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
1095  * be too small then we use ACL_CNT to find out the actual
1096  * size, reallocate the ACL buffer, and then call ACL_GET again.
1097  */
1098
1099 #define INITIAL_ACL_SIZE        16
1100
1101 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
1102 {
1103         SMB_ACL_T       acl_d;
1104         int             count;          /* # of ACL entries allocated   */
1105         int             naccess;        /* # of access ACL entries      */
1106         int             ndefault;       /* # of default ACL entries     */
1107
1108         if(hpux_acl_call_presence() == False) {
1109                 /* Looks like we don't have the acl() system call on HPUX. 
1110                  * May be the system doesn't have the latest version of JFS.
1111                  */
1112                 return NULL; 
1113         }
1114
1115         if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
1116                 errno = EINVAL;
1117                 return NULL;
1118         }
1119
1120         count = INITIAL_ACL_SIZE;
1121         if ((acl_d = sys_acl_init(count)) == NULL) {
1122                 return NULL;
1123         }
1124
1125         /*
1126          * If there isn't enough space for the ACL entries we use
1127          * ACL_CNT to determine the actual number of ACL entries
1128          * reallocate and try again. This is in a loop because it
1129          * is possible that someone else could modify the ACL and
1130          * increase the number of entries between the call to
1131          * ACL_CNT and the call to ACL_GET.
1132          */
1133         while ((count = acl(path_p, ACL_GET, count, &acl_d->acl[0])) < 0 && errno == ENOSPC) {
1134
1135                 sys_acl_free_acl(acl_d);
1136
1137                 if ((count = acl(path_p, ACL_CNT, 0, NULL)) < 0) {
1138                         return NULL;
1139                 }
1140
1141                 if ((acl_d = sys_acl_init(count)) == NULL) {
1142                         return NULL;
1143                 }
1144         }
1145
1146         if (count < 0) {
1147                 sys_acl_free_acl(acl_d);
1148                 return NULL;
1149         }
1150
1151         /*
1152          * calculate the number of access and default ACL entries
1153          *
1154          * Note: we assume that the acl() system call returned a
1155          * well formed ACL which is sorted so that all of the
1156          * access ACL entries preceed any default ACL entries
1157          */
1158         for (naccess = 0; naccess < count; naccess++) {
1159                 if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
1160                         break;
1161         }
1162         ndefault = count - naccess;
1163         
1164         /*
1165          * if the caller wants the default ACL we have to copy
1166          * the entries down to the start of the acl[] buffer
1167          * and mask out the ACL_DEFAULT flag from the type field
1168          */
1169         if (type == SMB_ACL_TYPE_DEFAULT) {
1170                 int     i, j;
1171
1172                 for (i = 0, j = naccess; i < ndefault; i++, j++) {
1173                         acl_d->acl[i] = acl_d->acl[j];
1174                         acl_d->acl[i].a_type &= ~ACL_DEFAULT;
1175                 }
1176
1177                 acl_d->count = ndefault;
1178         } else {
1179                 acl_d->count = naccess;
1180         }
1181
1182         return acl_d;
1183 }
1184
1185 SMB_ACL_T sys_acl_get_fd(int fd)
1186 {
1187         /*
1188          * HPUX doesn't have the facl call. Fake it using the path.... JRA.
1189          */
1190
1191         files_struct *fsp = file_find_fd(fd);
1192
1193         if (fsp == NULL) {
1194                 errno = EBADF;
1195                 return NULL;
1196         }
1197
1198         /*
1199          * We know we're in the same conn context. So we
1200          * can use the relative path.
1201          */
1202
1203         return sys_acl_get_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
1204 }
1205
1206 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
1207 {
1208         *permset_d = 0;
1209
1210         return 0;
1211 }
1212
1213 int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
1214 {
1215         if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
1216             && perm != SMB_ACL_EXECUTE) {
1217                 errno = EINVAL;
1218                 return -1;
1219         }
1220
1221         if (permset_d == NULL) {
1222                 errno = EINVAL;
1223                 return -1;
1224         }
1225
1226         *permset_d |= perm;
1227
1228         return 0;
1229 }
1230
1231 int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
1232 {
1233         return *permset_d & perm;
1234 }
1235
1236 char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
1237 {
1238         int     i;
1239         int     len, maxlen;
1240         char    *text;
1241
1242         /*
1243          * use an initial estimate of 20 bytes per ACL entry
1244          * when allocating memory for the text representation
1245          * of the ACL
1246          */
1247         len     = 0;
1248         maxlen  = 20 * acl_d->count;
1249         if ((text = SMB_MALLOC(maxlen)) == NULL) {
1250                 errno = ENOMEM;
1251                 return NULL;
1252         }
1253
1254         for (i = 0; i < acl_d->count; i++) {
1255                 struct acl      *ap     = &acl_d->acl[i];
1256                 struct passwd   *pw;
1257                 struct group    *gr;
1258                 char            tagbuf[12];
1259                 char            idbuf[12];
1260                 char            *tag;
1261                 char            *id     = "";
1262                 char            perms[4];
1263                 int             nbytes;
1264
1265                 switch (ap->a_type) {
1266                         /*
1267                          * for debugging purposes it's probably more
1268                          * useful to dump unknown tag types rather
1269                          * than just returning an error
1270                          */
1271                         default:
1272                                 slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
1273                                         ap->a_type);
1274                                 tag = tagbuf;
1275                                 slprintf(idbuf, sizeof(idbuf)-1, "%ld",
1276                                         (long)ap->a_id);
1277                                 id = idbuf;
1278                                 break;
1279
1280                         case SMB_ACL_USER:
1281                                 id = uidtoname(ap->a_id);
1282                         case SMB_ACL_USER_OBJ:
1283                                 tag = "user";
1284                                 break;
1285
1286                         case SMB_ACL_GROUP:
1287                                 if ((gr = getgrgid(ap->a_id)) == NULL) {
1288                                         slprintf(idbuf, sizeof(idbuf)-1, "%ld",
1289                                                 (long)ap->a_id);
1290                                         id = idbuf;
1291                                 } else {
1292                                         id = gr->gr_name;
1293                                 }
1294                         case SMB_ACL_GROUP_OBJ:
1295                                 tag = "group";
1296                                 break;
1297
1298                         case SMB_ACL_OTHER:
1299                                 tag = "other";
1300                                 break;
1301
1302                         case SMB_ACL_MASK:
1303                                 tag = "mask";
1304                                 break;
1305
1306                 }
1307
1308                 perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
1309                 perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
1310                 perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
1311                 perms[3] = '\0';
1312
1313                 /*          <tag>      :  <qualifier>   :  rwx \n  \0 */
1314                 nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
1315
1316                 /*
1317                  * If this entry would overflow the buffer
1318                  * allocate enough additional memory for this
1319                  * entry and an estimate of another 20 bytes
1320                  * for each entry still to be processed
1321                  */
1322                 if ((len + nbytes) > maxlen) {
1323                         char *oldtext = text;
1324
1325                         maxlen += nbytes + 20 * (acl_d->count - i);
1326
1327                         if ((text = SMB_REALLOC(oldtext, maxlen)) == NULL) {
1328                                 free(oldtext);
1329                                 errno = ENOMEM;
1330                                 return NULL;
1331                         }
1332                 }
1333
1334                 slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
1335                 len += nbytes - 1;
1336         }
1337
1338         if (len_p)
1339                 *len_p = len;
1340
1341         return text;
1342 }
1343
1344 SMB_ACL_T sys_acl_init(int count)
1345 {
1346         SMB_ACL_T       a;
1347
1348         if (count < 0) {
1349                 errno = EINVAL;
1350                 return NULL;
1351         }
1352
1353         /*
1354          * note that since the definition of the structure pointed
1355          * to by the SMB_ACL_T includes the first element of the
1356          * acl[] array, this actually allocates an ACL with room
1357          * for (count+1) entries
1358          */
1359         if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + count * sizeof(struct acl))) == NULL) {
1360                 errno = ENOMEM;
1361                 return NULL;
1362         }
1363
1364         a->size = count + 1;
1365         a->count = 0;
1366         a->next = -1;
1367
1368         return a;
1369 }
1370
1371
1372 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
1373 {
1374         SMB_ACL_T       acl_d;
1375         SMB_ACL_ENTRY_T entry_d;
1376
1377         if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
1378                 errno = EINVAL;
1379                 return -1;
1380         }
1381
1382         if (acl_d->count >= acl_d->size) {
1383                 errno = ENOSPC;
1384                 return -1;
1385         }
1386
1387         entry_d         = &acl_d->acl[acl_d->count++];
1388         entry_d->a_type = 0;
1389         entry_d->a_id   = -1;
1390         entry_d->a_perm = 0;
1391         *entry_p        = entry_d;
1392
1393         return 0;
1394 }
1395
1396 int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
1397 {
1398         switch (tag_type) {
1399                 case SMB_ACL_USER:
1400                 case SMB_ACL_USER_OBJ:
1401                 case SMB_ACL_GROUP:
1402                 case SMB_ACL_GROUP_OBJ:
1403                 case SMB_ACL_OTHER:
1404                 case SMB_ACL_MASK:
1405                         entry_d->a_type = tag_type;
1406                         break;
1407                 default:
1408                         errno = EINVAL;
1409                         return -1;
1410         }
1411
1412         return 0;
1413 }
1414
1415 int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
1416 {
1417         if (entry_d->a_type != SMB_ACL_GROUP
1418             && entry_d->a_type != SMB_ACL_USER) {
1419                 errno = EINVAL;
1420                 return -1;
1421         }
1422
1423         entry_d->a_id = *((id_t *)qual_p);
1424
1425         return 0;
1426 }
1427
1428 int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
1429 {
1430         if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
1431                 return EINVAL;
1432         }
1433
1434         entry_d->a_perm = *permset_d;
1435
1436         return 0;
1437 }
1438
1439 /* Structure to capture the count for each type of ACE. */
1440
1441 struct hpux_acl_types {
1442         int n_user;
1443         int n_def_user;
1444         int n_user_obj;
1445         int n_def_user_obj;
1446
1447         int n_group;
1448         int n_def_group;
1449         int n_group_obj;
1450         int n_def_group_obj;
1451
1452         int n_other;
1453         int n_other_obj;
1454         int n_def_other_obj;
1455
1456         int n_class_obj;
1457         int n_def_class_obj;
1458
1459         int n_illegal_obj;
1460 };
1461
1462 /* count_obj:
1463  * Counts the different number of objects in a given array of ACL
1464  * structures.
1465  * Inputs:
1466  *
1467  * acl_count      - Count of ACLs in the array of ACL strucutres.
1468  * aclp           - Array of ACL structures.
1469  * acl_type_count - Pointer to acl_types structure. Should already be
1470  *                  allocated.
1471  * Output: 
1472  *
1473  * acl_type_count - This structure is filled up with counts of various 
1474  *                  acl types.
1475  */
1476
1477 static int hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_types *acl_type_count)
1478 {
1479         int i;
1480
1481         memset(acl_type_count, 0, sizeof(struct hpux_acl_types));
1482
1483         for(i=0;i<acl_count;i++) {
1484                 switch(aclp[i].a_type) {
1485                 case USER: 
1486                         acl_type_count->n_user++;
1487                         break;
1488                 case USER_OBJ: 
1489                         acl_type_count->n_user_obj++;
1490                         break;
1491                 case DEF_USER_OBJ: 
1492                         acl_type_count->n_def_user_obj++;
1493                         break;
1494                 case GROUP: 
1495                         acl_type_count->n_group++;
1496                         break;
1497                 case GROUP_OBJ: 
1498                         acl_type_count->n_group_obj++;
1499                         break;
1500                 case DEF_GROUP_OBJ: 
1501                         acl_type_count->n_def_group_obj++;
1502                         break;
1503                 case OTHER_OBJ: 
1504                         acl_type_count->n_other_obj++;
1505                         break;
1506                 case DEF_OTHER_OBJ: 
1507                         acl_type_count->n_def_other_obj++;
1508                         break;
1509                 case CLASS_OBJ:
1510                         acl_type_count->n_class_obj++;
1511                         break;
1512                 case DEF_CLASS_OBJ:
1513                         acl_type_count->n_def_class_obj++;
1514                         break;
1515                 case DEF_USER:
1516                         acl_type_count->n_def_user++;
1517                         break;
1518                 case DEF_GROUP:
1519                         acl_type_count->n_def_group++;
1520                         break;
1521                 default: 
1522                         acl_type_count->n_illegal_obj++;
1523                         break;
1524                 }
1525         }
1526 }
1527
1528 /* swap_acl_entries:  Swaps two ACL entries. 
1529  *
1530  * Inputs: aclp0, aclp1 - ACL entries to be swapped.
1531  */
1532
1533 static void hpux_swap_acl_entries(struct acl *aclp0, struct acl *aclp1)
1534 {
1535         struct acl temp_acl;
1536
1537         temp_acl.a_type = aclp0->a_type;
1538         temp_acl.a_id = aclp0->a_id;
1539         temp_acl.a_perm = aclp0->a_perm;
1540
1541         aclp0->a_type = aclp1->a_type;
1542         aclp0->a_id = aclp1->a_id;
1543         aclp0->a_perm = aclp1->a_perm;
1544
1545         aclp1->a_type = temp_acl.a_type;
1546         aclp1->a_id = temp_acl.a_id;
1547         aclp1->a_perm = temp_acl.a_perm;
1548 }
1549
1550 /* prohibited_duplicate_type
1551  * Identifies if given ACL type can have duplicate entries or 
1552  * not.
1553  *
1554  * Inputs: acl_type - ACL Type.
1555  *
1556  * Outputs: 
1557  *
1558  * Return.. 
1559  *
1560  * True - If the ACL type matches any of the prohibited types.
1561  * False - If the ACL type doesn't match any of the prohibited types.
1562  */ 
1563
1564 static BOOL hpux_prohibited_duplicate_type(int acl_type)
1565 {
1566         switch(acl_type) {
1567                 case USER:
1568                 case GROUP:
1569                 case DEF_USER: 
1570                 case DEF_GROUP:
1571                         return True;
1572                 default:
1573                         return False;
1574         }
1575 }
1576
1577 /* get_needed_class_perm
1578  * Returns the permissions of a ACL structure only if the ACL
1579  * type matches one of the pre-determined types for computing 
1580  * CLASS_OBJ permissions.
1581  *
1582  * Inputs: aclp - Pointer to ACL structure.
1583  */
1584
1585 static int hpux_get_needed_class_perm(struct acl *aclp)
1586 {
1587         switch(aclp->a_type) {
1588                 case USER: 
1589                 case GROUP_OBJ: 
1590                 case GROUP: 
1591                 case DEF_USER_OBJ: 
1592                 case DEF_USER:
1593                 case DEF_GROUP_OBJ: 
1594                 case DEF_GROUP:
1595                 case DEF_CLASS_OBJ:
1596                 case DEF_OTHER_OBJ: 
1597                         return aclp->a_perm;
1598                 default: 
1599                         return 0;
1600         }
1601 }
1602
1603 /* acl_sort for HPUX.
1604  * Sorts the array of ACL structures as per the description in
1605  * aclsort man page. Refer to aclsort man page for more details
1606  *
1607  * Inputs:
1608  *
1609  * acl_count - Count of ACLs in the array of ACL structures.
1610  * calclass  - If this is not zero, then we compute the CLASS_OBJ
1611  *             permissions.
1612  * aclp      - Array of ACL structures.
1613  *
1614  * Outputs:
1615  *
1616  * aclp     - Sorted array of ACL structures.
1617  *
1618  * Outputs:
1619  *
1620  * Returns 0 for success -1 for failure. Prints a message to the Samba
1621  * debug log in case of failure.
1622  */
1623
1624 static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
1625 {
1626 #if !defined(HAVE_HPUX_ACLSORT)
1627         /*
1628          * The aclsort() system call is availabe on the latest HPUX General
1629          * Patch Bundles. So for HPUX, we developed our version of acl_sort 
1630          * function. Because, we don't want to update to a new 
1631          * HPUX GR bundle just for aclsort() call.
1632          */
1633
1634         struct hpux_acl_types acl_obj_count;
1635         int n_class_obj_perm = 0;
1636         int i, j;
1637  
1638         if(!acl_count) {
1639                 DEBUG(10,("Zero acl count passed. Returning Success\n"));
1640                 return 0;
1641         }
1642
1643         if(aclp == NULL) {
1644                 DEBUG(0,("Null ACL pointer in hpux_acl_sort. Returning Failure. \n"));
1645                 return -1;
1646         }
1647
1648         /* Count different types of ACLs in the ACLs array */
1649
1650         hpux_count_obj(acl_count, aclp, &acl_obj_count);
1651
1652         /* There should be only one entry each of type USER_OBJ, GROUP_OBJ, 
1653          * CLASS_OBJ and OTHER_OBJ 
1654          */
1655
1656         if( (acl_obj_count.n_user_obj  != 1) || 
1657                 (acl_obj_count.n_group_obj != 1) || 
1658                 (acl_obj_count.n_class_obj != 1) ||
1659                 (acl_obj_count.n_other_obj != 1) 
1660         ) {
1661                 DEBUG(0,("hpux_acl_sort: More than one entry or no entries for \
1662 USER OBJ or GROUP_OBJ or OTHER_OBJ or CLASS_OBJ\n"));
1663                 return -1;
1664         }
1665
1666         /* If any of the default objects are present, there should be only
1667          * one of them each.
1668          */
1669
1670         if( (acl_obj_count.n_def_user_obj  > 1) || (acl_obj_count.n_def_group_obj > 1) || 
1671                         (acl_obj_count.n_def_other_obj > 1) || (acl_obj_count.n_def_class_obj > 1) ) {
1672                 DEBUG(0,("hpux_acl_sort: More than one entry for DEF_CLASS_OBJ \
1673 or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
1674                 return -1;
1675         }
1676
1677         /* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl 
1678          * structures.  
1679          *
1680          * Sorting crieteria - First sort by ACL type. If there are multiple entries of
1681          * same ACL type, sort by ACL id.
1682          *
1683          * I am using the trival kind of sorting method here because, performance isn't 
1684          * really effected by the ACLs feature. More over there aren't going to be more
1685          * than 17 entries on HPUX. 
1686          */
1687
1688         for(i=0; i<acl_count;i++) {
1689                 for (j=i+1; j<acl_count; j++) {
1690                         if( aclp[i].a_type > aclp[j].a_type ) {
1691                                 /* ACL entries out of order, swap them */
1692
1693                                 hpux_swap_acl_entries((aclp+i), (aclp+j));
1694
1695                         } else if ( aclp[i].a_type == aclp[j].a_type ) {
1696
1697                                 /* ACL entries of same type, sort by id */
1698
1699                                 if(aclp[i].a_id > aclp[j].a_id) {
1700                                         hpux_swap_acl_entries((aclp+i), (aclp+j));
1701                                 } else if (aclp[i].a_id == aclp[j].a_id) {
1702                                         /* We have a duplicate entry. */
1703                                         if(hpux_prohibited_duplicate_type(aclp[i].a_type)) {
1704                                                 DEBUG(0, ("hpux_acl_sort: Duplicate entry: Type(hex): %x Id: %d\n",
1705                                                         aclp[i].a_type, aclp[i].a_id));
1706                                                 return -1;
1707                                         }
1708                                 }
1709
1710                         }
1711                 }
1712         }
1713
1714         /* set the class obj permissions to the computed one. */
1715         if(calclass) {
1716                 int n_class_obj_index = -1;
1717
1718                 for(i=0;i<acl_count;i++) {
1719                         n_class_obj_perm |= hpux_get_needed_class_perm((aclp+i));
1720
1721                         if(aclp[i].a_type == CLASS_OBJ)
1722                                 n_class_obj_index = i;
1723                 }
1724                 aclp[n_class_obj_index].a_perm = n_class_obj_perm;
1725         }
1726
1727         return 0;
1728 #else
1729         return aclsort(acl_count, calclass, aclp);
1730 #endif
1731 }
1732
1733 /*
1734  * sort the ACL and check it for validity
1735  *
1736  * if it's a minimal ACL with only 4 entries then we
1737  * need to recalculate the mask permissions to make
1738  * sure that they are the same as the GROUP_OBJ
1739  * permissions as required by the UnixWare acl() system call.
1740  *
1741  * (note: since POSIX allows minimal ACLs which only contain
1742  * 3 entries - ie there is no mask entry - we should, in theory,
1743  * check for this and add a mask entry if necessary - however
1744  * we "know" that the caller of this interface always specifies
1745  * a mask so, in practice "this never happens" (tm) - if it *does*
1746  * happen aclsort() will fail and return an error and someone will
1747  * have to fix it ...)
1748  */
1749
1750 static int acl_sort(SMB_ACL_T acl_d)
1751 {
1752         int fixmask = (acl_d->count <= 4);
1753
1754         if (hpux_acl_sort(acl_d->count, fixmask, acl_d->acl) != 0) {
1755                 errno = EINVAL;
1756                 return -1;
1757         }
1758         return 0;
1759 }
1760  
1761 int sys_acl_valid(SMB_ACL_T acl_d)
1762 {
1763         return acl_sort(acl_d);
1764 }
1765
1766 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
1767 {
1768         struct stat     s;
1769         struct acl      *acl_p;
1770         int             acl_count;
1771         struct acl      *acl_buf        = NULL;
1772         int             ret;
1773
1774         if(hpux_acl_call_presence() == False) {
1775                 /* Looks like we don't have the acl() system call on HPUX. 
1776                  * May be the system doesn't have the latest version of JFS.
1777                  */
1778                 errno=ENOSYS;
1779                 return -1; 
1780         }
1781
1782         if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
1783                 errno = EINVAL;
1784                 return -1;
1785         }
1786
1787         if (acl_sort(acl_d) != 0) {
1788                 return -1;
1789         }
1790
1791         acl_p           = &acl_d->acl[0];
1792         acl_count       = acl_d->count;
1793
1794         /*
1795          * if it's a directory there is extra work to do
1796          * since the acl() system call will replace both
1797          * the access ACLs and the default ACLs (if any)
1798          */
1799         if (stat(name, &s) != 0) {
1800                 return -1;
1801         }
1802         if (S_ISDIR(s.st_mode)) {
1803                 SMB_ACL_T       acc_acl;
1804                 SMB_ACL_T       def_acl;
1805                 SMB_ACL_T       tmp_acl;
1806                 int             i;
1807
1808                 if (type == SMB_ACL_TYPE_ACCESS) {
1809                         acc_acl = acl_d;
1810                         def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
1811
1812                 } else {
1813                         def_acl = acl_d;
1814                         acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
1815                 }
1816
1817                 if (tmp_acl == NULL) {
1818                         return -1;
1819                 }
1820
1821                 /*
1822                  * allocate a temporary buffer for the complete ACL
1823                  */
1824                 acl_count = acc_acl->count + def_acl->count;
1825                 acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count);
1826
1827                 if (acl_buf == NULL) {
1828                         sys_acl_free_acl(tmp_acl);
1829                         errno = ENOMEM;
1830                         return -1;
1831                 }
1832
1833                 /*
1834                  * copy the access control and default entries into the buffer
1835                  */
1836                 memcpy(&acl_buf[0], &acc_acl->acl[0],
1837                         acc_acl->count * sizeof(acl_buf[0]));
1838
1839                 memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
1840                         def_acl->count * sizeof(acl_buf[0]));
1841
1842                 /*
1843                  * set the ACL_DEFAULT flag on the default entries
1844                  */
1845                 for (i = acc_acl->count; i < acl_count; i++) {
1846                         acl_buf[i].a_type |= ACL_DEFAULT;
1847                 }
1848
1849                 sys_acl_free_acl(tmp_acl);
1850
1851         } else if (type != SMB_ACL_TYPE_ACCESS) {
1852                 errno = EINVAL;
1853                 return -1;
1854         }
1855
1856         ret = acl(name, ACL_SET, acl_count, acl_p);
1857
1858         if (acl_buf) {
1859                 free(acl_buf);
1860         }
1861
1862         return ret;
1863 }
1864
1865 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
1866 {
1867         /*
1868          * HPUX doesn't have the facl call. Fake it using the path.... JRA.
1869          */
1870
1871         files_struct *fsp = file_find_fd(fd);
1872
1873         if (fsp == NULL) {
1874                 errno = EBADF;
1875                 return NULL;
1876         }
1877
1878         if (acl_sort(acl_d) != 0) {
1879                 return -1;
1880         }
1881
1882         /*
1883          * We know we're in the same conn context. So we
1884          * can use the relative path.
1885          */
1886
1887         return sys_acl_set_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS, acl_d);
1888 }
1889
1890 int sys_acl_delete_def_file(const char *path)
1891 {
1892         SMB_ACL_T       acl_d;
1893         int             ret;
1894
1895         /*
1896          * fetching the access ACL and rewriting it has
1897          * the effect of deleting the default ACL
1898          */
1899         if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
1900                 return -1;
1901         }
1902
1903         ret = acl(path, ACL_SET, acl_d->count, acl_d->acl);
1904
1905         sys_acl_free_acl(acl_d);
1906         
1907         return ret;
1908 }
1909
1910 int sys_acl_free_text(char *text)
1911 {
1912         free(text);
1913         return 0;
1914 }
1915
1916 int sys_acl_free_acl(SMB_ACL_T acl_d) 
1917 {
1918         free(acl_d);
1919         return 0;
1920 }
1921
1922 int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
1923 {
1924         return 0;
1925 }
1926
1927 #elif defined(HAVE_IRIX_ACLS)
1928
1929 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
1930 {
1931         if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
1932                 errno = EINVAL;
1933                 return -1;
1934         }
1935
1936         if (entry_p == NULL) {
1937                 errno = EINVAL;
1938                 return -1;
1939         }
1940
1941         if (entry_id == SMB_ACL_FIRST_ENTRY) {
1942                 acl_d->next = 0;
1943         }
1944
1945         if (acl_d->next < 0) {
1946                 errno = EINVAL;
1947                 return -1;
1948         }
1949
1950         if (acl_d->next >= acl_d->aclp->acl_cnt) {
1951                 return 0;
1952         }
1953
1954         *entry_p = &acl_d->aclp->acl_entry[acl_d->next++];
1955
1956         return 1;
1957 }
1958
1959 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
1960 {
1961         *type_p = entry_d->ae_tag;
1962
1963         return 0;
1964 }
1965
1966 int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
1967 {
1968         *permset_p = entry_d;
1969
1970         return 0;
1971 }
1972
1973 void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
1974 {
1975         if (entry_d->ae_tag != SMB_ACL_USER
1976             && entry_d->ae_tag != SMB_ACL_GROUP) {
1977                 errno = EINVAL;
1978                 return NULL;
1979         }
1980
1981         return &entry_d->ae_id;
1982 }
1983
1984 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
1985 {
1986         SMB_ACL_T       a;
1987
1988         if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
1989                 errno = ENOMEM;
1990                 return NULL;
1991         }
1992         if ((a->aclp = acl_get_file(path_p, type)) == NULL) {
1993                 SAFE_FREE(a);
1994                 return NULL;
1995         }
1996         a->next = -1;
1997         a->freeaclp = True;
1998         return a;
1999 }
2000
2001 SMB_ACL_T sys_acl_get_fd(int fd)
2002 {
2003         SMB_ACL_T       a;
2004
2005         if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
2006                 errno = ENOMEM;
2007                 return NULL;
2008         }
2009         if ((a->aclp = acl_get_fd(fd)) == NULL) {
2010                 SAFE_FREE(a);
2011                 return NULL;
2012         }
2013         a->next = -1;
2014         a->freeaclp = True;
2015         return a;
2016 }
2017
2018 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
2019 {
2020         permset_d->ae_perm = 0;
2021
2022         return 0;
2023 }
2024
2025 int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
2026 {
2027         if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
2028             && perm != SMB_ACL_EXECUTE) {
2029                 errno = EINVAL;
2030                 return -1;
2031         }
2032
2033         if (permset_d == NULL) {
2034                 errno = EINVAL;
2035                 return -1;
2036         }
2037
2038         permset_d->ae_perm |= perm;
2039
2040         return 0;
2041 }
2042
2043 int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
2044 {
2045         return permset_d->ae_perm & perm;
2046 }
2047
2048 char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
2049 {
2050         return acl_to_text(acl_d->aclp, len_p);
2051 }
2052
2053 SMB_ACL_T sys_acl_init(int count)
2054 {
2055         SMB_ACL_T       a;
2056
2057         if (count < 0) {
2058                 errno = EINVAL;
2059                 return NULL;
2060         }
2061
2062         if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + sizeof(struct acl))) == NULL) {
2063                 errno = ENOMEM;
2064                 return NULL;
2065         }
2066
2067         a->next = -1;
2068         a->freeaclp = False;
2069         a->aclp = (struct acl *)(&a->aclp + sizeof(struct acl *));
2070         a->aclp->acl_cnt = 0;
2071
2072         return a;
2073 }
2074
2075
2076 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
2077 {
2078         SMB_ACL_T       acl_d;
2079         SMB_ACL_ENTRY_T entry_d;
2080
2081         if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
2082                 errno = EINVAL;
2083                 return -1;
2084         }
2085
2086         if (acl_d->aclp->acl_cnt >= ACL_MAX_ENTRIES) {
2087                 errno = ENOSPC;
2088                 return -1;
2089         }
2090
2091         entry_d         = &acl_d->aclp->acl_entry[acl_d->aclp->acl_cnt++];
2092         entry_d->ae_tag = 0;
2093         entry_d->ae_id  = 0;
2094         entry_d->ae_perm        = 0;
2095         *entry_p        = entry_d;
2096
2097         return 0;
2098 }
2099
2100 int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
2101 {
2102         switch (tag_type) {
2103                 case SMB_ACL_USER:
2104                 case SMB_ACL_USER_OBJ:
2105                 case SMB_ACL_GROUP:
2106                 case SMB_ACL_GROUP_OBJ:
2107                 case SMB_ACL_OTHER:
2108                 case SMB_ACL_MASK:
2109                         entry_d->ae_tag = tag_type;
2110                         break;
2111                 default:
2112                         errno = EINVAL;
2113                         return -1;
2114         }
2115
2116         return 0;
2117 }
2118
2119 int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
2120 {
2121         if (entry_d->ae_tag != SMB_ACL_GROUP
2122             && entry_d->ae_tag != SMB_ACL_USER) {
2123                 errno = EINVAL;
2124                 return -1;
2125         }
2126
2127         entry_d->ae_id = *((id_t *)qual_p);
2128
2129         return 0;
2130 }
2131
2132 int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
2133 {
2134         if (permset_d->ae_perm & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
2135                 return EINVAL;
2136         }
2137
2138         entry_d->ae_perm = permset_d->ae_perm;
2139
2140         return 0;
2141 }
2142
2143 int sys_acl_valid(SMB_ACL_T acl_d)
2144 {
2145         return acl_valid(acl_d->aclp);
2146 }
2147
2148 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
2149 {
2150         return acl_set_file(name, type, acl_d->aclp);
2151 }
2152
2153 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
2154 {
2155         return acl_set_fd(fd, acl_d->aclp);
2156 }
2157
2158 int sys_acl_delete_def_file(const char *name)
2159 {
2160         return acl_delete_def_file(name);
2161 }
2162
2163 int sys_acl_free_text(char *text)
2164 {
2165         return acl_free(text);
2166 }
2167
2168 int sys_acl_free_acl(SMB_ACL_T acl_d) 
2169 {
2170         if (acl_d->freeaclp) {
2171                 acl_free(acl_d->aclp);
2172         }
2173         acl_free(acl_d);
2174         return 0;
2175 }
2176
2177 int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
2178 {
2179         return 0;
2180 }
2181
2182 #elif defined(HAVE_AIX_ACLS)
2183
2184 /* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
2185
2186 int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
2187 {
2188         struct acl_entry_link *link;
2189         struct new_acl_entry *entry;
2190         int keep_going;
2191
2192         DEBUG(10,("This is the count: %d\n",theacl->count));
2193
2194         /* Check if count was previously set to -1. *
2195          * If it was, that means we reached the end *
2196          * of the acl last time.                    */
2197         if(theacl->count == -1)
2198                 return(0);
2199
2200         link = theacl;
2201         /* To get to the next acl, traverse linked list until index *
2202          * of acl matches the count we are keeping.  This count is  *
2203          * incremented each time we return an acl entry.            */
2204
2205         for(keep_going = 0; keep_going < theacl->count; keep_going++)
2206                 link = link->nextp;
2207
2208         entry = *entry_p =  link->entryp;
2209
2210         DEBUG(10,("*entry_p is %d\n",entry_p));
2211         DEBUG(10,("*entry_p->ace_access is %d\n",entry->ace_access));
2212
2213         /* Increment count */
2214         theacl->count++;
2215         if(link->nextp == NULL)
2216                 theacl->count = -1;
2217
2218         return(1);
2219 }
2220
2221 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
2222 {
2223         /* Initialize tag type */
2224
2225         *tag_type_p = -1;
2226         DEBUG(10,("the tagtype is %d\n",entry_d->ace_id->id_type));
2227
2228         /* Depending on what type of entry we have, *
2229          * return tag type.                         */
2230         switch(entry_d->ace_id->id_type) {
2231         case ACEID_USER:
2232                 *tag_type_p = SMB_ACL_USER;
2233                 break;
2234         case ACEID_GROUP:
2235                 *tag_type_p = SMB_ACL_GROUP;
2236                 break;
2237
2238         case SMB_ACL_USER_OBJ:
2239         case SMB_ACL_GROUP_OBJ:
2240         case SMB_ACL_OTHER:
2241                 *tag_type_p = entry_d->ace_id->id_type;
2242                 break;
2243  
2244         default:
2245                 return(-1);
2246         }
2247
2248         return(0);
2249 }
2250
2251 int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
2252 {
2253         DEBUG(10,("Starting AIX sys_acl_get_permset\n"));
2254         *permset_p = &entry_d->ace_access;
2255         DEBUG(10,("**permset_p is %d\n",**permset_p));
2256         if(!(**permset_p & S_IXUSR) &&
2257                 !(**permset_p & S_IWUSR) &&
2258                 !(**permset_p & S_IRUSR) &&
2259                 (**permset_p != 0))
2260                         return(-1);
2261
2262         DEBUG(10,("Ending AIX sys_acl_get_permset\n"));
2263         return(0);
2264 }
2265
2266 void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
2267 {
2268         return(entry_d->ace_id->id_data);
2269 }
2270
2271 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
2272 {
2273         struct acl *file_acl = (struct acl *)NULL;
2274         struct acl_entry *acl_entry;
2275         struct new_acl_entry *new_acl_entry;
2276         struct ace_id *idp;
2277         struct acl_entry_link *acl_entry_link;
2278         struct acl_entry_link *acl_entry_link_head;
2279         int i;
2280         int rc = 0;
2281         uid_t user_id;
2282
2283         /* AIX has no DEFAULT */
2284         if  ( type == SMB_ACL_TYPE_DEFAULT )
2285                 return NULL;
2286
2287         /* Get the acl using statacl */
2288  
2289         DEBUG(10,("Entering sys_acl_get_file\n"));
2290         DEBUG(10,("path_p is %s\n",path_p));
2291
2292         file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2293  
2294         if(file_acl == NULL) {
2295                 errno=ENOMEM;
2296                 DEBUG(0,("Error in AIX sys_acl_get_file: %d\n",errno));
2297                 return(NULL);
2298         }
2299
2300         memset(file_acl,0,BUFSIZ);
2301
2302         rc = statacl((char *)path_p,0,file_acl,BUFSIZ);
2303         if(rc == -1) {
2304                 DEBUG(0,("statacl returned %d with errno %d\n",rc,errno));
2305                 SAFE_FREE(file_acl);
2306                 return(NULL);
2307         }
2308
2309         DEBUG(10,("Got facl and returned it\n"));
2310
2311         /* Point to the first acl entry in the acl */
2312         acl_entry =  file_acl->acl_ext;
2313
2314         /* Begin setting up the head of the linked list *
2315          * that will be used for the storing the acl    *
2316          * in a way that is useful for the posix_acls.c *
2317          * code.                                          */
2318
2319         acl_entry_link_head = acl_entry_link = sys_acl_init(0);
2320         if(acl_entry_link_head == NULL)
2321                 return(NULL);
2322
2323         acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2324         if(acl_entry_link->entryp == NULL) {
2325                 SAFE_FREE(file_acl);
2326                 errno = ENOMEM;
2327                 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
2328                 return(NULL);
2329         }
2330
2331         DEBUG(10,("acl_entry is %d\n",acl_entry));
2332         DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
2333
2334         /* Check if the extended acl bit is on.   *
2335          * If it isn't, do not show the           *
2336          * contents of the acl since AIX intends *
2337          * the extended info to remain unused     */
2338
2339         if(file_acl->acl_mode & S_IXACL){
2340                 /* while we are not pointing to the very end */
2341                 while(acl_entry < acl_last(file_acl)) {
2342                         /* before we malloc anything, make sure this is  */
2343                         /* a valid acl entry and one that we want to map */
2344                         idp = id_nxt(acl_entry->ace_id);
2345                         if((acl_entry->ace_type == ACC_SPECIFY ||
2346                                 (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
2347                                         acl_entry = acl_nxt(acl_entry);
2348                                         continue;
2349                         }
2350
2351                         idp = acl_entry->ace_id;
2352
2353                         /* Check if this is the first entry in the linked list. *
2354                          * The first entry needs to keep prevp pointing to NULL *
2355                          * and already has entryp allocated.                  */
2356
2357                         if(acl_entry_link_head->count != 0) {
2358                                 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2359
2360                                 if(acl_entry_link->nextp == NULL) {
2361                                         SAFE_FREE(file_acl);
2362                                         errno = ENOMEM;
2363                                         DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
2364                                         return(NULL);
2365                                 }
2366
2367                                 acl_entry_link->nextp->prevp = acl_entry_link;
2368                                 acl_entry_link = acl_entry_link->nextp;
2369                                 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2370                                 if(acl_entry_link->entryp == NULL) {
2371                                         SAFE_FREE(file_acl);
2372                                         errno = ENOMEM;
2373                                         DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
2374                                         return(NULL);
2375                                 }
2376                                 acl_entry_link->nextp = NULL;
2377                         }
2378
2379                         acl_entry_link->entryp->ace_len = acl_entry->ace_len;
2380
2381                         /* Don't really need this since all types are going *
2382                          * to be specified but, it's better than leaving it 0 */
2383
2384                         acl_entry_link->entryp->ace_type = acl_entry->ace_type;
2385  
2386                         acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2387  
2388                         memcpy(acl_entry_link->entryp->ace_id,idp,sizeof(struct ace_id));
2389
2390                         /* The access in the acl entries must be left shifted by *
2391                          * three bites, because they will ultimately be compared *
2392                          * to S_IRUSR, S_IWUSR, and S_IXUSR.                  */
2393
2394                         switch(acl_entry->ace_type){
2395                         case ACC_PERMIT:
2396                         case ACC_SPECIFY:
2397                                 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2398                                 acl_entry_link->entryp->ace_access <<= 6;
2399                                 acl_entry_link_head->count++;
2400                                 break;
2401                         case ACC_DENY:
2402                                 /* Since there is no way to return a DENY acl entry *
2403                                  * change to PERMIT and then shift.                 */
2404                                 DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
2405                                 acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
2406                                 DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
2407                                 acl_entry_link->entryp->ace_access <<= 6;
2408                                 acl_entry_link_head->count++;
2409                                 break;
2410                         default:
2411                                 return(0);
2412                         }
2413
2414                         DEBUG(10,("acl_entry = %d\n",acl_entry));
2415                         DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
2416  
2417                         acl_entry = acl_nxt(acl_entry);
2418                 }
2419         } /* end of if enabled */
2420
2421         /* Since owner, group, other acl entries are not *
2422          * part of the acl entries in an acl, they must  *
2423          * be dummied up to become part of the list.     */
2424
2425         for( i = 1; i < 4; i++) {
2426                 DEBUG(10,("i is %d\n",i));
2427                 if(acl_entry_link_head->count != 0) {
2428                         acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2429                         if(acl_entry_link->nextp == NULL) {
2430                                 SAFE_FREE(file_acl);
2431                                 errno = ENOMEM;
2432                                 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
2433                                 return(NULL);
2434                         }
2435
2436                         acl_entry_link->nextp->prevp = acl_entry_link;
2437                         acl_entry_link = acl_entry_link->nextp;
2438                         acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2439                         if(acl_entry_link->entryp == NULL) {
2440                                 SAFE_FREE(file_acl);
2441                                 errno = ENOMEM;
2442                                 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
2443                                 return(NULL);
2444                         }
2445                 }
2446
2447                 acl_entry_link->nextp = NULL;
2448
2449                 new_acl_entry = acl_entry_link->entryp;
2450                 idp = new_acl_entry->ace_id;
2451
2452                 new_acl_entry->ace_len = sizeof(struct acl_entry);
2453                 new_acl_entry->ace_type = ACC_PERMIT;
2454                 idp->id_len = sizeof(struct ace_id);
2455                 DEBUG(10,("idp->id_len = %d\n",idp->id_len));
2456                 memset(idp->id_data,0,sizeof(uid_t));
2457
2458                 switch(i) {
2459                 case 2:
2460                         new_acl_entry->ace_access = file_acl->g_access << 6;
2461                         idp->id_type = SMB_ACL_GROUP_OBJ;
2462                         break;
2463
2464                 case 3:
2465                         new_acl_entry->ace_access = file_acl->o_access << 6;
2466                         idp->id_type = SMB_ACL_OTHER;
2467                         break;
2468  
2469                 case 1:
2470                         new_acl_entry->ace_access = file_acl->u_access << 6;
2471                         idp->id_type = SMB_ACL_USER_OBJ;
2472                         break;
2473  
2474                 default:
2475                         return(NULL);
2476
2477                 }
2478
2479                 acl_entry_link_head->count++;
2480                 DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
2481         }
2482
2483         acl_entry_link_head->count = 0;
2484         SAFE_FREE(file_acl);
2485
2486         return(acl_entry_link_head);
2487 }
2488
2489 SMB_ACL_T sys_acl_get_fd(int fd)
2490 {
2491         struct acl *file_acl = (struct acl *)NULL;
2492         struct acl_entry *acl_entry;
2493         struct new_acl_entry *new_acl_entry;
2494         struct ace_id *idp;
2495         struct acl_entry_link *acl_entry_link;
2496         struct acl_entry_link *acl_entry_link_head;
2497         int i;
2498         int rc = 0;
2499         uid_t user_id;
2500
2501         /* Get the acl using fstatacl */
2502    
2503         DEBUG(10,("Entering sys_acl_get_fd\n"));
2504         DEBUG(10,("fd is %d\n",fd));
2505         file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2506
2507         if(file_acl == NULL) {
2508                 errno=ENOMEM;
2509                 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2510                 return(NULL);
2511         }
2512
2513         memset(file_acl,0,BUFSIZ);
2514
2515         rc = fstatacl(fd,0,file_acl,BUFSIZ);
2516         if(rc == -1) {
2517                 DEBUG(0,("The fstatacl call returned %d with errno %d\n",rc,errno));
2518                 SAFE_FREE(file_acl);
2519                 return(NULL);
2520         }
2521
2522         DEBUG(10,("Got facl and returned it\n"));
2523
2524         /* Point to the first acl entry in the acl */
2525
2526         acl_entry =  file_acl->acl_ext;
2527         /* Begin setting up the head of the linked list *
2528          * that will be used for the storing the acl    *
2529          * in a way that is useful for the posix_acls.c *
2530          * code.                                        */
2531
2532         acl_entry_link_head = acl_entry_link = sys_acl_init(0);
2533         if(acl_entry_link_head == NULL){
2534                 SAFE_FREE(file_acl);
2535                 return(NULL);
2536         }
2537
2538         acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2539
2540         if(acl_entry_link->entryp == NULL) {
2541                 errno = ENOMEM;
2542                 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2543                 SAFE_FREE(file_acl);
2544                 return(NULL);
2545         }
2546
2547         DEBUG(10,("acl_entry is %d\n",acl_entry));
2548         DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
2549  
2550         /* Check if the extended acl bit is on.   *
2551          * If it isn't, do not show the           *
2552          * contents of the acl since AIX intends  *
2553          * the extended info to remain unused     */
2554  
2555         if(file_acl->acl_mode & S_IXACL){
2556                 /* while we are not pointing to the very end */
2557                 while(acl_entry < acl_last(file_acl)) {
2558                         /* before we malloc anything, make sure this is  */
2559                         /* a valid acl entry and one that we want to map */
2560
2561                         idp = id_nxt(acl_entry->ace_id);
2562                         if((acl_entry->ace_type == ACC_SPECIFY ||
2563                                 (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
2564                                         acl_entry = acl_nxt(acl_entry);
2565                                         continue;
2566                         }
2567
2568                         idp = acl_entry->ace_id;
2569  
2570                         /* Check if this is the first entry in the linked list. *
2571                          * The first entry needs to keep prevp pointing to NULL *
2572                          * and already has entryp allocated.                 */
2573
2574                         if(acl_entry_link_head->count != 0) {
2575                                 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2576                                 if(acl_entry_link->nextp == NULL) {
2577                                         errno = ENOMEM;
2578                                         DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2579                                         SAFE_FREE(file_acl);
2580                                         return(NULL);
2581                                 }
2582                                 acl_entry_link->nextp->prevp = acl_entry_link;
2583                                 acl_entry_link = acl_entry_link->nextp;
2584                                 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2585                                 if(acl_entry_link->entryp == NULL) {
2586                                         errno = ENOMEM;
2587                                         DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2588                                         SAFE_FREE(file_acl);
2589                                         return(NULL);
2590                                 }
2591
2592                                 acl_entry_link->nextp = NULL;
2593                         }
2594
2595                         acl_entry_link->entryp->ace_len = acl_entry->ace_len;
2596
2597                         /* Don't really need this since all types are going *
2598                          * to be specified but, it's better than leaving it 0 */
2599
2600                         acl_entry_link->entryp->ace_type = acl_entry->ace_type;
2601                         acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2602
2603                         memcpy(acl_entry_link->entryp->ace_id, idp, sizeof(struct ace_id));
2604
2605                         /* The access in the acl entries must be left shifted by *
2606                          * three bites, because they will ultimately be compared *
2607                          * to S_IRUSR, S_IWUSR, and S_IXUSR.                  */
2608
2609                         switch(acl_entry->ace_type){
2610                         case ACC_PERMIT:
2611                         case ACC_SPECIFY:
2612                                 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2613                                 acl_entry_link->entryp->ace_access <<= 6;
2614                                 acl_entry_link_head->count++;
2615                                 break;
2616                         case ACC_DENY:
2617                                 /* Since there is no way to return a DENY acl entry *
2618                                  * change to PERMIT and then shift.                 */
2619                                 DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
2620                                 acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
2621                                 DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
2622                                 acl_entry_link->entryp->ace_access <<= 6;
2623                                 acl_entry_link_head->count++;
2624                                 break;
2625                         default:
2626                                 return(0);
2627                         }
2628
2629                         DEBUG(10,("acl_entry = %d\n",acl_entry));
2630                         DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
2631  
2632                         acl_entry = acl_nxt(acl_entry);
2633                 }
2634         } /* end of if enabled */
2635
2636         /* Since owner, group, other acl entries are not *
2637          * part of the acl entries in an acl, they must  *
2638          * be dummied up to become part of the list.     */
2639
2640         for( i = 1; i < 4; i++) {
2641                 DEBUG(10,("i is %d\n",i));
2642                 if(acl_entry_link_head->count != 0){
2643                         acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2644                         if(acl_entry_link->nextp == NULL) {
2645                                 errno = ENOMEM;
2646                                 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2647                                 SAFE_FREE(file_acl);
2648                                 return(NULL);
2649                         }
2650
2651                         acl_entry_link->nextp->prevp = acl_entry_link;
2652                         acl_entry_link = acl_entry_link->nextp;
2653                         acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2654
2655                         if(acl_entry_link->entryp == NULL) {
2656                                 SAFE_FREE(file_acl);
2657                                 errno = ENOMEM;
2658                                 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2659                                 return(NULL);
2660                         }
2661                 }
2662
2663                 acl_entry_link->nextp = NULL;
2664  
2665                 new_acl_entry = acl_entry_link->entryp;
2666                 idp = new_acl_entry->ace_id;
2667  
2668                 new_acl_entry->ace_len = sizeof(struct acl_entry);
2669                 new_acl_entry->ace_type = ACC_PERMIT;
2670                 idp->id_len = sizeof(struct ace_id);
2671                 DEBUG(10,("idp->id_len = %d\n",idp->id_len));
2672                 memset(idp->id_data,0,sizeof(uid_t));
2673  
2674                 switch(i) {
2675                 case 2:
2676                         new_acl_entry->ace_access = file_acl->g_access << 6;
2677                         idp->id_type = SMB_ACL_GROUP_OBJ;
2678                         break;
2679  
2680                 case 3:
2681                         new_acl_entry->ace_access = file_acl->o_access << 6;
2682                         idp->id_type = SMB_ACL_OTHER;
2683                         break;
2684  
2685                 case 1:
2686                         new_acl_entry->ace_access = file_acl->u_access << 6;
2687                         idp->id_type = SMB_ACL_USER_OBJ;
2688                         break;
2689  
2690                 default:
2691                         return(NULL);
2692                 }
2693  
2694                 acl_entry_link_head->count++;
2695                 DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
2696         }
2697
2698         acl_entry_link_head->count = 0;
2699         SAFE_FREE(file_acl);
2700  
2701         return(acl_entry_link_head);
2702 }
2703
2704 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
2705 {
2706         *permset = *permset & ~0777;
2707         return(0);
2708 }
2709
2710 int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
2711 {
2712         if((perm != 0) &&
2713                         (perm & (S_IXUSR | S_IWUSR | S_IRUSR)) == 0)
2714                 return(-1);
2715
2716         *permset |= perm;
2717         DEBUG(10,("This is the permset now: %d\n",*permset));
2718         return(0);
2719 }
2720
2721 char *sys_acl_to_text( SMB_ACL_T theacl, ssize_t *plen)
2722 {
2723         return(NULL);
2724 }
2725
2726 SMB_ACL_T sys_acl_init( int count)
2727 {
2728         struct acl_entry_link *theacl = NULL;
2729  
2730         DEBUG(10,("Entering sys_acl_init\n"));
2731
2732         theacl = SMB_MALLOC_P(struct acl_entry_link);
2733         if(theacl == NULL) {
2734                 errno = ENOMEM;
2735                 DEBUG(0,("Error in sys_acl_init is %d\n",errno));
2736                 return(NULL);
2737         }
2738
2739         theacl->count = 0;
2740         theacl->nextp = NULL;
2741         theacl->prevp = NULL;
2742         theacl->entryp = NULL;
2743         DEBUG(10,("Exiting sys_acl_init\n"));
2744         return(theacl);
2745 }
2746
2747 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
2748 {
2749         struct acl_entry_link *theacl;
2750         struct acl_entry_link *acl_entryp;
2751         struct acl_entry_link *temp_entry;
2752         int counting;
2753
2754         DEBUG(10,("Entering the sys_acl_create_entry\n"));
2755
2756         theacl = acl_entryp = *pacl;
2757
2758         /* Get to the end of the acl before adding entry */
2759
2760         for(counting=0; counting < theacl->count; counting++){
2761                 DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
2762                 temp_entry = acl_entryp;
2763                 acl_entryp = acl_entryp->nextp;
2764         }
2765
2766         if(theacl->count != 0){
2767                 temp_entry->nextp = acl_entryp = SMB_MALLOC_P(struct acl_entry_link);
2768                 if(acl_entryp == NULL) {
2769                         errno = ENOMEM;
2770                         DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
2771                         return(-1);
2772                 }
2773
2774                 DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
2775                 acl_entryp->prevp = temp_entry;
2776                 DEBUG(10,("The acl_entryp->prevp is %d\n",acl_entryp->prevp));
2777         }
2778
2779         *pentry = acl_entryp->entryp = SMB_MALLOC_P(struct new_acl_entry);
2780         if(*pentry == NULL) {
2781                 errno = ENOMEM;
2782                 DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
2783                 return(-1);
2784         }
2785
2786         memset(*pentry,0,sizeof(struct new_acl_entry));
2787         acl_entryp->entryp->ace_len = sizeof(struct acl_entry);
2788         acl_entryp->entryp->ace_type = ACC_PERMIT;
2789         acl_entryp->entryp->ace_id->id_len = sizeof(struct ace_id);
2790         acl_entryp->nextp = NULL;
2791         theacl->count++;
2792         DEBUG(10,("Exiting sys_acl_create_entry\n"));
2793         return(0);
2794 }
2795
2796 int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
2797 {
2798         DEBUG(10,("Starting AIX sys_acl_set_tag_type\n"));
2799         entry->ace_id->id_type = tagtype;
2800         DEBUG(10,("The tag type is %d\n",entry->ace_id->id_type));
2801         DEBUG(10,("Ending AIX sys_acl_set_tag_type\n"));
2802 }
2803
2804 int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
2805 {
2806         DEBUG(10,("Starting AIX sys_acl_set_qualifier\n"));
2807         memcpy(entry->ace_id->id_data,qual,sizeof(uid_t));
2808         DEBUG(10,("Ending AIX sys_acl_set_qualifier\n"));
2809         return(0);
2810 }
2811
2812 int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
2813 {
2814         DEBUG(10,("Starting AIX sys_acl_set_permset\n"));
2815         if(!(*permset & S_IXUSR) &&
2816                 !(*permset & S_IWUSR) &&
2817                 !(*permset & S_IRUSR) &&
2818                 (*permset != 0))
2819                         return(-1);
2820
2821         entry->ace_access = *permset;
2822         DEBUG(10,("entry->ace_access = %d\n",entry->ace_access));
2823         DEBUG(10,("Ending AIX sys_acl_set_permset\n"));
2824         return(0);
2825 }
2826
2827 int sys_acl_valid( SMB_ACL_T theacl )
2828 {
2829         int user_obj = 0;
2830         int group_obj = 0;
2831         int other_obj = 0;
2832         struct acl_entry_link *acl_entry;
2833
2834         for(acl_entry=theacl; acl_entry != NULL; acl_entry = acl_entry->nextp) {
2835                 user_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_USER_OBJ);
2836                 group_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_GROUP_OBJ);
2837                 other_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_OTHER);
2838         }
2839
2840         DEBUG(10,("user_obj=%d, group_obj=%d, other_obj=%d\n",user_obj,group_obj,other_obj));
2841  
2842         if(user_obj != 1 || group_obj != 1 || other_obj != 1)
2843                 return(-1); 
2844
2845         return(0);
2846 }
2847
2848 int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2849 {
2850         struct acl_entry_link *acl_entry_link = NULL;
2851         struct acl *file_acl = NULL;
2852         struct acl *file_acl_temp = NULL;
2853         struct acl_entry *acl_entry = NULL;
2854         struct ace_id *ace_id = NULL;
2855         uint id_type;
2856         uint ace_access;
2857         uint user_id;
2858         uint acl_length;
2859         uint rc;
2860
2861         DEBUG(10,("Entering sys_acl_set_file\n"));
2862         DEBUG(10,("File name is %s\n",name));
2863  
2864         /* AIX has no default ACL */
2865         if(acltype == SMB_ACL_TYPE_DEFAULT)
2866                 return(0);
2867
2868         acl_length = BUFSIZ;
2869         file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2870
2871         if(file_acl == NULL) {
2872                 errno = ENOMEM;
2873                 DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
2874                 return(-1);
2875         }
2876
2877         memset(file_acl,0,BUFSIZ);
2878
2879         file_acl->acl_len = ACL_SIZ;
2880         file_acl->acl_mode = S_IXACL;
2881
2882         for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
2883                 acl_entry_link->entryp->ace_access >>= 6;
2884                 id_type = acl_entry_link->entryp->ace_id->id_type;
2885
2886                 switch(id_type) {
2887                 case SMB_ACL_USER_OBJ:
2888                         file_acl->u_access = acl_entry_link->entryp->ace_access;
2889                         continue;
2890                 case SMB_ACL_GROUP_OBJ:
2891                         file_acl->g_access = acl_entry_link->entryp->ace_access;
2892                         continue;
2893                 case SMB_ACL_OTHER:
2894                         file_acl->o_access = acl_entry_link->entryp->ace_access;
2895                         continue;
2896                 case SMB_ACL_MASK:
2897                         continue;
2898                 }
2899
2900                 if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
2901                         acl_length += sizeof(struct acl_entry);
2902                         file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
2903                         if(file_acl_temp == NULL) {
2904                                 SAFE_FREE(file_acl);
2905                                 errno = ENOMEM;
2906                                 DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
2907                                 return(-1);
2908                         }  
2909
2910                         memcpy(file_acl_temp,file_acl,file_acl->acl_len);
2911                         SAFE_FREE(file_acl);
2912                         file_acl = file_acl_temp;
2913                 }
2914
2915                 acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
2916                 file_acl->acl_len += sizeof(struct acl_entry);
2917                 acl_entry->ace_len = acl_entry_link->entryp->ace_len;
2918                 acl_entry->ace_access = acl_entry_link->entryp->ace_access;
2919  
2920                 /* In order to use this, we'll need to wait until we can get denies */
2921                 /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
2922                 acl_entry->ace_type = ACC_SPECIFY; */
2923
2924                 acl_entry->ace_type = ACC_SPECIFY;
2925  
2926                 ace_id = acl_entry->ace_id;
2927  
2928                 ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
2929                 DEBUG(10,("The id type is %d\n",ace_id->id_type));
2930                 ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
2931                 memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
2932                 memcpy(acl_entry->ace_id->id_data, &user_id, sizeof(uid_t));
2933         }
2934
2935         rc = chacl(name,file_acl,file_acl->acl_len);
2936         DEBUG(10,("errno is %d\n",errno));
2937         DEBUG(10,("return code is %d\n",rc));
2938         SAFE_FREE(file_acl);
2939         DEBUG(10,("Exiting the sys_acl_set_file\n"));
2940         return(rc);
2941 }
2942
2943 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
2944 {
2945         struct acl_entry_link *acl_entry_link = NULL;
2946         struct acl *file_acl = NULL;
2947         struct acl *file_acl_temp = NULL;
2948         struct acl_entry *acl_entry = NULL;
2949         struct ace_id *ace_id = NULL;
2950         uint id_type;
2951         uint user_id;
2952         uint acl_length;
2953         uint rc;
2954  
2955         DEBUG(10,("Entering sys_acl_set_fd\n"));
2956         acl_length = BUFSIZ;
2957         file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2958
2959         if(file_acl == NULL) {
2960                 errno = ENOMEM;
2961                 DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
2962                 return(-1);
2963         }
2964
2965         memset(file_acl,0,BUFSIZ);
2966  
2967         file_acl->acl_len = ACL_SIZ;
2968         file_acl->acl_mode = S_IXACL;
2969
2970         for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
2971                 acl_entry_link->entryp->ace_access >>= 6;
2972                 id_type = acl_entry_link->entryp->ace_id->id_type;
2973                 DEBUG(10,("The id_type is %d\n",id_type));
2974
2975                 switch(id_type) {
2976                 case SMB_ACL_USER_OBJ:
2977                         file_acl->u_access = acl_entry_link->entryp->ace_access;
2978                         continue;
2979                 case SMB_ACL_GROUP_OBJ:
2980                         file_acl->g_access = acl_entry_link->entryp->ace_access;
2981                         continue;
2982                 case SMB_ACL_OTHER:
2983                         file_acl->o_access = acl_entry_link->entryp->ace_access;
2984                         continue;
2985                 case SMB_ACL_MASK:
2986                         continue;
2987                 }
2988
2989                 if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
2990                         acl_length += sizeof(struct acl_entry);
2991                         file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
2992                         if(file_acl_temp == NULL) {
2993                                 SAFE_FREE(file_acl);
2994                                 errno = ENOMEM;
2995                                 DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
2996                                 return(-1);
2997                         }
2998
2999                         memcpy(file_acl_temp,file_acl,file_acl->acl_len);
3000                         SAFE_FREE(file_acl);
3001                         file_acl = file_acl_temp;
3002                 }
3003
3004                 acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
3005                 file_acl->acl_len += sizeof(struct acl_entry);
3006                 acl_entry->ace_len = acl_entry_link->entryp->ace_len;
3007                 acl_entry->ace_access = acl_entry_link->entryp->ace_access;
3008  
3009                 /* In order to use this, we'll need to wait until we can get denies */
3010                 /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
3011                         acl_entry->ace_type = ACC_SPECIFY; */
3012  
3013                 acl_entry->ace_type = ACC_SPECIFY;
3014  
3015                 ace_id = acl_entry->ace_id;
3016  
3017                 ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
3018                 DEBUG(10,("The id type is %d\n",ace_id->id_type));
3019                 ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
3020                 memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
3021                 memcpy(ace_id->id_data, &user_id, sizeof(uid_t));
3022         }
3023  
3024         rc = fchacl(fd,file_acl,file_acl->acl_len);
3025         DEBUG(10,("errno is %d\n",errno));
3026         DEBUG(10,("return code is %d\n",rc));
3027         SAFE_FREE(file_acl);
3028         DEBUG(10,("Exiting sys_acl_set_fd\n"));
3029         return(rc);
3030 }
3031
3032 int sys_acl_delete_def_file(const char *name)
3033 {
3034         /* AIX has no default ACL */
3035         return 0;
3036 }
3037
3038 int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
3039 {
3040         return(*permset & perm);
3041 }
3042
3043 int sys_acl_free_text(char *text)
3044 {
3045         return(0);
3046 }
3047
3048 int sys_acl_free_acl(SMB_ACL_T posix_acl)
3049 {
3050         struct acl_entry_link *acl_entry_link;
3051
3052         for(acl_entry_link = posix_acl->nextp; acl_entry_link->nextp != NULL; acl_entry_link = acl_entry_link->nextp) {
3053                 SAFE_FREE(acl_entry_link->prevp->entryp);
3054                 SAFE_FREE(acl_entry_link->prevp);
3055         }
3056
3057         SAFE_FREE(acl_entry_link->prevp->entryp);
3058         SAFE_FREE(acl_entry_link->prevp);
3059         SAFE_FREE(acl_entry_link->entryp);
3060         SAFE_FREE(acl_entry_link);
3061  
3062         return(0);
3063 }
3064
3065 int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
3066 {
3067         return(0);
3068 }
3069
3070 #else /* No ACLs. */
3071
3072 int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
3073 {
3074         errno = ENOSYS;
3075         return -1;
3076 }
3077
3078 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
3079 {
3080         errno = ENOSYS;
3081         return -1;
3082 }
3083
3084 int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
3085 {
3086         errno = ENOSYS;
3087         return -1;
3088 }
3089
3090 void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
3091 {
3092         errno = ENOSYS;
3093         return NULL;
3094 }
3095
3096 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
3097 {
3098         errno = ENOSYS;
3099         return (SMB_ACL_T)NULL;
3100 }
3101
3102 SMB_ACL_T sys_acl_get_fd(int fd)
3103 {
3104         errno = ENOSYS;
3105         return (SMB_ACL_T)NULL;
3106 }
3107
3108 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
3109 {
3110         errno = ENOSYS;
3111         return -1;
3112 }
3113
3114 int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
3115 {
3116         errno = ENOSYS;
3117         return -1;
3118 }
3119
3120 int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
3121 {
3122         errno = ENOSYS;
3123         return (permset & perm) ? 1 : 0;
3124 }
3125
3126 char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
3127 {
3128         errno = ENOSYS;
3129         return NULL;
3130 }
3131
3132 int sys_acl_free_text(char *text)
3133 {
3134         errno = ENOSYS;
3135         return -1;
3136 }
3137
3138 SMB_ACL_T sys_acl_init( int count)
3139 {
3140         errno = ENOSYS;
3141         return NULL;
3142 }
3143
3144 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
3145 {
3146         errno = ENOSYS;
3147         return -1;
3148 }
3149
3150 int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
3151 {
3152         errno = ENOSYS;
3153         return -1;
3154 }
3155
3156 int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
3157 {
3158         errno = ENOSYS;
3159         return -1;
3160 }
3161
3162 int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
3163 {
3164         errno = ENOSYS;
3165         return -1;
3166 }
3167
3168 int sys_acl_valid( SMB_ACL_T theacl )
3169 {
3170         errno = ENOSYS;
3171         return -1;
3172 }
3173
3174 int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
3175 {
3176         errno = ENOSYS;
3177         return -1;
3178 }
3179
3180 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
3181 {
3182         errno = ENOSYS;
3183         return -1;
3184 }
3185
3186 int sys_acl_delete_def_file(const char *name)
3187 {
3188         errno = ENOSYS;
3189         return -1;
3190 }
3191
3192 int sys_acl_free_acl(SMB_ACL_T the_acl) 
3193 {
3194         errno = ENOSYS;
3195         return -1;
3196 }
3197
3198 int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
3199 {
3200         errno = ENOSYS;
3201         return -1;
3202 }
3203
3204 #endif /* No ACLs. */
3205
3206 /************************************************************************
3207  Deliberately outside the ACL defines. Return 1 if this is a "no acls"
3208  errno, 0 if not.
3209 ************************************************************************/
3210
3211 int no_acl_syscall_error(int err)
3212 {
3213 #if defined(ENOSYS)
3214         if (err == ENOSYS) {
3215                 return 1;
3216         }
3217 #endif
3218 #if defined(ENOTSUP)
3219         if (err == ENOTSUP) {
3220                 return 1;
3221         }
3222 #endif
3223         return 0;
3224 }