OSDN Git Service

* globals.cc (enum exit_states::ES_GLOBAL_DTORS): Delete.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / sec_acl.cc
1 /* sec_acl.cc: Sun compatible ACL functions.
2
3    Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc.
4
5    Written by Corinna Vinschen <corinna@vinschen.de>
6
7 This file is part of Cygwin.
8
9 This software is a copyrighted work licensed under the terms of the
10 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
11 details. */
12
13 #include "winsup.h"
14 #include <stdlib.h>
15 #include <sys/acl.h>
16 #include <ctype.h>
17 #include "cygerrno.h"
18 #include "security.h"
19 #include "path.h"
20 #include "fhandler.h"
21 #include "dtable.h"
22 #include "cygheap.h"
23 #include "pwdgrp.h"
24
25 static int
26 searchace (__aclent32_t *aclp, int nentries, int type, __uid32_t id = ILLEGAL_UID)
27 {
28   int i;
29
30   for (i = 0; i < nentries; ++i)
31     if ((aclp[i].a_type == type && (id == ILLEGAL_UID || aclp[i].a_id == id))
32         || !aclp[i].a_type)
33       return i;
34   return -1;
35 }
36
37 int
38 setacl (HANDLE handle, path_conv &pc, int nentries, __aclent32_t *aclbufp,
39         bool &writable)
40 {
41   security_descriptor sd_ret;
42
43   if (get_file_sd (handle, pc, sd_ret))
44     return -1;
45
46   BOOL dummy;
47
48   /* Get owner SID. */
49   PSID owner_sid;
50   if (!GetSecurityDescriptorOwner (sd_ret, &owner_sid, &dummy))
51     {
52       __seterrno ();
53       return -1;
54     }
55   cygsid owner (owner_sid);
56
57   /* Get group SID. */
58   PSID group_sid;
59   if (!GetSecurityDescriptorGroup (sd_ret, &group_sid, &dummy))
60     {
61       __seterrno ();
62       return -1;
63     }
64   cygsid group (group_sid);
65
66   /* Initialize local security descriptor. */
67   SECURITY_DESCRIPTOR sd;
68   if (!InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION))
69     {
70       __seterrno ();
71       return -1;
72     }
73   if (!SetSecurityDescriptorOwner (&sd, owner, FALSE))
74     {
75       __seterrno ();
76       return -1;
77     }
78   if (!SetSecurityDescriptorGroup (&sd, group, FALSE))
79     {
80       __seterrno ();
81       return -1;
82     }
83
84   /* Fill access control list. */
85   PACL acl = (PACL) alloca (3072);
86   size_t acl_len = sizeof (ACL);
87   int ace_off = 0;
88
89   cygsid sid;
90   struct passwd *pw;
91   struct __group32 *gr;
92   int pos;
93
94   if (!InitializeAcl (acl, 3072, ACL_REVISION))
95     {
96       __seterrno ();
97       return -1;
98     }
99
100   writable = false;
101
102   for (int i = 0; i < nentries; ++i)
103     {
104       DWORD allow;
105       /* Owner has more standard rights set. */
106       if ((aclbufp[i].a_type & ~ACL_DEFAULT) == USER_OBJ)
107         allow = STANDARD_RIGHTS_ALL
108                 | (pc.fs_is_samba ()
109                    ? 0 : (FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES));
110       else
111         allow = STANDARD_RIGHTS_READ
112                 | (pc.fs_is_samba () ? 0 : FILE_READ_ATTRIBUTES);
113       if (aclbufp[i].a_perm & S_IROTH)
114         allow |= FILE_GENERIC_READ;
115       if (aclbufp[i].a_perm & S_IWOTH)
116         {
117           allow |= FILE_GENERIC_WRITE;
118           writable = true;
119         }
120       if (aclbufp[i].a_perm & S_IXOTH)
121         allow |= FILE_GENERIC_EXECUTE & ~FILE_READ_ATTRIBUTES;
122       if ((aclbufp[i].a_perm & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH))
123         allow |= FILE_DELETE_CHILD;
124       /* Set inherit property. */
125       DWORD inheritance = (aclbufp[i].a_type & ACL_DEFAULT)
126                           ? (SUB_CONTAINERS_AND_OBJECTS_INHERIT | INHERIT_ONLY)
127                           : NO_INHERITANCE;
128       /*
129        * If a specific acl contains a corresponding default entry with
130        * identical permissions, only one Windows ACE with proper
131        * inheritance bits is created.
132        */
133       if (!(aclbufp[i].a_type & ACL_DEFAULT)
134           && aclbufp[i].a_type & (USER|GROUP|OTHER_OBJ)
135           && (pos = searchace (aclbufp + i + 1, nentries - i - 1,
136                                aclbufp[i].a_type | ACL_DEFAULT,
137                                (aclbufp[i].a_type & (USER|GROUP))
138                                ? aclbufp[i].a_id : ILLEGAL_UID)) >= 0
139           && aclbufp[i].a_perm == aclbufp[i + 1 + pos].a_perm)
140         {
141           inheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
142           /* This invalidates the corresponding default entry. */
143           aclbufp[i + 1 + pos].a_type = USER|GROUP|ACL_DEFAULT;
144         }
145       switch (aclbufp[i].a_type)
146         {
147         case USER_OBJ:
148           if (!add_access_allowed_ace (acl, ace_off++, allow,
149                                         owner, acl_len, inheritance))
150             return -1;
151           break;
152         case DEF_USER_OBJ:
153           if (!add_access_allowed_ace (acl, ace_off++, allow,
154                                        well_known_creator_owner_sid, acl_len, inheritance))
155             return -1;
156           break;
157         case USER:
158         case DEF_USER:
159           if (!(pw = internal_getpwuid (aclbufp[i].a_id))
160               || !sid.getfrompw (pw))
161             {
162               set_errno (EINVAL);
163               return -1;
164             }
165           if (!add_access_allowed_ace (acl, ace_off++, allow,
166                                        sid, acl_len, inheritance))
167             return -1;
168           break;
169         case GROUP_OBJ:
170           if (!add_access_allowed_ace (acl, ace_off++, allow,
171                                        group, acl_len, inheritance))
172             return -1;
173           break;
174         case DEF_GROUP_OBJ:
175           if (!add_access_allowed_ace (acl, ace_off++, allow,
176                                        well_known_creator_group_sid, acl_len, inheritance))
177             return -1;
178           break;
179         case GROUP:
180         case DEF_GROUP:
181           if (!(gr = internal_getgrgid (aclbufp[i].a_id))
182               || !sid.getfromgr (gr))
183             {
184               set_errno (EINVAL);
185               return -1;
186             }
187           if (!add_access_allowed_ace (acl, ace_off++, allow,
188                                        sid, acl_len, inheritance))
189             return -1;
190           break;
191         case OTHER_OBJ:
192         case DEF_OTHER_OBJ:
193           if (!add_access_allowed_ace (acl, ace_off++, allow,
194                                        well_known_world_sid,
195                                        acl_len, inheritance))
196             return -1;
197           break;
198         }
199     }
200   /* Set AclSize to computed value. */
201   acl->AclSize = acl_len;
202   debug_printf ("ACL-Size: %d", acl_len);
203   /* Create DACL for local security descriptor. */
204   if (!SetSecurityDescriptorDacl (&sd, TRUE, acl, FALSE))
205     {
206       __seterrno ();
207       return -1;
208     }
209   /* Make self relative security descriptor in sd_ret. */
210   DWORD sd_size = 0;
211   MakeSelfRelativeSD (&sd, sd_ret, &sd_size);
212   if (sd_size <= 0)
213     {
214       __seterrno ();
215       return -1;
216     }
217   if (!sd_ret.realloc (sd_size))
218     {
219       set_errno (ENOMEM);
220       return -1;
221     }
222   if (!MakeSelfRelativeSD (&sd, sd_ret, &sd_size))
223     {
224       __seterrno ();
225       return -1;
226     }
227   debug_printf ("Created SD-Size: %d", sd_ret.size ());
228   return set_file_sd (handle, pc, sd_ret, false);
229 }
230
231 /* Temporary access denied bits */
232 #define DENY_R 040000
233 #define DENY_W 020000
234 #define DENY_X 010000
235
236 static void
237 getace (__aclent32_t &acl, int type, int id, DWORD win_ace_mask,
238         DWORD win_ace_type)
239 {
240   acl.a_type = type;
241   acl.a_id = id;
242
243   if ((win_ace_mask & FILE_READ_BITS) && !(acl.a_perm & (S_IROTH | DENY_R)))
244     {
245       if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE)
246         acl.a_perm |= S_IROTH;
247       else if (win_ace_type == ACCESS_DENIED_ACE_TYPE)
248         acl.a_perm |= DENY_R;
249     }
250
251   if ((win_ace_mask & FILE_WRITE_BITS) && !(acl.a_perm & (S_IWOTH | DENY_W)))
252     {
253       if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE)
254         acl.a_perm |= S_IWOTH;
255       else if (win_ace_type == ACCESS_DENIED_ACE_TYPE)
256         acl.a_perm |= DENY_W;
257     }
258
259   if ((win_ace_mask & FILE_EXEC_BITS) && !(acl.a_perm & (S_IXOTH | DENY_X)))
260     {
261       if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE)
262         acl.a_perm |= S_IXOTH;
263       else if (win_ace_type == ACCESS_DENIED_ACE_TYPE)
264         acl.a_perm |= DENY_X;
265     }
266 }
267
268 int
269 getacl (HANDLE handle, path_conv &pc, int nentries, __aclent32_t *aclbufp)
270 {
271   security_descriptor sd;
272
273   if (get_file_sd (handle, pc, sd))
274     return -1;
275
276   cygpsid owner_sid;
277   cygpsid group_sid;
278   BOOL dummy;
279   __uid32_t uid;
280   __gid32_t gid;
281
282   if (!GetSecurityDescriptorOwner (sd, (PSID *) &owner_sid, &dummy))
283     {
284       debug_printf ("GetSecurityDescriptorOwner %E");
285       __seterrno ();
286       return -1;
287     }
288   uid = owner_sid.get_uid ();
289
290   if (!GetSecurityDescriptorGroup (sd, (PSID *) &group_sid, &dummy))
291     {
292       debug_printf ("GetSecurityDescriptorGroup %E");
293       __seterrno ();
294       return -1;
295     }
296   gid = group_sid.get_gid ();
297
298   __aclent32_t lacl[MAX_ACL_ENTRIES];
299   memset (&lacl, 0, MAX_ACL_ENTRIES * sizeof (__aclent32_t));
300   lacl[0].a_type = USER_OBJ;
301   lacl[0].a_id = uid;
302   lacl[1].a_type = GROUP_OBJ;
303   lacl[1].a_id = gid;
304   lacl[2].a_type = OTHER_OBJ;
305   lacl[2].a_id = ILLEGAL_GID;
306   lacl[3].a_type = CLASS_OBJ;
307   lacl[3].a_id = ILLEGAL_GID;
308   lacl[3].a_perm = S_IROTH | S_IWOTH | S_IXOTH;
309
310   PACL acl;
311   BOOL acl_exists;
312
313   if (!GetSecurityDescriptorDacl (sd, &acl_exists, &acl, &dummy))
314     {
315       __seterrno ();
316       debug_printf ("GetSecurityDescriptorDacl %E");
317       return -1;
318     }
319
320   int pos, i, types_def = 0;
321
322   if (!acl_exists || !acl)
323     for (pos = 0; pos < 3; ++pos) /* Don't change CLASS_OBJ entry */
324       lacl[pos].a_perm = S_IROTH | S_IWOTH | S_IXOTH;
325   else
326     {
327       for (i = 0; i < acl->AceCount; ++i)
328         {
329           ACCESS_ALLOWED_ACE *ace;
330
331           if (!GetAce (acl, i, (PVOID *) &ace))
332             continue;
333
334           cygpsid ace_sid ((PSID) &ace->SidStart);
335           int id;
336           int type = 0;
337
338           if (ace_sid == well_known_world_sid)
339             {
340               type = OTHER_OBJ;
341               id = ILLEGAL_GID;
342             }
343           else if (ace_sid == group_sid)
344             {
345               type = GROUP_OBJ;
346               id = gid;
347             }
348           else if (ace_sid == owner_sid)
349             {
350               type = USER_OBJ;
351               id = uid;
352             }
353           else if (ace_sid == well_known_creator_group_sid)
354             {
355               type = GROUP_OBJ | ACL_DEFAULT;
356               id = ILLEGAL_GID;
357             }
358           else if (ace_sid == well_known_creator_owner_sid)
359             {
360               type = USER_OBJ | ACL_DEFAULT;
361               id = ILLEGAL_GID;
362             }
363           else
364             id = ace_sid.get_id (true, &type);
365
366           if (!type)
367             continue;
368           if (!(ace->Header.AceFlags & INHERIT_ONLY || type & ACL_DEFAULT))
369             {
370               if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0)
371                 getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType);
372             }
373           if ((ace->Header.AceFlags & SUB_CONTAINERS_AND_OBJECTS_INHERIT)
374               && pc.isdir ())
375             {
376               if (type == USER_OBJ)
377                 type = USER;
378               else if (type == GROUP_OBJ)
379                 type = GROUP;
380               type |= ACL_DEFAULT;
381               types_def |= type;
382               if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0)
383                 getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType);
384             }
385         }
386       /* Include DEF_CLASS_OBJ if any default ace exists */
387       if ((types_def & (USER|GROUP))
388           && ((pos = searchace (lacl, MAX_ACL_ENTRIES, DEF_CLASS_OBJ)) >= 0))
389         {
390           lacl[pos].a_type = DEF_CLASS_OBJ;
391           lacl[pos].a_id = ILLEGAL_GID;
392           lacl[pos].a_perm = S_IRWXU | S_IRWXG | S_IRWXO;
393         }
394     }
395   if ((pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) < 0)
396     pos = MAX_ACL_ENTRIES;
397   if (aclbufp) {
398     if (owner_sid == group_sid)
399       lacl[0].a_perm = lacl[1].a_perm;
400     if (pos > nentries)
401       {
402         set_errno (ENOSPC);
403         return -1;
404       }
405     memcpy (aclbufp, lacl, pos * sizeof (__aclent32_t));
406     for (i = 0; i < pos; ++i)
407       aclbufp[i].a_perm &= ~(DENY_R | DENY_W | DENY_X);
408     aclsort32 (pos, 0, aclbufp);
409   }
410   syscall_printf ("%d = getacl (%S)", pos, pc.get_nt_native_path ());
411   return pos;
412 }
413
414 static int
415 acl_worker (const char *path, int cmd, int nentries, __aclent32_t *aclbufp,
416             unsigned fmode)
417 {
418   int res = -1;
419   fhandler_base *fh = build_fh_name (path, NULL, fmode, stat_suffixes);
420   if (fh->error ())
421     {
422       debug_printf ("got %d error from build_fh_name", fh->error ());
423       set_errno (fh->error ());
424     }
425   else if (!fh->exists ())
426     set_errno (ENOENT);
427   else
428     res = fh->facl (cmd, nentries, aclbufp);
429
430   delete fh;
431   syscall_printf ("%d = acl (%s)", res, path);
432   return res;
433 }
434
435 extern "C" int
436 acl32 (const char *path, int cmd, int nentries, __aclent32_t *aclbufp)
437 {
438   return acl_worker (path, cmd, nentries, aclbufp, PC_SYM_FOLLOW);
439 }
440
441 extern "C" int
442 lacl32 (const char *path, int cmd, int nentries, __aclent32_t *aclbufp)
443 {
444   return acl_worker (path, cmd, nentries, aclbufp, PC_SYM_NOFOLLOW);
445 }
446
447 extern "C" int
448 facl32 (int fd, int cmd, int nentries, __aclent32_t *aclbufp)
449 {
450   cygheap_fdget cfd (fd);
451   if (cfd < 0)
452     {
453       syscall_printf ("-1 = facl (%d)", fd);
454       return -1;
455     }
456   int res = cfd->facl (cmd, nentries, aclbufp);
457   syscall_printf ("%d = facl (%s) )", res, cfd->get_name ());
458   return res;
459 }
460
461 extern "C" int
462 aclcheck32 (__aclent32_t *aclbufp, int nentries, int *which)
463 {
464   bool has_user_obj = false;
465   bool has_group_obj = false;
466   bool has_other_obj = false;
467   bool has_class_obj = false;
468   bool has_ug_objs = false;
469   bool has_def_user_obj = false;
470   bool has_def_group_obj = false;
471   bool has_def_other_obj = false;
472   bool has_def_class_obj = false;
473   bool has_def_ug_objs = false;
474   int pos2;
475
476   for (int pos = 0; pos < nentries; ++pos)
477     switch (aclbufp[pos].a_type)
478       {
479       case USER_OBJ:
480         if (has_user_obj)
481           {
482             if (which)
483               *which = pos;
484             return USER_ERROR;
485           }
486         has_user_obj = true;
487         break;
488       case GROUP_OBJ:
489         if (has_group_obj)
490           {
491             if (which)
492               *which = pos;
493             return GRP_ERROR;
494           }
495         has_group_obj = true;
496         break;
497       case OTHER_OBJ:
498         if (has_other_obj)
499           {
500             if (which)
501               *which = pos;
502             return OTHER_ERROR;
503           }
504         has_other_obj = true;
505         break;
506       case CLASS_OBJ:
507         if (has_class_obj)
508           {
509             if (which)
510               *which = pos;
511             return CLASS_ERROR;
512           }
513         has_class_obj = true;
514         break;
515       case USER:
516       case GROUP:
517         if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1,
518                                aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0)
519           {
520             if (which)
521               *which = pos2;
522             return DUPLICATE_ERROR;
523           }
524         has_ug_objs = true;
525         break;
526       case DEF_USER_OBJ:
527         if (has_def_user_obj)
528           {
529             if (which)
530               *which = pos;
531             return USER_ERROR;
532           }
533         has_def_user_obj = true;
534         break;
535       case DEF_GROUP_OBJ:
536         if (has_def_group_obj)
537           {
538             if (which)
539               *which = pos;
540             return GRP_ERROR;
541           }
542         has_def_group_obj = true;
543         break;
544       case DEF_OTHER_OBJ:
545         if (has_def_other_obj)
546           {
547             if (which)
548               *which = pos;
549             return OTHER_ERROR;
550           }
551         has_def_other_obj = true;
552         break;
553       case DEF_CLASS_OBJ:
554         if (has_def_class_obj)
555           {
556             if (which)
557               *which = pos;
558             return CLASS_ERROR;
559           }
560         has_def_class_obj = true;
561         break;
562       case DEF_USER:
563       case DEF_GROUP:
564         if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1,
565                                aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0)
566           {
567             if (which)
568               *which = pos2;
569             return DUPLICATE_ERROR;
570           }
571         has_def_ug_objs = true;
572         break;
573       default:
574         return ENTRY_ERROR;
575       }
576   if (!has_user_obj
577       || !has_group_obj
578       || !has_other_obj
579 #if 0
580       /* These checks are not ok yet since CLASS_OBJ isn't fully implemented. */
581       || (has_ug_objs && !has_class_obj)
582       || (has_def_ug_objs && !has_def_class_obj)
583 #endif
584      )
585     {
586       if (which)
587         *which = -1;
588       return MISS_ERROR;
589     }
590   return 0;
591 }
592
593 static int
594 acecmp (const void *a1, const void *a2)
595 {
596 #define ace(i) ((const __aclent32_t *) a##i)
597   int ret = ace (1)->a_type - ace (2)->a_type;
598   if (!ret)
599     ret = ace (1)->a_id - ace (2)->a_id;
600   return ret;
601 #undef ace
602 }
603
604 extern "C" int
605 aclsort32 (int nentries, int, __aclent32_t *aclbufp)
606 {
607   if (aclcheck32 (aclbufp, nentries, NULL))
608     return -1;
609   if (!aclbufp || nentries < 1)
610     {
611       set_errno (EINVAL);
612       return -1;
613     }
614   qsort ((void *) aclbufp, nentries, sizeof (__aclent32_t), acecmp);
615   return 0;
616 }
617
618 extern "C" int
619 acltomode32 (__aclent32_t *aclbufp, int nentries, mode_t *modep)
620 {
621   int pos;
622
623   if (!aclbufp || nentries < 1 || !modep)
624     {
625       set_errno (EINVAL);
626       return -1;
627     }
628   *modep = 0;
629   if ((pos = searchace (aclbufp, nentries, USER_OBJ)) < 0
630       || !aclbufp[pos].a_type)
631     {
632       set_errno (EINVAL);
633       return -1;
634     }
635   *modep |= (aclbufp[pos].a_perm & S_IRWXO) << 6;
636   if ((pos = searchace (aclbufp, nentries, GROUP_OBJ)) < 0
637       || !aclbufp[pos].a_type)
638     {
639       set_errno (EINVAL);
640       return -1;
641     }
642   *modep |= (aclbufp[pos].a_perm & S_IRWXO) << 3;
643   int cpos;
644   if ((cpos = searchace (aclbufp, nentries, CLASS_OBJ)) >= 0
645       && aclbufp[cpos].a_type == CLASS_OBJ)
646     *modep |= ((aclbufp[pos].a_perm & S_IRWXO) & aclbufp[cpos].a_perm) << 3;
647   if ((pos = searchace (aclbufp, nentries, OTHER_OBJ)) < 0
648       || !aclbufp[pos].a_type)
649     {
650       set_errno (EINVAL);
651       return -1;
652     }
653   *modep |= aclbufp[pos].a_perm & S_IRWXO;
654   return 0;
655 }
656
657 extern "C" int
658 aclfrommode32 (__aclent32_t *aclbufp, int nentries, mode_t *modep)
659 {
660   int pos;
661
662   if (!aclbufp || nentries < 1 || !modep)
663     {
664       set_errno (EINVAL);
665       return -1;
666     }
667   if ((pos = searchace (aclbufp, nentries, USER_OBJ)) < 0
668       || !aclbufp[pos].a_type)
669     {
670       set_errno (EINVAL);
671       return -1;
672     }
673   aclbufp[pos].a_perm = (*modep & S_IRWXU) >> 6;
674   if ((pos = searchace (aclbufp, nentries, GROUP_OBJ)) < 0
675       || !aclbufp[pos].a_type)
676     {
677       set_errno (EINVAL);
678       return -1;
679     }
680   aclbufp[pos].a_perm = (*modep & S_IRWXG) >> 3;
681   if ((pos = searchace (aclbufp, nentries, CLASS_OBJ)) >= 0
682       && aclbufp[pos].a_type == CLASS_OBJ)
683     aclbufp[pos].a_perm = (*modep & S_IRWXG) >> 3;
684   if ((pos = searchace (aclbufp, nentries, OTHER_OBJ)) < 0
685       || !aclbufp[pos].a_type)
686     {
687       set_errno (EINVAL);
688       return -1;
689     }
690   aclbufp[pos].a_perm = (*modep & S_IRWXO);
691   return 0;
692 }
693
694 extern "C" int
695 acltopbits32 (__aclent32_t *aclbufp, int nentries, mode_t *pbitsp)
696 {
697   return acltomode32 (aclbufp, nentries, pbitsp);
698 }
699
700 extern "C" int
701 aclfrompbits32 (__aclent32_t *aclbufp, int nentries, mode_t *pbitsp)
702 {
703   return aclfrommode32 (aclbufp, nentries, pbitsp);
704 }
705
706 static char *
707 permtostr (mode_t perm)
708 {
709   static char pbuf[4];
710
711   pbuf[0] = (perm & S_IROTH) ? 'r' : '-';
712   pbuf[1] = (perm & S_IWOTH) ? 'w' : '-';
713   pbuf[2] = (perm & S_IXOTH) ? 'x' : '-';
714   pbuf[3] = '\0';
715   return pbuf;
716 }
717
718 extern "C" char *
719 acltotext32 (__aclent32_t *aclbufp, int aclcnt)
720 {
721   if (!aclbufp || aclcnt < 1 || aclcnt > MAX_ACL_ENTRIES
722       || aclcheck32 (aclbufp, aclcnt, NULL))
723     {
724       set_errno (EINVAL);
725       return NULL;
726     }
727   char buf[32000];
728   buf[0] = '\0';
729   bool first = true;
730
731   for (int pos = 0; pos < aclcnt; ++pos)
732     {
733       if (!first)
734         strcat (buf, ",");
735       first = false;
736       if (aclbufp[pos].a_type & ACL_DEFAULT)
737         strcat (buf, "default");
738       switch (aclbufp[pos].a_type & ~ACL_DEFAULT)
739         {
740         case USER_OBJ:
741           __small_sprintf (buf + strlen (buf), "user::%s",
742                    permtostr (aclbufp[pos].a_perm));
743           break;
744         case USER:
745           __small_sprintf (buf + strlen (buf), "user:%d:%s",
746                    aclbufp[pos].a_id, permtostr (aclbufp[pos].a_perm));
747           break;
748         case GROUP_OBJ:
749           __small_sprintf (buf + strlen (buf), "group::%s",
750                    permtostr (aclbufp[pos].a_perm));
751           break;
752         case GROUP:
753           __small_sprintf (buf + strlen (buf), "group:%d:%s",
754                    aclbufp[pos].a_id, permtostr (aclbufp[pos].a_perm));
755           break;
756         case CLASS_OBJ:
757           __small_sprintf (buf + strlen (buf), "mask::%s",
758                    permtostr (aclbufp[pos].a_perm));
759           break;
760         case OTHER_OBJ:
761           __small_sprintf (buf + strlen (buf), "other::%s",
762                    permtostr (aclbufp[pos].a_perm));
763           break;
764         default:
765           set_errno (EINVAL);
766           return NULL;
767         }
768     }
769   return strdup (buf);
770 }
771
772 static mode_t
773 permfromstr (char *perm)
774 {
775   mode_t mode = 0;
776
777   if (strlen (perm) != 3)
778     return 01000;
779   if (perm[0] == 'r')
780     mode |= S_IROTH;
781   else if (perm[0] != '-')
782     return 01000;
783   if (perm[1] == 'w')
784     mode |= S_IWOTH;
785   else if (perm[1] != '-')
786     return 01000;
787   if (perm[2] == 'x')
788     mode |= S_IXOTH;
789   else if (perm[2] != '-')
790     return 01000;
791   return mode;
792 }
793
794 extern "C" __aclent32_t *
795 aclfromtext32 (char *acltextp, int *)
796 {
797   if (!acltextp)
798     {
799       set_errno (EINVAL);
800       return NULL;
801     }
802   char buf[strlen (acltextp) + 1];
803   __aclent32_t lacl[MAX_ACL_ENTRIES];
804   memset (lacl, 0, sizeof lacl);
805   int pos = 0;
806   strcpy (buf, acltextp);
807   char *lasts;
808   for (char *c = strtok_r (buf, ",", &lasts);
809        c;
810        c = strtok_r (NULL, ",", &lasts))
811     {
812       if (!strncmp (c, "default", 7))
813         {
814           lacl[pos].a_type |= ACL_DEFAULT;
815           c += 7;
816         }
817       if (!strncmp (c, "user:", 5))
818         {
819           if (c[5] == ':')
820             lacl[pos].a_type |= USER_OBJ;
821           else
822             {
823               lacl[pos].a_type |= USER;
824               c += 5;
825               if (isalpha (*c))
826                 {
827                   struct passwd *pw = internal_getpwnam (c);
828                   if (!pw)
829                     {
830                       set_errno (EINVAL);
831                       return NULL;
832                     }
833                   lacl[pos].a_id = pw->pw_uid;
834                   c = strechr (c, ':');
835                 }
836               else if (isdigit (*c))
837                 lacl[pos].a_id = strtol (c, &c, 10);
838               if (*c != ':')
839                 {
840                   set_errno (EINVAL);
841                   return NULL;
842                 }
843             }
844         }
845       else if (!strncmp (c, "group:", 6))
846         {
847           if (c[5] == ':')
848             lacl[pos].a_type |= GROUP_OBJ;
849           else
850             {
851               lacl[pos].a_type |= GROUP;
852               c += 5;
853               if (isalpha (*c))
854                 {
855                   struct __group32 *gr = internal_getgrnam (c);
856                   if (!gr)
857                     {
858                       set_errno (EINVAL);
859                       return NULL;
860                     }
861                   lacl[pos].a_id = gr->gr_gid;
862                   c = strechr (c, ':');
863                 }
864               else if (isdigit (*c))
865                 lacl[pos].a_id = strtol (c, &c, 10);
866               if (*c != ':')
867                 {
868                   set_errno (EINVAL);
869                   return NULL;
870                 }
871             }
872         }
873       else if (!strncmp (c, "mask:", 5))
874         {
875           if (c[5] == ':')
876             lacl[pos].a_type |= CLASS_OBJ;
877           else
878             {
879               set_errno (EINVAL);
880               return NULL;
881             }
882         }
883       else if (!strncmp (c, "other:", 6))
884         {
885           if (c[5] == ':')
886             lacl[pos].a_type |= OTHER_OBJ;
887           else
888             {
889               set_errno (EINVAL);
890               return NULL;
891             }
892         }
893       if ((lacl[pos].a_perm = permfromstr (c)) == 01000)
894         {
895           set_errno (EINVAL);
896           return NULL;
897         }
898       ++pos;
899     }
900   __aclent32_t *aclp = (__aclent32_t *) malloc (pos * sizeof (__aclent32_t));
901   if (aclp)
902     memcpy (aclp, lacl, pos * sizeof (__aclent32_t));
903   return aclp;
904 }
905
906 /* __aclent16_t and __aclent32_t have same size and same member offsets */
907 static __aclent32_t *
908 acl16to32 (__aclent16_t *aclbufp, int nentries)
909 {
910   __aclent32_t *aclbufp32 = (__aclent32_t *) aclbufp;
911   if (aclbufp32)
912     for (int i = 0; i < nentries; i++)
913       aclbufp32[i].a_id &= USHRT_MAX;
914   return aclbufp32;
915 }
916
917 extern "C" int
918 acl (const char *path, int cmd, int nentries, __aclent16_t *aclbufp)
919 {
920   return acl32 (path, cmd, nentries, acl16to32 (aclbufp, nentries));
921 }
922
923 extern "C" int
924 facl (int fd, int cmd, int nentries, __aclent16_t *aclbufp)
925 {
926   return facl32 (fd, cmd, nentries, acl16to32 (aclbufp, nentries));
927 }
928
929 extern "C" int
930 lacl (const char *path, int cmd, int nentries, __aclent16_t *aclbufp)
931 {
932   return lacl32 (path, cmd, nentries, acl16to32 (aclbufp, nentries));
933 }
934
935 extern "C" int
936 aclcheck (__aclent16_t *aclbufp, int nentries, int *which)
937 {
938   return aclcheck32 (acl16to32 (aclbufp, nentries), nentries, which);
939 }
940
941 extern "C" int
942 aclsort (int nentries, int i, __aclent16_t *aclbufp)
943 {
944   return aclsort32 (nentries, i, acl16to32 (aclbufp, nentries));
945 }
946
947
948 extern "C" int
949 acltomode (__aclent16_t *aclbufp, int nentries, mode_t *modep)
950 {
951   return acltomode32 (acl16to32 (aclbufp, nentries), nentries, modep);
952 }
953
954 extern "C" int
955 aclfrommode (__aclent16_t *aclbufp, int nentries, mode_t *modep)
956 {
957   return aclfrommode32 ((__aclent32_t *)aclbufp, nentries, modep);
958 }
959
960 extern "C" int
961 acltopbits (__aclent16_t *aclbufp, int nentries, mode_t *pbitsp)
962 {
963   return acltopbits32 (acl16to32 (aclbufp, nentries), nentries, pbitsp);
964 }
965
966 extern "C" int
967 aclfrompbits (__aclent16_t *aclbufp, int nentries, mode_t *pbitsp)
968 {
969   return aclfrompbits32 ((__aclent32_t *)aclbufp, nentries, pbitsp);
970 }
971
972 extern "C" char *
973 acltotext (__aclent16_t *aclbufp, int aclcnt)
974 {
975   return acltotext32 (acl16to32 (aclbufp, aclcnt), aclcnt);
976 }
977
978 extern "C" __aclent16_t *
979 aclfromtext (char *acltextp, int * aclcnt)
980 {
981   return (__aclent16_t *) aclfromtext32 (acltextp, aclcnt);
982 }