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