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