r13915: Fixed a very interesting class of realloc() bugs found by Coverity.
[kai/samba.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                                 free(oldtext);
1322                                 errno = ENOMEM;
1323                                 return NULL;
1324                         }
1325                 }
1326
1327                 slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
1328                 len += nbytes - 1;
1329         }
1330
1331         if (len_p)
1332                 *len_p = len;
1333
1334         return text;
1335 }
1336
1337 SMB_ACL_T sys_acl_init(int count)
1338 {
1339         SMB_ACL_T       a;
1340
1341         if (count < 0) {
1342                 errno = EINVAL;
1343                 return NULL;
1344         }
1345
1346         /*
1347          * note that since the definition of the structure pointed
1348          * to by the SMB_ACL_T includes the first element of the
1349          * acl[] array, this actually allocates an ACL with room
1350          * for (count+1) entries
1351          */
1352         if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + count * sizeof(struct acl))) == NULL) {
1353                 errno = ENOMEM;
1354                 return NULL;
1355         }
1356
1357         a->size = count + 1;
1358         a->count = 0;
1359         a->next = -1;
1360
1361         return a;
1362 }
1363
1364
1365 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
1366 {
1367         SMB_ACL_T       acl_d;
1368         SMB_ACL_ENTRY_T entry_d;
1369
1370         if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
1371                 errno = EINVAL;
1372                 return -1;
1373         }
1374
1375         if (acl_d->count >= acl_d->size) {
1376                 errno = ENOSPC;
1377                 return -1;
1378         }
1379
1380         entry_d         = &acl_d->acl[acl_d->count++];
1381         entry_d->a_type = 0;
1382         entry_d->a_id   = -1;
1383         entry_d->a_perm = 0;
1384         *entry_p        = entry_d;
1385
1386         return 0;
1387 }
1388
1389 int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
1390 {
1391         switch (tag_type) {
1392                 case SMB_ACL_USER:
1393                 case SMB_ACL_USER_OBJ:
1394                 case SMB_ACL_GROUP:
1395                 case SMB_ACL_GROUP_OBJ:
1396                 case SMB_ACL_OTHER:
1397                 case SMB_ACL_MASK:
1398                         entry_d->a_type = tag_type;
1399                         break;
1400                 default:
1401                         errno = EINVAL;
1402                         return -1;
1403         }
1404
1405         return 0;
1406 }
1407
1408 int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
1409 {
1410         if (entry_d->a_type != SMB_ACL_GROUP
1411             && entry_d->a_type != SMB_ACL_USER) {
1412                 errno = EINVAL;
1413                 return -1;
1414         }
1415
1416         entry_d->a_id = *((id_t *)qual_p);
1417
1418         return 0;
1419 }
1420
1421 int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
1422 {
1423         if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
1424                 return EINVAL;
1425         }
1426
1427         entry_d->a_perm = *permset_d;
1428
1429         return 0;
1430 }
1431
1432 /* Structure to capture the count for each type of ACE. */
1433
1434 struct hpux_acl_types {
1435         int n_user;
1436         int n_def_user;
1437         int n_user_obj;
1438         int n_def_user_obj;
1439
1440         int n_group;
1441         int n_def_group;
1442         int n_group_obj;
1443         int n_def_group_obj;
1444
1445         int n_other;
1446         int n_other_obj;
1447         int n_def_other_obj;
1448
1449         int n_class_obj;
1450         int n_def_class_obj;
1451
1452         int n_illegal_obj;
1453 };
1454
1455 /* count_obj:
1456  * Counts the different number of objects in a given array of ACL
1457  * structures.
1458  * Inputs:
1459  *
1460  * acl_count      - Count of ACLs in the array of ACL strucutres.
1461  * aclp           - Array of ACL structures.
1462  * acl_type_count - Pointer to acl_types structure. Should already be
1463  *                  allocated.
1464  * Output: 
1465  *
1466  * acl_type_count - This structure is filled up with counts of various 
1467  *                  acl types.
1468  */
1469
1470 static int hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_types *acl_type_count)
1471 {
1472         int i;
1473
1474         memset(acl_type_count, 0, sizeof(struct hpux_acl_types));
1475
1476         for(i=0;i<acl_count;i++) {
1477                 switch(aclp[i].a_type) {
1478                 case USER: 
1479                         acl_type_count->n_user++;
1480                         break;
1481                 case USER_OBJ: 
1482                         acl_type_count->n_user_obj++;
1483                         break;
1484                 case DEF_USER_OBJ: 
1485                         acl_type_count->n_def_user_obj++;
1486                         break;
1487                 case GROUP: 
1488                         acl_type_count->n_group++;
1489                         break;
1490                 case GROUP_OBJ: 
1491                         acl_type_count->n_group_obj++;
1492                         break;
1493                 case DEF_GROUP_OBJ: 
1494                         acl_type_count->n_def_group_obj++;
1495                         break;
1496                 case OTHER_OBJ: 
1497                         acl_type_count->n_other_obj++;
1498                         break;
1499                 case DEF_OTHER_OBJ: 
1500                         acl_type_count->n_def_other_obj++;
1501                         break;
1502                 case CLASS_OBJ:
1503                         acl_type_count->n_class_obj++;
1504                         break;
1505                 case DEF_CLASS_OBJ:
1506                         acl_type_count->n_def_class_obj++;
1507                         break;
1508                 case DEF_USER:
1509                         acl_type_count->n_def_user++;
1510                         break;
1511                 case DEF_GROUP:
1512                         acl_type_count->n_def_group++;
1513                         break;
1514                 default: 
1515                         acl_type_count->n_illegal_obj++;
1516                         break;
1517                 }
1518         }
1519 }
1520
1521 /* swap_acl_entries:  Swaps two ACL entries. 
1522  *
1523  * Inputs: aclp0, aclp1 - ACL entries to be swapped.
1524  */
1525
1526 static void hpux_swap_acl_entries(struct acl *aclp0, struct acl *aclp1)
1527 {
1528         struct acl temp_acl;
1529
1530         temp_acl.a_type = aclp0->a_type;
1531         temp_acl.a_id = aclp0->a_id;
1532         temp_acl.a_perm = aclp0->a_perm;
1533
1534         aclp0->a_type = aclp1->a_type;
1535         aclp0->a_id = aclp1->a_id;
1536         aclp0->a_perm = aclp1->a_perm;
1537
1538         aclp1->a_type = temp_acl.a_type;
1539         aclp1->a_id = temp_acl.a_id;
1540         aclp1->a_perm = temp_acl.a_perm;
1541 }
1542
1543 /* prohibited_duplicate_type
1544  * Identifies if given ACL type can have duplicate entries or 
1545  * not.
1546  *
1547  * Inputs: acl_type - ACL Type.
1548  *
1549  * Outputs: 
1550  *
1551  * Return.. 
1552  *
1553  * True - If the ACL type matches any of the prohibited types.
1554  * False - If the ACL type doesn't match any of the prohibited types.
1555  */ 
1556
1557 static BOOL hpux_prohibited_duplicate_type(int acl_type)
1558 {
1559         switch(acl_type) {
1560                 case USER:
1561                 case GROUP:
1562                 case DEF_USER: 
1563                 case DEF_GROUP:
1564                         return True;
1565                 default:
1566                         return False;
1567         }
1568 }
1569
1570 /* get_needed_class_perm
1571  * Returns the permissions of a ACL structure only if the ACL
1572  * type matches one of the pre-determined types for computing 
1573  * CLASS_OBJ permissions.
1574  *
1575  * Inputs: aclp - Pointer to ACL structure.
1576  */
1577
1578 static int hpux_get_needed_class_perm(struct acl *aclp)
1579 {
1580         switch(aclp->a_type) {
1581                 case USER: 
1582                 case GROUP_OBJ: 
1583                 case GROUP: 
1584                 case DEF_USER_OBJ: 
1585                 case DEF_USER:
1586                 case DEF_GROUP_OBJ: 
1587                 case DEF_GROUP:
1588                 case DEF_CLASS_OBJ:
1589                 case DEF_OTHER_OBJ: 
1590                         return aclp->a_perm;
1591                 default: 
1592                         return 0;
1593         }
1594 }
1595
1596 /* acl_sort for HPUX.
1597  * Sorts the array of ACL structures as per the description in
1598  * aclsort man page. Refer to aclsort man page for more details
1599  *
1600  * Inputs:
1601  *
1602  * acl_count - Count of ACLs in the array of ACL structures.
1603  * calclass  - If this is not zero, then we compute the CLASS_OBJ
1604  *             permissions.
1605  * aclp      - Array of ACL structures.
1606  *
1607  * Outputs:
1608  *
1609  * aclp     - Sorted array of ACL structures.
1610  *
1611  * Outputs:
1612  *
1613  * Returns 0 for success -1 for failure. Prints a message to the Samba
1614  * debug log in case of failure.
1615  */
1616
1617 static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
1618 {
1619 #if !defined(HAVE_HPUX_ACLSORT)
1620         /*
1621          * The aclsort() system call is availabe on the latest HPUX General
1622          * Patch Bundles. So for HPUX, we developed our version of acl_sort 
1623          * function. Because, we don't want to update to a new 
1624          * HPUX GR bundle just for aclsort() call.
1625          */
1626
1627         struct hpux_acl_types acl_obj_count;
1628         int n_class_obj_perm = 0;
1629         int i, j;
1630  
1631         if(!acl_count) {
1632                 DEBUG(10,("Zero acl count passed. Returning Success\n"));
1633                 return 0;
1634         }
1635
1636         if(aclp == NULL) {
1637                 DEBUG(0,("Null ACL pointer in hpux_acl_sort. Returning Failure. \n"));
1638                 return -1;
1639         }
1640
1641         /* Count different types of ACLs in the ACLs array */
1642
1643         hpux_count_obj(acl_count, aclp, &acl_obj_count);
1644
1645         /* There should be only one entry each of type USER_OBJ, GROUP_OBJ, 
1646          * CLASS_OBJ and OTHER_OBJ 
1647          */
1648
1649         if( (acl_obj_count.n_user_obj  != 1) || 
1650                 (acl_obj_count.n_group_obj != 1) || 
1651                 (acl_obj_count.n_class_obj != 1) ||
1652                 (acl_obj_count.n_other_obj != 1) 
1653         ) {
1654                 DEBUG(0,("hpux_acl_sort: More than one entry or no entries for \
1655 USER OBJ or GROUP_OBJ or OTHER_OBJ or CLASS_OBJ\n"));
1656                 return -1;
1657         }
1658
1659         /* If any of the default objects are present, there should be only
1660          * one of them each.
1661          */
1662
1663         if( (acl_obj_count.n_def_user_obj  > 1) || (acl_obj_count.n_def_group_obj > 1) || 
1664                         (acl_obj_count.n_def_other_obj > 1) || (acl_obj_count.n_def_class_obj > 1) ) {
1665                 DEBUG(0,("hpux_acl_sort: More than one entry for DEF_CLASS_OBJ \
1666 or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
1667                 return -1;
1668         }
1669
1670         /* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl 
1671          * structures.  
1672          *
1673          * Sorting crieteria - First sort by ACL type. If there are multiple entries of
1674          * same ACL type, sort by ACL id.
1675          *
1676          * I am using the trival kind of sorting method here because, performance isn't 
1677          * really effected by the ACLs feature. More over there aren't going to be more
1678          * than 17 entries on HPUX. 
1679          */
1680
1681         for(i=0; i<acl_count;i++) {
1682                 for (j=i+1; j<acl_count; j++) {
1683                         if( aclp[i].a_type > aclp[j].a_type ) {
1684                                 /* ACL entries out of order, swap them */
1685
1686                                 hpux_swap_acl_entries((aclp+i), (aclp+j));
1687
1688                         } else if ( aclp[i].a_type == aclp[j].a_type ) {
1689
1690                                 /* ACL entries of same type, sort by id */
1691
1692                                 if(aclp[i].a_id > aclp[j].a_id) {
1693                                         hpux_swap_acl_entries((aclp+i), (aclp+j));
1694                                 } else if (aclp[i].a_id == aclp[j].a_id) {
1695                                         /* We have a duplicate entry. */
1696                                         if(hpux_prohibited_duplicate_type(aclp[i].a_type)) {
1697                                                 DEBUG(0, ("hpux_acl_sort: Duplicate entry: Type(hex): %x Id: %d\n",
1698                                                         aclp[i].a_type, aclp[i].a_id));
1699                                                 return -1;
1700                                         }
1701                                 }
1702
1703                         }
1704                 }
1705         }
1706
1707         /* set the class obj permissions to the computed one. */
1708         if(calclass) {
1709                 int n_class_obj_index = -1;
1710
1711                 for(i=0;i<acl_count;i++) {
1712                         n_class_obj_perm |= hpux_get_needed_class_perm((aclp+i));
1713
1714                         if(aclp[i].a_type == CLASS_OBJ)
1715                                 n_class_obj_index = i;
1716                 }
1717                 aclp[n_class_obj_index].a_perm = n_class_obj_perm;
1718         }
1719
1720         return 0;
1721 #else
1722         return aclsort(acl_count, calclass, aclp);
1723 #endif
1724 }
1725
1726 /*
1727  * sort the ACL and check it for validity
1728  *
1729  * if it's a minimal ACL with only 4 entries then we
1730  * need to recalculate the mask permissions to make
1731  * sure that they are the same as the GROUP_OBJ
1732  * permissions as required by the UnixWare acl() system call.
1733  *
1734  * (note: since POSIX allows minimal ACLs which only contain
1735  * 3 entries - ie there is no mask entry - we should, in theory,
1736  * check for this and add a mask entry if necessary - however
1737  * we "know" that the caller of this interface always specifies
1738  * a mask so, in practice "this never happens" (tm) - if it *does*
1739  * happen aclsort() will fail and return an error and someone will
1740  * have to fix it ...)
1741  */
1742
1743 static int acl_sort(SMB_ACL_T acl_d)
1744 {
1745         int fixmask = (acl_d->count <= 4);
1746
1747         if (hpux_acl_sort(acl_d->count, fixmask, acl_d->acl) != 0) {
1748                 errno = EINVAL;
1749                 return -1;
1750         }
1751         return 0;
1752 }
1753  
1754 int sys_acl_valid(SMB_ACL_T acl_d)
1755 {
1756         return acl_sort(acl_d);
1757 }
1758
1759 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
1760 {
1761         struct stat     s;
1762         struct acl      *acl_p;
1763         int             acl_count;
1764         struct acl      *acl_buf        = NULL;
1765         int             ret;
1766
1767         if(hpux_acl_call_presence() == False) {
1768                 /* Looks like we don't have the acl() system call on HPUX. 
1769                  * May be the system doesn't have the latest version of JFS.
1770                  */
1771                 errno=ENOSYS;
1772                 return -1; 
1773         }
1774
1775         if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
1776                 errno = EINVAL;
1777                 return -1;
1778         }
1779
1780         if (acl_sort(acl_d) != 0) {
1781                 return -1;
1782         }
1783
1784         acl_p           = &acl_d->acl[0];
1785         acl_count       = acl_d->count;
1786
1787         /*
1788          * if it's a directory there is extra work to do
1789          * since the acl() system call will replace both
1790          * the access ACLs and the default ACLs (if any)
1791          */
1792         if (stat(name, &s) != 0) {
1793                 return -1;
1794         }
1795         if (S_ISDIR(s.st_mode)) {
1796                 SMB_ACL_T       acc_acl;
1797                 SMB_ACL_T       def_acl;
1798                 SMB_ACL_T       tmp_acl;
1799                 int             i;
1800
1801                 if (type == SMB_ACL_TYPE_ACCESS) {
1802                         acc_acl = acl_d;
1803                         def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
1804
1805                 } else {
1806                         def_acl = acl_d;
1807                         acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
1808                 }
1809
1810                 if (tmp_acl == NULL) {
1811                         return -1;
1812                 }
1813
1814                 /*
1815                  * allocate a temporary buffer for the complete ACL
1816                  */
1817                 acl_count = acc_acl->count + def_acl->count;
1818                 acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count);
1819
1820                 if (acl_buf == NULL) {
1821                         sys_acl_free_acl(tmp_acl);
1822                         errno = ENOMEM;
1823                         return -1;
1824                 }
1825
1826                 /*
1827                  * copy the access control and default entries into the buffer
1828                  */
1829                 memcpy(&acl_buf[0], &acc_acl->acl[0],
1830                         acc_acl->count * sizeof(acl_buf[0]));
1831
1832                 memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
1833                         def_acl->count * sizeof(acl_buf[0]));
1834
1835                 /*
1836                  * set the ACL_DEFAULT flag on the default entries
1837                  */
1838                 for (i = acc_acl->count; i < acl_count; i++) {
1839                         acl_buf[i].a_type |= ACL_DEFAULT;
1840                 }
1841
1842                 sys_acl_free_acl(tmp_acl);
1843
1844         } else if (type != SMB_ACL_TYPE_ACCESS) {
1845                 errno = EINVAL;
1846                 return -1;
1847         }
1848
1849         ret = acl(name, ACL_SET, acl_count, acl_p);
1850
1851         if (acl_buf) {
1852                 free(acl_buf);
1853         }
1854
1855         return ret;
1856 }
1857
1858 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
1859 {
1860         /*
1861          * HPUX doesn't have the facl call. Fake it using the path.... JRA.
1862          */
1863
1864         files_struct *fsp = file_find_fd(fd);
1865
1866         if (fsp == NULL) {
1867                 errno = EBADF;
1868                 return NULL;
1869         }
1870
1871         if (acl_sort(acl_d) != 0) {
1872                 return -1;
1873         }
1874
1875         /*
1876          * We know we're in the same conn context. So we
1877          * can use the relative path.
1878          */
1879
1880         return sys_acl_set_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS, acl_d);
1881 }
1882
1883 int sys_acl_delete_def_file(const char *path)
1884 {
1885         SMB_ACL_T       acl_d;
1886         int             ret;
1887
1888         /*
1889          * fetching the access ACL and rewriting it has
1890          * the effect of deleting the default ACL
1891          */
1892         if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
1893                 return -1;
1894         }
1895
1896         ret = acl(path, ACL_SET, acl_d->count, acl_d->acl);
1897
1898         sys_acl_free_acl(acl_d);
1899         
1900         return ret;
1901 }
1902
1903 int sys_acl_free_text(char *text)
1904 {
1905         free(text);
1906         return 0;
1907 }
1908
1909 int sys_acl_free_acl(SMB_ACL_T acl_d) 
1910 {
1911         free(acl_d);
1912         return 0;
1913 }
1914
1915 int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
1916 {
1917         return 0;
1918 }
1919
1920 #elif defined(HAVE_IRIX_ACLS)
1921
1922 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
1923 {
1924         if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
1925                 errno = EINVAL;
1926                 return -1;
1927         }
1928
1929         if (entry_p == NULL) {
1930                 errno = EINVAL;
1931                 return -1;
1932         }
1933
1934         if (entry_id == SMB_ACL_FIRST_ENTRY) {
1935                 acl_d->next = 0;
1936         }
1937
1938         if (acl_d->next < 0) {
1939                 errno = EINVAL;
1940                 return -1;
1941         }
1942
1943         if (acl_d->next >= acl_d->aclp->acl_cnt) {
1944                 return 0;
1945         }
1946
1947         *entry_p = &acl_d->aclp->acl_entry[acl_d->next++];
1948
1949         return 1;
1950 }
1951
1952 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
1953 {
1954         *type_p = entry_d->ae_tag;
1955
1956         return 0;
1957 }
1958
1959 int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
1960 {
1961         *permset_p = entry_d;
1962
1963         return 0;
1964 }
1965
1966 void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
1967 {
1968         if (entry_d->ae_tag != SMB_ACL_USER
1969             && entry_d->ae_tag != SMB_ACL_GROUP) {
1970                 errno = EINVAL;
1971                 return NULL;
1972         }
1973
1974         return &entry_d->ae_id;
1975 }
1976
1977 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
1978 {
1979         SMB_ACL_T       a;
1980
1981         if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
1982                 errno = ENOMEM;
1983                 return NULL;
1984         }
1985         if ((a->aclp = acl_get_file(path_p, type)) == NULL) {
1986                 SAFE_FREE(a);
1987                 return NULL;
1988         }
1989         a->next = -1;
1990         a->freeaclp = True;
1991         return a;
1992 }
1993
1994 SMB_ACL_T sys_acl_get_fd(int fd)
1995 {
1996         SMB_ACL_T       a;
1997
1998         if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
1999                 errno = ENOMEM;
2000                 return NULL;
2001         }
2002         if ((a->aclp = acl_get_fd(fd)) == NULL) {
2003                 SAFE_FREE(a);
2004                 return NULL;
2005         }
2006         a->next = -1;
2007         a->freeaclp = True;
2008         return a;
2009 }
2010
2011 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
2012 {
2013         permset_d->ae_perm = 0;
2014
2015         return 0;
2016 }
2017
2018 int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
2019 {
2020         if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
2021             && perm != SMB_ACL_EXECUTE) {
2022                 errno = EINVAL;
2023                 return -1;
2024         }
2025
2026         if (permset_d == NULL) {
2027                 errno = EINVAL;
2028                 return -1;
2029         }
2030
2031         permset_d->ae_perm |= perm;
2032
2033         return 0;
2034 }
2035
2036 int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
2037 {
2038         return permset_d->ae_perm & perm;
2039 }
2040
2041 char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
2042 {
2043         return acl_to_text(acl_d->aclp, len_p);
2044 }
2045
2046 SMB_ACL_T sys_acl_init(int count)
2047 {
2048         SMB_ACL_T       a;
2049
2050         if (count < 0) {
2051                 errno = EINVAL;
2052                 return NULL;
2053         }
2054
2055         if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + sizeof(struct acl))) == NULL) {
2056                 errno = ENOMEM;
2057                 return NULL;
2058         }
2059
2060         a->next = -1;
2061         a->freeaclp = False;
2062         a->aclp = (struct acl *)(&a->aclp + sizeof(struct acl *));
2063         a->aclp->acl_cnt = 0;
2064
2065         return a;
2066 }
2067
2068
2069 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
2070 {
2071         SMB_ACL_T       acl_d;
2072         SMB_ACL_ENTRY_T entry_d;
2073
2074         if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
2075                 errno = EINVAL;
2076                 return -1;
2077         }
2078
2079         if (acl_d->aclp->acl_cnt >= ACL_MAX_ENTRIES) {
2080                 errno = ENOSPC;
2081                 return -1;
2082         }
2083
2084         entry_d         = &acl_d->aclp->acl_entry[acl_d->aclp->acl_cnt++];
2085         entry_d->ae_tag = 0;
2086         entry_d->ae_id  = 0;
2087         entry_d->ae_perm        = 0;
2088         *entry_p        = entry_d;
2089
2090         return 0;
2091 }
2092
2093 int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
2094 {
2095         switch (tag_type) {
2096                 case SMB_ACL_USER:
2097                 case SMB_ACL_USER_OBJ:
2098                 case SMB_ACL_GROUP:
2099                 case SMB_ACL_GROUP_OBJ:
2100                 case SMB_ACL_OTHER:
2101                 case SMB_ACL_MASK:
2102                         entry_d->ae_tag = tag_type;
2103                         break;
2104                 default:
2105                         errno = EINVAL;
2106                         return -1;
2107         }
2108
2109         return 0;
2110 }
2111
2112 int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
2113 {
2114         if (entry_d->ae_tag != SMB_ACL_GROUP
2115             && entry_d->ae_tag != SMB_ACL_USER) {
2116                 errno = EINVAL;
2117                 return -1;
2118         }
2119
2120         entry_d->ae_id = *((id_t *)qual_p);
2121
2122         return 0;
2123 }
2124
2125 int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
2126 {
2127         if (permset_d->ae_perm & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
2128                 return EINVAL;
2129         }
2130
2131         entry_d->ae_perm = permset_d->ae_perm;
2132
2133         return 0;
2134 }
2135
2136 int sys_acl_valid(SMB_ACL_T acl_d)
2137 {
2138         return acl_valid(acl_d->aclp);
2139 }
2140
2141 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
2142 {
2143         return acl_set_file(name, type, acl_d->aclp);
2144 }
2145
2146 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
2147 {
2148         return acl_set_fd(fd, acl_d->aclp);
2149 }
2150
2151 int sys_acl_delete_def_file(const char *name)
2152 {
2153         return acl_delete_def_file(name);
2154 }
2155
2156 int sys_acl_free_text(char *text)
2157 {
2158         return acl_free(text);
2159 }
2160
2161 int sys_acl_free_acl(SMB_ACL_T acl_d) 
2162 {
2163         if (acl_d->freeaclp) {
2164                 acl_free(acl_d->aclp);
2165         }
2166         acl_free(acl_d);
2167         return 0;
2168 }
2169
2170 int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
2171 {
2172         return 0;
2173 }
2174
2175 #elif defined(HAVE_AIX_ACLS)
2176
2177 /* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
2178
2179 int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
2180 {
2181         struct acl_entry_link *link;
2182         struct new_acl_entry *entry;
2183         int keep_going;
2184
2185         DEBUG(10,("This is the count: %d\n",theacl->count));
2186
2187         /* Check if count was previously set to -1. *
2188          * If it was, that means we reached the end *
2189          * of the acl last time.                    */
2190         if(theacl->count == -1)
2191                 return(0);
2192
2193         link = theacl;
2194         /* To get to the next acl, traverse linked list until index *
2195          * of acl matches the count we are keeping.  This count is  *
2196          * incremented each time we return an acl entry.            */
2197
2198         for(keep_going = 0; keep_going < theacl->count; keep_going++)
2199                 link = link->nextp;
2200
2201         entry = *entry_p =  link->entryp;
2202
2203         DEBUG(10,("*entry_p is %d\n",entry_p));
2204         DEBUG(10,("*entry_p->ace_access is %d\n",entry->ace_access));
2205
2206         /* Increment count */
2207         theacl->count++;
2208         if(link->nextp == NULL)
2209                 theacl->count = -1;
2210
2211         return(1);
2212 }
2213
2214 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
2215 {
2216         /* Initialize tag type */
2217
2218         *tag_type_p = -1;
2219         DEBUG(10,("the tagtype is %d\n",entry_d->ace_id->id_type));
2220
2221         /* Depending on what type of entry we have, *
2222          * return tag type.                         */
2223         switch(entry_d->ace_id->id_type) {
2224         case ACEID_USER:
2225                 *tag_type_p = SMB_ACL_USER;
2226                 break;
2227         case ACEID_GROUP:
2228                 *tag_type_p = SMB_ACL_GROUP;
2229                 break;
2230
2231         case SMB_ACL_USER_OBJ:
2232         case SMB_ACL_GROUP_OBJ:
2233         case SMB_ACL_OTHER:
2234                 *tag_type_p = entry_d->ace_id->id_type;
2235                 break;
2236  
2237         default:
2238                 return(-1);
2239         }
2240
2241         return(0);
2242 }
2243
2244 int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
2245 {
2246         DEBUG(10,("Starting AIX sys_acl_get_permset\n"));
2247         *permset_p = &entry_d->ace_access;
2248         DEBUG(10,("**permset_p is %d\n",**permset_p));
2249         if(!(**permset_p & S_IXUSR) &&
2250                 !(**permset_p & S_IWUSR) &&
2251                 !(**permset_p & S_IRUSR) &&
2252                 (**permset_p != 0))
2253                         return(-1);
2254
2255         DEBUG(10,("Ending AIX sys_acl_get_permset\n"));
2256         return(0);
2257 }
2258
2259 void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
2260 {
2261         return(entry_d->ace_id->id_data);
2262 }
2263
2264 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
2265 {
2266         struct acl *file_acl = (struct acl *)NULL;
2267         struct acl_entry *acl_entry;
2268         struct new_acl_entry *new_acl_entry;
2269         struct ace_id *idp;
2270         struct acl_entry_link *acl_entry_link;
2271         struct acl_entry_link *acl_entry_link_head;
2272         int i;
2273         int rc = 0;
2274         uid_t user_id;
2275
2276         /* AIX has no DEFAULT */
2277         if  ( type == SMB_ACL_TYPE_DEFAULT )
2278                 return NULL;
2279
2280         /* Get the acl using statacl */
2281  
2282         DEBUG(10,("Entering sys_acl_get_file\n"));
2283         DEBUG(10,("path_p is %s\n",path_p));
2284
2285         file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2286  
2287         if(file_acl == NULL) {
2288                 errno=ENOMEM;
2289                 DEBUG(0,("Error in AIX sys_acl_get_file: %d\n",errno));
2290                 return(NULL);
2291         }
2292
2293         memset(file_acl,0,BUFSIZ);
2294
2295         rc = statacl((char *)path_p,0,file_acl,BUFSIZ);
2296         if(rc == -1) {
2297                 DEBUG(0,("statacl returned %d with errno %d\n",rc,errno));
2298                 SAFE_FREE(file_acl);
2299                 return(NULL);
2300         }
2301
2302         DEBUG(10,("Got facl and returned it\n"));
2303
2304         /* Point to the first acl entry in the acl */
2305         acl_entry =  file_acl->acl_ext;
2306
2307         /* Begin setting up the head of the linked list *
2308          * that will be used for the storing the acl    *
2309          * in a way that is useful for the posix_acls.c *
2310          * code.                                          */
2311
2312         acl_entry_link_head = acl_entry_link = sys_acl_init(0);
2313         if(acl_entry_link_head == NULL)
2314                 return(NULL);
2315
2316         acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2317         if(acl_entry_link->entryp == NULL) {
2318                 SAFE_FREE(file_acl);
2319                 errno = ENOMEM;
2320                 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
2321                 return(NULL);
2322         }
2323
2324         DEBUG(10,("acl_entry is %d\n",acl_entry));
2325         DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
2326
2327         /* Check if the extended acl bit is on.   *
2328          * If it isn't, do not show the           *
2329          * contents of the acl since AIX intends *
2330          * the extended info to remain unused     */
2331
2332         if(file_acl->acl_mode & S_IXACL){
2333                 /* while we are not pointing to the very end */
2334                 while(acl_entry < acl_last(file_acl)) {
2335                         /* before we malloc anything, make sure this is  */
2336                         /* a valid acl entry and one that we want to map */
2337                         idp = id_nxt(acl_entry->ace_id);
2338                         if((acl_entry->ace_type == ACC_SPECIFY ||
2339                                 (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
2340                                         acl_entry = acl_nxt(acl_entry);
2341                                         continue;
2342                         }
2343
2344                         idp = acl_entry->ace_id;
2345
2346                         /* Check if this is the first entry in the linked list. *
2347                          * The first entry needs to keep prevp pointing to NULL *
2348                          * and already has entryp allocated.                  */
2349
2350                         if(acl_entry_link_head->count != 0) {
2351                                 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2352
2353                                 if(acl_entry_link->nextp == NULL) {
2354                                         SAFE_FREE(file_acl);
2355                                         errno = ENOMEM;
2356                                         DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
2357                                         return(NULL);
2358                                 }
2359
2360                                 acl_entry_link->nextp->prevp = acl_entry_link;
2361                                 acl_entry_link = acl_entry_link->nextp;
2362                                 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2363                                 if(acl_entry_link->entryp == NULL) {
2364                                         SAFE_FREE(file_acl);
2365                                         errno = ENOMEM;
2366                                         DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
2367                                         return(NULL);
2368                                 }
2369                                 acl_entry_link->nextp = NULL;
2370                         }
2371
2372                         acl_entry_link->entryp->ace_len = acl_entry->ace_len;
2373
2374                         /* Don't really need this since all types are going *
2375                          * to be specified but, it's better than leaving it 0 */
2376
2377                         acl_entry_link->entryp->ace_type = acl_entry->ace_type;
2378  
2379                         acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2380  
2381                         memcpy(acl_entry_link->entryp->ace_id,idp,sizeof(struct ace_id));
2382
2383                         /* The access in the acl entries must be left shifted by *
2384                          * three bites, because they will ultimately be compared *
2385                          * to S_IRUSR, S_IWUSR, and S_IXUSR.                  */
2386
2387                         switch(acl_entry->ace_type){
2388                         case ACC_PERMIT:
2389                         case ACC_SPECIFY:
2390                                 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2391                                 acl_entry_link->entryp->ace_access <<= 6;
2392                                 acl_entry_link_head->count++;
2393                                 break;
2394                         case ACC_DENY:
2395                                 /* Since there is no way to return a DENY acl entry *
2396                                  * change to PERMIT and then shift.                 */
2397                                 DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
2398                                 acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
2399                                 DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
2400                                 acl_entry_link->entryp->ace_access <<= 6;
2401                                 acl_entry_link_head->count++;
2402                                 break;
2403                         default:
2404                                 return(0);
2405                         }
2406
2407                         DEBUG(10,("acl_entry = %d\n",acl_entry));
2408                         DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
2409  
2410                         acl_entry = acl_nxt(acl_entry);
2411                 }
2412         } /* end of if enabled */
2413
2414         /* Since owner, group, other acl entries are not *
2415          * part of the acl entries in an acl, they must  *
2416          * be dummied up to become part of the list.     */
2417
2418         for( i = 1; i < 4; i++) {
2419                 DEBUG(10,("i is %d\n",i));
2420                 if(acl_entry_link_head->count != 0) {
2421                         acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2422                         if(acl_entry_link->nextp == NULL) {
2423                                 SAFE_FREE(file_acl);
2424                                 errno = ENOMEM;
2425                                 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
2426                                 return(NULL);
2427                         }
2428
2429                         acl_entry_link->nextp->prevp = acl_entry_link;
2430                         acl_entry_link = acl_entry_link->nextp;
2431                         acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2432                         if(acl_entry_link->entryp == NULL) {
2433                                 SAFE_FREE(file_acl);
2434                                 errno = ENOMEM;
2435                                 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
2436                                 return(NULL);
2437                         }
2438                 }
2439
2440                 acl_entry_link->nextp = NULL;
2441
2442                 new_acl_entry = acl_entry_link->entryp;
2443                 idp = new_acl_entry->ace_id;
2444
2445                 new_acl_entry->ace_len = sizeof(struct acl_entry);
2446                 new_acl_entry->ace_type = ACC_PERMIT;
2447                 idp->id_len = sizeof(struct ace_id);
2448                 DEBUG(10,("idp->id_len = %d\n",idp->id_len));
2449                 memset(idp->id_data,0,sizeof(uid_t));
2450
2451                 switch(i) {
2452                 case 2:
2453                         new_acl_entry->ace_access = file_acl->g_access << 6;
2454                         idp->id_type = SMB_ACL_GROUP_OBJ;
2455                         break;
2456
2457                 case 3:
2458                         new_acl_entry->ace_access = file_acl->o_access << 6;
2459                         idp->id_type = SMB_ACL_OTHER;
2460                         break;
2461  
2462                 case 1:
2463                         new_acl_entry->ace_access = file_acl->u_access << 6;
2464                         idp->id_type = SMB_ACL_USER_OBJ;
2465                         break;
2466  
2467                 default:
2468                         return(NULL);
2469
2470                 }
2471
2472                 acl_entry_link_head->count++;
2473                 DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
2474         }
2475
2476         acl_entry_link_head->count = 0;
2477         SAFE_FREE(file_acl);
2478
2479         return(acl_entry_link_head);
2480 }
2481
2482 SMB_ACL_T sys_acl_get_fd(int fd)
2483 {
2484         struct acl *file_acl = (struct acl *)NULL;
2485         struct acl_entry *acl_entry;
2486         struct new_acl_entry *new_acl_entry;
2487         struct ace_id *idp;
2488         struct acl_entry_link *acl_entry_link;
2489         struct acl_entry_link *acl_entry_link_head;
2490         int i;
2491         int rc = 0;
2492         uid_t user_id;
2493
2494         /* Get the acl using fstatacl */
2495    
2496         DEBUG(10,("Entering sys_acl_get_fd\n"));
2497         DEBUG(10,("fd is %d\n",fd));
2498         file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2499
2500         if(file_acl == NULL) {
2501                 errno=ENOMEM;
2502                 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2503                 return(NULL);
2504         }
2505
2506         memset(file_acl,0,BUFSIZ);
2507
2508         rc = fstatacl(fd,0,file_acl,BUFSIZ);
2509         if(rc == -1) {
2510                 DEBUG(0,("The fstatacl call returned %d with errno %d\n",rc,errno));
2511                 SAFE_FREE(file_acl);
2512                 return(NULL);
2513         }
2514
2515         DEBUG(10,("Got facl and returned it\n"));
2516
2517         /* Point to the first acl entry in the acl */
2518
2519         acl_entry =  file_acl->acl_ext;
2520         /* Begin setting up the head of the linked list *
2521          * that will be used for the storing the acl    *
2522          * in a way that is useful for the posix_acls.c *
2523          * code.                                        */
2524
2525         acl_entry_link_head = acl_entry_link = sys_acl_init(0);
2526         if(acl_entry_link_head == NULL){
2527                 SAFE_FREE(file_acl);
2528                 return(NULL);
2529         }
2530
2531         acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2532
2533         if(acl_entry_link->entryp == NULL) {
2534                 errno = ENOMEM;
2535                 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2536                 SAFE_FREE(file_acl);
2537                 return(NULL);
2538         }
2539
2540         DEBUG(10,("acl_entry is %d\n",acl_entry));
2541         DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
2542  
2543         /* Check if the extended acl bit is on.   *
2544          * If it isn't, do not show the           *
2545          * contents of the acl since AIX intends  *
2546          * the extended info to remain unused     */
2547  
2548         if(file_acl->acl_mode & S_IXACL){
2549                 /* while we are not pointing to the very end */
2550                 while(acl_entry < acl_last(file_acl)) {
2551                         /* before we malloc anything, make sure this is  */
2552                         /* a valid acl entry and one that we want to map */
2553
2554                         idp = id_nxt(acl_entry->ace_id);
2555                         if((acl_entry->ace_type == ACC_SPECIFY ||
2556                                 (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
2557                                         acl_entry = acl_nxt(acl_entry);
2558                                         continue;
2559                         }
2560
2561                         idp = acl_entry->ace_id;
2562  
2563                         /* Check if this is the first entry in the linked list. *
2564                          * The first entry needs to keep prevp pointing to NULL *
2565                          * and already has entryp allocated.                 */
2566
2567                         if(acl_entry_link_head->count != 0) {
2568                                 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2569                                 if(acl_entry_link->nextp == NULL) {
2570                                         errno = ENOMEM;
2571                                         DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2572                                         SAFE_FREE(file_acl);
2573                                         return(NULL);
2574                                 }
2575                                 acl_entry_link->nextp->prevp = acl_entry_link;
2576                                 acl_entry_link = acl_entry_link->nextp;
2577                                 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2578                                 if(acl_entry_link->entryp == NULL) {
2579                                         errno = ENOMEM;
2580                                         DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2581                                         SAFE_FREE(file_acl);
2582                                         return(NULL);
2583                                 }
2584
2585                                 acl_entry_link->nextp = NULL;
2586                         }
2587
2588                         acl_entry_link->entryp->ace_len = acl_entry->ace_len;
2589
2590                         /* Don't really need this since all types are going *
2591                          * to be specified but, it's better than leaving it 0 */
2592
2593                         acl_entry_link->entryp->ace_type = acl_entry->ace_type;
2594                         acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2595
2596                         memcpy(acl_entry_link->entryp->ace_id, idp, sizeof(struct ace_id));
2597
2598                         /* The access in the acl entries must be left shifted by *
2599                          * three bites, because they will ultimately be compared *
2600                          * to S_IRUSR, S_IWUSR, and S_IXUSR.                  */
2601
2602                         switch(acl_entry->ace_type){
2603                         case ACC_PERMIT:
2604                         case ACC_SPECIFY:
2605                                 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2606                                 acl_entry_link->entryp->ace_access <<= 6;
2607                                 acl_entry_link_head->count++;
2608                                 break;
2609                         case ACC_DENY:
2610                                 /* Since there is no way to return a DENY acl entry *
2611                                  * change to PERMIT and then shift.                 */
2612                                 DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
2613                                 acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
2614                                 DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
2615                                 acl_entry_link->entryp->ace_access <<= 6;
2616                                 acl_entry_link_head->count++;
2617                                 break;
2618                         default:
2619                                 return(0);
2620                         }
2621
2622                         DEBUG(10,("acl_entry = %d\n",acl_entry));
2623                         DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
2624  
2625                         acl_entry = acl_nxt(acl_entry);
2626                 }
2627         } /* end of if enabled */
2628
2629         /* Since owner, group, other acl entries are not *
2630          * part of the acl entries in an acl, they must  *
2631          * be dummied up to become part of the list.     */
2632
2633         for( i = 1; i < 4; i++) {
2634                 DEBUG(10,("i is %d\n",i));
2635                 if(acl_entry_link_head->count != 0){
2636                         acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2637                         if(acl_entry_link->nextp == NULL) {
2638                                 errno = ENOMEM;
2639                                 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2640                                 SAFE_FREE(file_acl);
2641                                 return(NULL);
2642                         }
2643
2644                         acl_entry_link->nextp->prevp = acl_entry_link;
2645                         acl_entry_link = acl_entry_link->nextp;
2646                         acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2647
2648                         if(acl_entry_link->entryp == NULL) {
2649                                 SAFE_FREE(file_acl);
2650                                 errno = ENOMEM;
2651                                 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2652                                 return(NULL);
2653                         }
2654                 }
2655
2656                 acl_entry_link->nextp = NULL;
2657  
2658                 new_acl_entry = acl_entry_link->entryp;
2659                 idp = new_acl_entry->ace_id;
2660  
2661                 new_acl_entry->ace_len = sizeof(struct acl_entry);
2662                 new_acl_entry->ace_type = ACC_PERMIT;
2663                 idp->id_len = sizeof(struct ace_id);
2664                 DEBUG(10,("idp->id_len = %d\n",idp->id_len));
2665                 memset(idp->id_data,0,sizeof(uid_t));
2666  
2667                 switch(i) {
2668                 case 2:
2669                         new_acl_entry->ace_access = file_acl->g_access << 6;
2670                         idp->id_type = SMB_ACL_GROUP_OBJ;
2671                         break;
2672  
2673                 case 3:
2674                         new_acl_entry->ace_access = file_acl->o_access << 6;
2675                         idp->id_type = SMB_ACL_OTHER;
2676                         break;
2677  
2678                 case 1:
2679                         new_acl_entry->ace_access = file_acl->u_access << 6;
2680                         idp->id_type = SMB_ACL_USER_OBJ;
2681                         break;
2682  
2683                 default:
2684                         return(NULL);
2685                 }
2686  
2687                 acl_entry_link_head->count++;
2688                 DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
2689         }
2690
2691         acl_entry_link_head->count = 0;
2692         SAFE_FREE(file_acl);
2693  
2694         return(acl_entry_link_head);
2695 }
2696
2697 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
2698 {
2699         *permset = *permset & ~0777;
2700         return(0);
2701 }
2702
2703 int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
2704 {
2705         if((perm != 0) &&
2706                         (perm & (S_IXUSR | S_IWUSR | S_IRUSR)) == 0)
2707                 return(-1);
2708
2709         *permset |= perm;
2710         DEBUG(10,("This is the permset now: %d\n",*permset));
2711         return(0);
2712 }
2713
2714 char *sys_acl_to_text( SMB_ACL_T theacl, ssize_t *plen)
2715 {
2716         return(NULL);
2717 }
2718
2719 SMB_ACL_T sys_acl_init( int count)
2720 {
2721         struct acl_entry_link *theacl = NULL;
2722  
2723         DEBUG(10,("Entering sys_acl_init\n"));
2724
2725         theacl = SMB_MALLOC_P(struct acl_entry_link);
2726         if(theacl == NULL) {
2727                 errno = ENOMEM;
2728                 DEBUG(0,("Error in sys_acl_init is %d\n",errno));
2729                 return(NULL);
2730         }
2731
2732         theacl->count = 0;
2733         theacl->nextp = NULL;
2734         theacl->prevp = NULL;
2735         theacl->entryp = NULL;
2736         DEBUG(10,("Exiting sys_acl_init\n"));
2737         return(theacl);
2738 }
2739
2740 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
2741 {
2742         struct acl_entry_link *theacl;
2743         struct acl_entry_link *acl_entryp;
2744         struct acl_entry_link *temp_entry;
2745         int counting;
2746
2747         DEBUG(10,("Entering the sys_acl_create_entry\n"));
2748
2749         theacl = acl_entryp = *pacl;
2750
2751         /* Get to the end of the acl before adding entry */
2752
2753         for(counting=0; counting < theacl->count; counting++){
2754                 DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
2755                 temp_entry = acl_entryp;
2756                 acl_entryp = acl_entryp->nextp;
2757         }
2758
2759         if(theacl->count != 0){
2760                 temp_entry->nextp = acl_entryp = SMB_MALLOC_P(struct acl_entry_link);
2761                 if(acl_entryp == NULL) {
2762                         errno = ENOMEM;
2763                         DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
2764                         return(-1);
2765                 }
2766
2767                 DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
2768                 acl_entryp->prevp = temp_entry;
2769                 DEBUG(10,("The acl_entryp->prevp is %d\n",acl_entryp->prevp));
2770         }
2771
2772         *pentry = acl_entryp->entryp = SMB_MALLOC_P(struct new_acl_entry);
2773         if(*pentry == NULL) {
2774                 errno = ENOMEM;
2775                 DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
2776                 return(-1);
2777         }
2778
2779         memset(*pentry,0,sizeof(struct new_acl_entry));
2780         acl_entryp->entryp->ace_len = sizeof(struct acl_entry);
2781         acl_entryp->entryp->ace_type = ACC_PERMIT;
2782         acl_entryp->entryp->ace_id->id_len = sizeof(struct ace_id);
2783         acl_entryp->nextp = NULL;
2784         theacl->count++;
2785         DEBUG(10,("Exiting sys_acl_create_entry\n"));
2786         return(0);
2787 }
2788
2789 int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
2790 {
2791         DEBUG(10,("Starting AIX sys_acl_set_tag_type\n"));
2792         entry->ace_id->id_type = tagtype;
2793         DEBUG(10,("The tag type is %d\n",entry->ace_id->id_type));
2794         DEBUG(10,("Ending AIX sys_acl_set_tag_type\n"));
2795 }
2796
2797 int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
2798 {
2799         DEBUG(10,("Starting AIX sys_acl_set_qualifier\n"));
2800         memcpy(entry->ace_id->id_data,qual,sizeof(uid_t));
2801         DEBUG(10,("Ending AIX sys_acl_set_qualifier\n"));
2802         return(0);
2803 }
2804
2805 int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
2806 {
2807         DEBUG(10,("Starting AIX sys_acl_set_permset\n"));
2808         if(!(*permset & S_IXUSR) &&
2809                 !(*permset & S_IWUSR) &&
2810                 !(*permset & S_IRUSR) &&
2811                 (*permset != 0))
2812                         return(-1);
2813
2814         entry->ace_access = *permset;
2815         DEBUG(10,("entry->ace_access = %d\n",entry->ace_access));
2816         DEBUG(10,("Ending AIX sys_acl_set_permset\n"));
2817         return(0);
2818 }
2819
2820 int sys_acl_valid( SMB_ACL_T theacl )
2821 {
2822         int user_obj = 0;
2823         int group_obj = 0;
2824         int other_obj = 0;
2825         struct acl_entry_link *acl_entry;
2826
2827         for(acl_entry=theacl; acl_entry != NULL; acl_entry = acl_entry->nextp) {
2828                 user_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_USER_OBJ);
2829                 group_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_GROUP_OBJ);
2830                 other_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_OTHER);
2831         }
2832
2833         DEBUG(10,("user_obj=%d, group_obj=%d, other_obj=%d\n",user_obj,group_obj,other_obj));
2834  
2835         if(user_obj != 1 || group_obj != 1 || other_obj != 1)
2836                 return(-1); 
2837
2838         return(0);
2839 }
2840
2841 int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2842 {
2843         struct acl_entry_link *acl_entry_link = NULL;
2844         struct acl *file_acl = NULL;
2845         struct acl *file_acl_temp = NULL;
2846         struct acl_entry *acl_entry = NULL;
2847         struct ace_id *ace_id = NULL;
2848         uint id_type;
2849         uint ace_access;
2850         uint user_id;
2851         uint acl_length;
2852         uint rc;
2853
2854         DEBUG(10,("Entering sys_acl_set_file\n"));
2855         DEBUG(10,("File name is %s\n",name));
2856  
2857         /* AIX has no default ACL */
2858         if(acltype == SMB_ACL_TYPE_DEFAULT)
2859                 return(0);
2860
2861         acl_length = BUFSIZ;
2862         file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2863
2864         if(file_acl == NULL) {
2865                 errno = ENOMEM;
2866                 DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
2867                 return(-1);
2868         }
2869
2870         memset(file_acl,0,BUFSIZ);
2871
2872         file_acl->acl_len = ACL_SIZ;
2873         file_acl->acl_mode = S_IXACL;
2874
2875         for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
2876                 acl_entry_link->entryp->ace_access >>= 6;
2877                 id_type = acl_entry_link->entryp->ace_id->id_type;
2878
2879                 switch(id_type) {
2880                 case SMB_ACL_USER_OBJ:
2881                         file_acl->u_access = acl_entry_link->entryp->ace_access;
2882                         continue;
2883                 case SMB_ACL_GROUP_OBJ:
2884                         file_acl->g_access = acl_entry_link->entryp->ace_access;
2885                         continue;
2886                 case SMB_ACL_OTHER:
2887                         file_acl->o_access = acl_entry_link->entryp->ace_access;
2888                         continue;
2889                 case SMB_ACL_MASK:
2890                         continue;
2891                 }
2892
2893                 if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
2894                         acl_length += sizeof(struct acl_entry);
2895                         file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
2896                         if(file_acl_temp == NULL) {
2897                                 SAFE_FREE(file_acl);
2898                                 errno = ENOMEM;
2899                                 DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
2900                                 return(-1);
2901                         }  
2902
2903                         memcpy(file_acl_temp,file_acl,file_acl->acl_len);
2904                         SAFE_FREE(file_acl);
2905                         file_acl = file_acl_temp;
2906                 }
2907
2908                 acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
2909                 file_acl->acl_len += sizeof(struct acl_entry);
2910                 acl_entry->ace_len = acl_entry_link->entryp->ace_len;
2911                 acl_entry->ace_access = acl_entry_link->entryp->ace_access;
2912  
2913                 /* In order to use this, we'll need to wait until we can get denies */
2914                 /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
2915                 acl_entry->ace_type = ACC_SPECIFY; */
2916
2917                 acl_entry->ace_type = ACC_SPECIFY;
2918  
2919                 ace_id = acl_entry->ace_id;
2920  
2921                 ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
2922                 DEBUG(10,("The id type is %d\n",ace_id->id_type));
2923                 ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
2924                 memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
2925                 memcpy(acl_entry->ace_id->id_data, &user_id, sizeof(uid_t));
2926         }
2927
2928         rc = chacl(name,file_acl,file_acl->acl_len);
2929         DEBUG(10,("errno is %d\n",errno));
2930         DEBUG(10,("return code is %d\n",rc));
2931         SAFE_FREE(file_acl);
2932         DEBUG(10,("Exiting the sys_acl_set_file\n"));
2933         return(rc);
2934 }
2935
2936 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
2937 {
2938         struct acl_entry_link *acl_entry_link = NULL;
2939         struct acl *file_acl = NULL;
2940         struct acl *file_acl_temp = NULL;
2941         struct acl_entry *acl_entry = NULL;
2942         struct ace_id *ace_id = NULL;
2943         uint id_type;
2944         uint user_id;
2945         uint acl_length;
2946         uint rc;
2947  
2948         DEBUG(10,("Entering sys_acl_set_fd\n"));
2949         acl_length = BUFSIZ;
2950         file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2951
2952         if(file_acl == NULL) {
2953                 errno = ENOMEM;
2954                 DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
2955                 return(-1);
2956         }
2957
2958         memset(file_acl,0,BUFSIZ);
2959  
2960         file_acl->acl_len = ACL_SIZ;
2961         file_acl->acl_mode = S_IXACL;
2962
2963         for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
2964                 acl_entry_link->entryp->ace_access >>= 6;
2965                 id_type = acl_entry_link->entryp->ace_id->id_type;
2966                 DEBUG(10,("The id_type is %d\n",id_type));
2967
2968                 switch(id_type) {
2969                 case SMB_ACL_USER_OBJ:
2970                         file_acl->u_access = acl_entry_link->entryp->ace_access;
2971                         continue;
2972                 case SMB_ACL_GROUP_OBJ:
2973                         file_acl->g_access = acl_entry_link->entryp->ace_access;
2974                         continue;
2975                 case SMB_ACL_OTHER:
2976                         file_acl->o_access = acl_entry_link->entryp->ace_access;
2977                         continue;
2978                 case SMB_ACL_MASK:
2979                         continue;
2980                 }
2981
2982                 if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
2983                         acl_length += sizeof(struct acl_entry);
2984                         file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
2985                         if(file_acl_temp == NULL) {
2986                                 SAFE_FREE(file_acl);
2987                                 errno = ENOMEM;
2988                                 DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
2989                                 return(-1);
2990                         }
2991
2992                         memcpy(file_acl_temp,file_acl,file_acl->acl_len);
2993                         SAFE_FREE(file_acl);
2994                         file_acl = file_acl_temp;
2995                 }
2996
2997                 acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
2998                 file_acl->acl_len += sizeof(struct acl_entry);
2999                 acl_entry->ace_len = acl_entry_link->entryp->ace_len;
3000                 acl_entry->ace_access = acl_entry_link->entryp->ace_access;
3001  
3002                 /* In order to use this, we'll need to wait until we can get denies */
3003                 /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
3004                         acl_entry->ace_type = ACC_SPECIFY; */
3005  
3006                 acl_entry->ace_type = ACC_SPECIFY;
3007  
3008                 ace_id = acl_entry->ace_id;
3009  
3010                 ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
3011                 DEBUG(10,("The id type is %d\n",ace_id->id_type));
3012                 ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
3013                 memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
3014                 memcpy(ace_id->id_data, &user_id, sizeof(uid_t));
3015         }
3016  
3017         rc = fchacl(fd,file_acl,file_acl->acl_len);
3018         DEBUG(10,("errno is %d\n",errno));
3019         DEBUG(10,("return code is %d\n",rc));
3020         SAFE_FREE(file_acl);
3021         DEBUG(10,("Exiting sys_acl_set_fd\n"));
3022         return(rc);
3023 }
3024
3025 int sys_acl_delete_def_file(const char *name)
3026 {
3027         /* AIX has no default ACL */
3028         return 0;
3029 }
3030
3031 int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
3032 {
3033         return(*permset & perm);
3034 }
3035
3036 int sys_acl_free_text(char *text)
3037 {
3038         return(0);
3039 }
3040
3041 int sys_acl_free_acl(SMB_ACL_T posix_acl)
3042 {
3043         struct acl_entry_link *acl_entry_link;
3044
3045         for(acl_entry_link = posix_acl->nextp; acl_entry_link->nextp != NULL; acl_entry_link = acl_entry_link->nextp) {
3046                 SAFE_FREE(acl_entry_link->prevp->entryp);
3047                 SAFE_FREE(acl_entry_link->prevp);
3048         }
3049
3050         SAFE_FREE(acl_entry_link->prevp->entryp);
3051         SAFE_FREE(acl_entry_link->prevp);
3052         SAFE_FREE(acl_entry_link->entryp);
3053         SAFE_FREE(acl_entry_link);
3054  
3055         return(0);
3056 }
3057
3058 int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
3059 {
3060         return(0);
3061 }
3062
3063 #else /* No ACLs. */
3064
3065 int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
3066 {
3067         errno = ENOSYS;
3068         return -1;
3069 }
3070
3071 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
3072 {
3073         errno = ENOSYS;
3074         return -1;
3075 }
3076
3077 int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
3078 {
3079         errno = ENOSYS;
3080         return -1;
3081 }
3082
3083 void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
3084 {
3085         errno = ENOSYS;
3086         return NULL;
3087 }
3088
3089 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
3090 {
3091         errno = ENOSYS;
3092         return (SMB_ACL_T)NULL;
3093 }
3094
3095 SMB_ACL_T sys_acl_get_fd(int fd)
3096 {
3097         errno = ENOSYS;
3098         return (SMB_ACL_T)NULL;
3099 }
3100
3101 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
3102 {
3103         errno = ENOSYS;
3104         return -1;
3105 }
3106
3107 int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
3108 {
3109         errno = ENOSYS;
3110         return -1;
3111 }
3112
3113 int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
3114 {
3115         errno = ENOSYS;
3116         return (permset & perm) ? 1 : 0;
3117 }
3118
3119 char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
3120 {
3121         errno = ENOSYS;
3122         return NULL;
3123 }
3124
3125 int sys_acl_free_text(char *text)
3126 {
3127         errno = ENOSYS;
3128         return -1;
3129 }
3130
3131 SMB_ACL_T sys_acl_init( int count)
3132 {
3133         errno = ENOSYS;
3134         return NULL;
3135 }
3136
3137 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
3138 {
3139         errno = ENOSYS;
3140         return -1;
3141 }
3142
3143 int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
3144 {
3145         errno = ENOSYS;
3146         return -1;
3147 }
3148
3149 int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
3150 {
3151         errno = ENOSYS;
3152         return -1;
3153 }
3154
3155 int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
3156 {
3157         errno = ENOSYS;
3158         return -1;
3159 }
3160
3161 int sys_acl_valid( SMB_ACL_T theacl )
3162 {
3163         errno = ENOSYS;
3164         return -1;
3165 }
3166
3167 int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
3168 {
3169         errno = ENOSYS;
3170         return -1;
3171 }
3172
3173 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
3174 {
3175         errno = ENOSYS;
3176         return -1;
3177 }
3178
3179 int sys_acl_delete_def_file(const char *name)
3180 {
3181         errno = ENOSYS;
3182         return -1;
3183 }
3184
3185 int sys_acl_free_acl(SMB_ACL_T the_acl) 
3186 {
3187         errno = ENOSYS;
3188         return -1;
3189 }
3190
3191 int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
3192 {
3193         errno = ENOSYS;
3194         return -1;
3195 }
3196
3197 #endif /* No ACLs. */
3198
3199 /************************************************************************
3200  Deliberately outside the ACL defines. Return 1 if this is a "no acls"
3201  errno, 0 if not.
3202 ************************************************************************/
3203
3204 int no_acl_syscall_error(int err)
3205 {
3206 #if defined(ENOSYS)
3207         if (err == ENOSYS) {
3208                 return 1;
3209         }
3210 #endif
3211 #if defined(ENOTSUP)
3212         if (err == ENOTSUP) {
3213                 return 1;
3214         }
3215 #endif
3216         return 0;
3217 }