root/maint/gnulib/lib/set-permissions.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. acl_from_mode
  2. set_acls_from_mode
  3. context_acl_from_mode
  4. context_aclv_from_mode
  5. set_acls_from_mode
  6. context_acl_from_mode
  7. context_acl_from_mode
  8. set_acls
  9. chmod_or_fchmod
  10. set_permissions

   1 /* Set permissions of a file.  -*- coding: utf-8 -*-
   2 
   3    Copyright (C) 2002-2003, 2005-2021 Free Software Foundation, Inc.
   4 
   5    This program is free software: you can redistribute it and/or modify
   6    it under the terms of the GNU General Public License as published by
   7    the Free Software Foundation; either version 3 of the License, or
   8    (at your option) any later version.
   9 
  10    This program is distributed in the hope that it will be useful,
  11    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13    GNU General Public License for more details.
  14 
  15    You should have received a copy of the GNU General Public License
  16    along with this program.  If not, see <https://www.gnu.org/licenses/>.
  17 
  18    Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible.  */
  19 
  20 #include <config.h>
  21 
  22 #include "acl.h"
  23 
  24 #include "acl-internal.h"
  25 
  26 #if USE_ACL
  27 # if ! defined HAVE_ACL_FROM_MODE && defined HAVE_ACL_FROM_TEXT /* FreeBSD, IRIX, Tru64, Cygwin >= 2.5 */
  28 #  if HAVE_ACL_GET_FILE && !HAVE_ACL_TYPE_EXTENDED
  29 
  30 static acl_t
  31 acl_from_mode (mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help] */
  32 {
  33 #  if HAVE_ACL_FREE_TEXT /* Tru64 */
  34   char acl_text[] = "u::---,g::---,o::---,";
  35 #  else /* FreeBSD, IRIX, Cygwin >= 2.5 */
  36   char acl_text[] = "u::---,g::---,o::---";
  37 #  endif
  38 
  39   if (mode & S_IRUSR) acl_text[ 3] = 'r';
  40   if (mode & S_IWUSR) acl_text[ 4] = 'w';
  41   if (mode & S_IXUSR) acl_text[ 5] = 'x';
  42   if (mode & S_IRGRP) acl_text[10] = 'r';
  43   if (mode & S_IWGRP) acl_text[11] = 'w';
  44   if (mode & S_IXGRP) acl_text[12] = 'x';
  45   if (mode & S_IROTH) acl_text[17] = 'r';
  46   if (mode & S_IWOTH) acl_text[18] = 'w';
  47   if (mode & S_IXOTH) acl_text[19] = 'x';
  48 
  49   return acl_from_text (acl_text);
  50 }
  51 #  endif
  52 # endif
  53 
  54 # if HAVE_FACL && defined GETACL /* Solaris, Cygwin < 2.5, not HP-UX */
  55 static int
  56 set_acls_from_mode (const char *name, int desc, mode_t mode, bool *must_chmod)
     /* [previous][next][first][last][top][bottom][index][help] */
  57 {
  58 #  ifdef ACE_GETACL
  59   /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
  60      file systems (whereas the other ones are used in UFS file systems).  */
  61 
  62   /* The flags in the ace_t structure changed in a binary incompatible way
  63      when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> version 1.15.
  64      How to distinguish the two conventions at runtime?
  65      We fetch the existing ACL.  In the old convention, usually three ACEs have
  66      a_flags = ACE_OWNER / ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400.
  67      In the new convention, these values are not used.  */
  68   int convention;
  69 
  70   {
  71     /* Initially, try to read the entries into a stack-allocated buffer.
  72        Use malloc if it does not fit.  */
  73     enum
  74       {
  75         alloc_init = 4000 / sizeof (ace_t), /* >= 3 */
  76         alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t))
  77       };
  78     ace_t buf[alloc_init];
  79     size_t alloc = alloc_init;
  80     ace_t *entries = buf;
  81     ace_t *malloced = NULL;
  82     int count;
  83 
  84     for (;;)
  85       {
  86         count = (desc != -1
  87                  ? facl (desc, ACE_GETACL, alloc, entries)
  88                  : acl (name, ACE_GETACL, alloc, entries));
  89         if (count < 0 && errno == ENOSPC)
  90           {
  91             /* Increase the size of the buffer.  */
  92             free (malloced);
  93             if (alloc > alloc_max / 2)
  94               {
  95                 errno = ENOMEM;
  96                 return -1;
  97               }
  98             alloc = 2 * alloc; /* <= alloc_max */
  99             entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t));
 100             if (entries == NULL)
 101               {
 102                 errno = ENOMEM;
 103                 return -1;
 104               }
 105             continue;
 106           }
 107         break;
 108       }
 109 
 110     if (count <= 0)
 111       convention = -1;
 112     else
 113       {
 114         int i;
 115 
 116         convention = 0;
 117         for (i = 0; i < count; i++)
 118           if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_ACE_OTHER))
 119             {
 120               convention = 1;
 121               break;
 122             }
 123       }
 124     free (malloced);
 125   }
 126 
 127   if (convention >= 0)
 128     {
 129       ace_t entries[6];
 130       int count;
 131       int ret;
 132 
 133       if (convention)
 134         {
 135           /* Running on Solaris 10.  */
 136           entries[0].a_type = OLD_ALLOW;
 137           entries[0].a_flags = OLD_ACE_OWNER;
 138           entries[0].a_who = 0; /* irrelevant */
 139           entries[0].a_access_mask = (mode >> 6) & 7;
 140           entries[1].a_type = OLD_ALLOW;
 141           entries[1].a_flags = OLD_ACE_GROUP;
 142           entries[1].a_who = 0; /* irrelevant */
 143           entries[1].a_access_mask = (mode >> 3) & 7;
 144           entries[2].a_type = OLD_ALLOW;
 145           entries[2].a_flags = OLD_ACE_OTHER;
 146           entries[2].a_who = 0;
 147           entries[2].a_access_mask = mode & 7;
 148           count = 3;
 149         }
 150       else
 151         {
 152           /* Running on Solaris 10 (newer version) or Solaris 11.
 153              The details here were found through "/bin/ls -lvd somefiles".  */
 154           entries[0].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
 155           entries[0].a_flags = NEW_ACE_OWNER;
 156           entries[0].a_who = 0; /* irrelevant */
 157           entries[0].a_access_mask = 0;
 158           entries[1].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE;
 159           entries[1].a_flags = NEW_ACE_OWNER;
 160           entries[1].a_who = 0; /* irrelevant */
 161           entries[1].a_access_mask = NEW_ACE_WRITE_NAMED_ATTRS
 162                                      | NEW_ACE_WRITE_ATTRIBUTES
 163                                      | NEW_ACE_WRITE_ACL
 164                                      | NEW_ACE_WRITE_OWNER;
 165           if (mode & 0400)
 166             entries[1].a_access_mask |= NEW_ACE_READ_DATA;
 167           else
 168             entries[0].a_access_mask |= NEW_ACE_READ_DATA;
 169           if (mode & 0200)
 170             entries[1].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
 171           else
 172             entries[0].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
 173           if (mode & 0100)
 174             entries[1].a_access_mask |= NEW_ACE_EXECUTE;
 175           else
 176             entries[0].a_access_mask |= NEW_ACE_EXECUTE;
 177           entries[2].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
 178           entries[2].a_flags = NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP;
 179           entries[2].a_who = 0; /* irrelevant */
 180           entries[2].a_access_mask = 0;
 181           entries[3].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE;
 182           entries[3].a_flags = NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP;
 183           entries[3].a_who = 0; /* irrelevant */
 184           entries[3].a_access_mask = 0;
 185           if (mode & 0040)
 186             entries[3].a_access_mask |= NEW_ACE_READ_DATA;
 187           else
 188             entries[2].a_access_mask |= NEW_ACE_READ_DATA;
 189           if (mode & 0020)
 190             entries[3].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
 191           else
 192             entries[2].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
 193           if (mode & 0010)
 194             entries[3].a_access_mask |= NEW_ACE_EXECUTE;
 195           else
 196             entries[2].a_access_mask |= NEW_ACE_EXECUTE;
 197           entries[4].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
 198           entries[4].a_flags = NEW_ACE_EVERYONE;
 199           entries[4].a_who = 0;
 200           entries[4].a_access_mask = NEW_ACE_WRITE_NAMED_ATTRS
 201                                      | NEW_ACE_WRITE_ATTRIBUTES
 202                                      | NEW_ACE_WRITE_ACL
 203                                      | NEW_ACE_WRITE_OWNER;
 204           entries[5].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE;
 205           entries[5].a_flags = NEW_ACE_EVERYONE;
 206           entries[5].a_who = 0;
 207           entries[5].a_access_mask = NEW_ACE_READ_NAMED_ATTRS
 208                                      | NEW_ACE_READ_ATTRIBUTES
 209                                      | NEW_ACE_READ_ACL
 210                                      | NEW_ACE_SYNCHRONIZE;
 211           if (mode & 0004)
 212             entries[5].a_access_mask |= NEW_ACE_READ_DATA;
 213           else
 214             entries[4].a_access_mask |= NEW_ACE_READ_DATA;
 215           if (mode & 0002)
 216             entries[5].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
 217           else
 218             entries[4].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
 219           if (mode & 0001)
 220             entries[5].a_access_mask |= NEW_ACE_EXECUTE;
 221           else
 222             entries[4].a_access_mask |= NEW_ACE_EXECUTE;
 223           count = 6;
 224         }
 225       if (desc != -1)
 226         ret = facl (desc, ACE_SETACL, count, entries);
 227       else
 228         ret = acl (name, ACE_SETACL, count, entries);
 229       if (ret < 0 && errno != EINVAL && errno != ENOTSUP)
 230         {
 231           if (errno == ENOSYS)
 232             {
 233               *must_chmod = true;
 234               return 0;
 235             }
 236           return -1;
 237         }
 238       if (ret == 0)
 239         return 0;
 240     }
 241 #  endif
 242 
 243   {
 244     aclent_t entries[3];
 245     int ret;
 246 
 247     entries[0].a_type = USER_OBJ;
 248     entries[0].a_id = 0; /* irrelevant */
 249     entries[0].a_perm = (mode >> 6) & 7;
 250     entries[1].a_type = GROUP_OBJ;
 251     entries[1].a_id = 0; /* irrelevant */
 252     entries[1].a_perm = (mode >> 3) & 7;
 253     entries[2].a_type = OTHER_OBJ;
 254     entries[2].a_id = 0;
 255     entries[2].a_perm = mode & 7;
 256 
 257     if (desc != -1)
 258       ret = facl (desc, SETACL,
 259                   sizeof (entries) / sizeof (aclent_t), entries);
 260     else
 261       ret = acl (name, SETACL,
 262                  sizeof (entries) / sizeof (aclent_t), entries);
 263     if (ret < 0)
 264       {
 265         if (errno == ENOSYS || errno == EOPNOTSUPP)
 266           {
 267             *must_chmod = true;
 268             return 0;
 269           }
 270         return -1;
 271       }
 272     return 0;
 273   }
 274 }
 275 
 276 # elif HAVE_GETACL /* HP-UX */
 277 static int
 278 context_acl_from_mode (struct permission_context *ctx, const char *name, int desc)
     /* [previous][next][first][last][top][bottom][index][help] */
 279 {
 280   struct stat statbuf;
 281   int ret;
 282 
 283   if (desc != -1)
 284     ret = fstat (desc, &statbuf);
 285   else
 286     ret = stat (name, &statbuf);
 287   if (ret < 0)
 288     return -1;
 289 
 290   ctx->entries[0].uid = statbuf.st_uid;
 291   ctx->entries[0].gid = ACL_NSGROUP;
 292   ctx->entries[0].mode = (ctx->mode >> 6) & 7;
 293   ctx->entries[1].uid = ACL_NSUSER;
 294   ctx->entries[1].gid = statbuf.st_gid;
 295   ctx->entries[1].mode = (ctx->mode >> 3) & 7;
 296   ctx->entries[2].uid = ACL_NSUSER;
 297   ctx->entries[2].gid = ACL_NSGROUP;
 298   ctx->entries[2].mode = ctx->mode & 7;
 299   ctx->count = 3;
 300   return 0;
 301 }
 302 
 303 #  if HAVE_ACLV_H /* HP-UX >= 11.11 */
 304 static int
 305 context_aclv_from_mode (struct permission_context *ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
 306 {
 307   int ret;
 308 
 309   ctx->aclv_entries[0].a_type = USER_OBJ;
 310   ctx->aclv_entries[0].a_id = 0; /* irrelevant */
 311   ctx->aclv_entries[0].a_perm = (ctx->mode >> 6) & 7;
 312   ctx->aclv_entries[1].a_type = GROUP_OBJ;
 313   ctx->aclv_entries[1].a_id = 0; /* irrelevant */
 314   ctx->aclv_entries[1].a_perm = (ctx->mode >> 3) & 7;
 315   ctx->aclv_entries[2].a_type = CLASS_OBJ;
 316   ctx->aclv_entries[2].a_id = 0;
 317   ctx->aclv_entries[2].a_perm = (ctx->mode >> 3) & 7;
 318   ctx->aclv_entries[3].a_type = OTHER_OBJ;
 319   ctx->aclv_entries[3].a_id = 0;
 320   ctx->aclv_entries[3].a_perm = ctx->mode & 7;
 321   ctx->aclv_count = 4;
 322 
 323   ret = aclsort (ctx->aclv_count, 1, ctx->aclv_entries);
 324   if (ret > 0)
 325     abort ();
 326   return ret;
 327 }
 328 #  endif
 329 
 330 # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
 331 static int
 332 set_acls_from_mode (const char *name, int desc, mode_t mode, bool *must_chmod)
     /* [previous][next][first][last][top][bottom][index][help] */
 333 {
 334   acl_type_list_t types;
 335   size_t types_size = sizeof (types);
 336   acl_type_t type;
 337 
 338   if (aclx_gettypes (name, &types, &types_size) < 0
 339       || types.num_entries == 0)
 340     {
 341       *must_chmod = true;
 342       return 0;
 343     }
 344 
 345   /* XXX Do we need to clear all types of ACLs for the given file, or is it
 346      sufficient to clear the first one?  */
 347   type = types.entries[0];
 348   if (type.u64 == ACL_AIXC)
 349     {
 350       union { struct acl a; char room[128]; } u;
 351       int ret;
 352 
 353       u.a.acl_len = (char *) &u.a.acl_ext[0] - (char *) &u.a; /* no entries */
 354       u.a.acl_mode = mode & ~(S_IXACL | 0777);
 355       u.a.u_access = (mode >> 6) & 7;
 356       u.a.g_access = (mode >> 3) & 7;
 357       u.a.o_access = mode & 7;
 358 
 359       if (desc != -1)
 360         ret = aclx_fput (desc, SET_ACL | SET_MODE_S_BITS,
 361                          type, &u.a, u.a.acl_len, mode);
 362       else
 363         ret = aclx_put (name, SET_ACL | SET_MODE_S_BITS,
 364                         type, &u.a, u.a.acl_len, mode);
 365       if (!(ret < 0 && errno == ENOSYS))
 366         return ret;
 367     }
 368   else if (type.u64 == ACL_NFS4)
 369     {
 370       union { nfs4_acl_int_t a; char room[128]; } u;
 371       nfs4_ace_int_t *ace;
 372       int ret;
 373 
 374       u.a.aclVersion = NFS4_ACL_INT_STRUCT_VERSION;
 375       u.a.aclEntryN = 0;
 376       ace = &u.a.aclEntry[0];
 377       {
 378         ace->flags = ACE4_ID_SPECIAL;
 379         ace->aceWho.special_whoid = ACE4_WHO_OWNER;
 380         ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE;
 381         ace->aceFlags = 0;
 382         ace->aceMask =
 383           (mode & 0400 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0)
 384           | (mode & 0200
 385              ? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA
 386                | ACE4_ADD_SUBDIRECTORY
 387              : 0)
 388           | (mode & 0100 ? ACE4_EXECUTE : 0);
 389         ace->aceWhoString[0] = '\0';
 390         ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace;
 391         ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4];
 392         u.a.aclEntryN++;
 393       }
 394       {
 395         ace->flags = ACE4_ID_SPECIAL;
 396         ace->aceWho.special_whoid = ACE4_WHO_GROUP;
 397         ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE;
 398         ace->aceFlags = 0;
 399         ace->aceMask =
 400           (mode & 0040 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0)
 401           | (mode & 0020
 402              ? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA
 403                | ACE4_ADD_SUBDIRECTORY
 404              : 0)
 405           | (mode & 0010 ? ACE4_EXECUTE : 0);
 406         ace->aceWhoString[0] = '\0';
 407         ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace;
 408         ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4];
 409         u.a.aclEntryN++;
 410       }
 411       {
 412         ace->flags = ACE4_ID_SPECIAL;
 413         ace->aceWho.special_whoid = ACE4_WHO_EVERYONE;
 414         ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE;
 415         ace->aceFlags = 0;
 416         ace->aceMask =
 417           (mode & 0004 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0)
 418           | (mode & 0002
 419              ? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA
 420                | ACE4_ADD_SUBDIRECTORY
 421              : 0)
 422           | (mode & 0001 ? ACE4_EXECUTE : 0);
 423         ace->aceWhoString[0] = '\0';
 424         ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace;
 425         ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4];
 426         u.a.aclEntryN++;
 427       }
 428       u.a.aclLength = (char *) ace - (char *) &u.a;
 429 
 430       if (desc != -1)
 431         ret = aclx_fput (desc, SET_ACL | SET_MODE_S_BITS,
 432                          type, &u.a, u.a.aclLength, mode);
 433       else
 434         ret = aclx_put (name, SET_ACL | SET_MODE_S_BITS,
 435                         type, &u.a, u.a.aclLength, mode);
 436       if (!(ret < 0 && errno == ENOSYS))
 437         return ret;
 438     }
 439 
 440   *must_chmod = true;
 441   return 0;
 442 }
 443 
 444 # elif HAVE_STATACL /* older AIX */
 445 static int
 446 context_acl_from_mode (struct permission_context *ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
 447 {
 448   ctx->u.a.acl_len = (char *) &ctx->u.a.acl_ext[0] - (char *) &ctx->u.a; /* no entries */
 449   ctx->u.a.acl_mode = ctx->mode & ~(S_IXACL | 0777);
 450   ctx->u.a.u_access = (ctx->mode >> 6) & 7;
 451   ctx->u.a.g_access = (ctx->mode >> 3) & 7;
 452   ctx->u.a.o_access = ctx->mode & 7;
 453   ctx->have_u = true;
 454   return 0;
 455 }
 456 
 457 # elif HAVE_ACLSORT /* NonStop Kernel */
 458 static int
 459 context_acl_from_mode (struct permission_context *ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
 460 {
 461   int ret;
 462 
 463   ctx->entries[0].a_type = USER_OBJ;
 464   ctx->entries[0].a_id = 0; /* irrelevant */
 465   ctx->entries[0].a_perm = (ctx->mode >> 6) & 7;
 466   ctx->entries[1].a_type = GROUP_OBJ;
 467   ctx->entries[1].a_id = 0; /* irrelevant */
 468   ctx->entries[1].a_perm = (ctx->mode >> 3) & 7;
 469   ctx->entries[2].a_type = CLASS_OBJ;
 470   ctx->entries[2].a_id = 0;
 471   ctx->entries[2].a_perm = (ctx->mode >> 3) & 7;
 472   ctx->entries[3].a_type = OTHER_OBJ;
 473   ctx->entries[3].a_id = 0;
 474   ctx->entries[3].a_perm = ctx->mode & 7;
 475   ctx->count = 4;
 476 
 477   ret = aclsort (ctx->count, 1, entries);
 478   if (ret > 0)
 479     abort ();
 480   return ret;
 481 }
 482 # endif
 483 
 484 static int
 485 set_acls (struct permission_context *ctx, const char *name, int desc,
     /* [previous][next][first][last][top][bottom][index][help] */
 486           int from_mode, bool *must_chmod, bool *acls_set)
 487 {
 488   int ret = 0;
 489 
 490 # if HAVE_ACL_GET_FILE
 491   /* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
 492   /* Linux, FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */
 493 #  if !HAVE_ACL_TYPE_EXTENDED
 494   /* Linux, FreeBSD, IRIX, Tru64, Cygwin >= 2.5 */
 495 
 496 #   ifndef HAVE_ACL_FROM_TEXT
 497 #    error Must have acl_from_text (see POSIX 1003.1e draft 17).
 498 #   endif
 499 #   ifndef HAVE_ACL_DELETE_DEF_FILE
 500 #    error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
 501 #   endif
 502 
 503   if (! ctx->acls_not_supported)
 504     {
 505       if (ret == 0 && from_mode)
 506         {
 507           if (ctx->acl)
 508             acl_free (ctx->acl);
 509           ctx->acl = acl_from_mode (ctx->mode);
 510           if (ctx->acl == NULL)
 511             ret = -1;
 512         }
 513 
 514       if (ret == 0 && ctx->acl)
 515         {
 516           if (HAVE_ACL_SET_FD && desc != -1)
 517             ret = acl_set_fd (desc, ctx->acl);
 518           else
 519             ret = acl_set_file (name, ACL_TYPE_ACCESS, ctx->acl);
 520           if (ret != 0)
 521             {
 522               if (! acl_errno_valid (errno))
 523                 {
 524                   ctx->acls_not_supported = true;
 525                   if (from_mode || acl_access_nontrivial (ctx->acl) == 0)
 526                     ret = 0;
 527                 }
 528             }
 529           else
 530             {
 531               *acls_set = true;
 532               if (S_ISDIR(ctx->mode))
 533                 {
 534                   if (! from_mode && ctx->default_acl &&
 535                       acl_default_nontrivial (ctx->default_acl))
 536                     ret = acl_set_file (name, ACL_TYPE_DEFAULT,
 537                                         ctx->default_acl);
 538                   else
 539                     ret = acl_delete_def_file (name);
 540                 }
 541             }
 542         }
 543     }
 544 
 545 #   if HAVE_ACL_TYPE_NFS4  /* FreeBSD */
 546 
 547   /* File systems either support POSIX ACLs (for example, ufs) or NFS4 ACLs
 548      (for example, zfs). */
 549 
 550   /* TODO: Implement setting ACLs once get_permissions() reads them. */
 551 
 552 #   endif
 553 
 554 #  else /* HAVE_ACL_TYPE_EXTENDED */
 555   /* Mac OS X */
 556 
 557   /* On Mac OS X,  acl_get_file (name, ACL_TYPE_ACCESS)
 558      and           acl_get_file (name, ACL_TYPE_DEFAULT)
 559      always return NULL / EINVAL.  You have to use
 560                    acl_get_file (name, ACL_TYPE_EXTENDED)
 561      or            acl_get_fd (open (name, ...))
 562      to retrieve an ACL.
 563      On the other hand,
 564                    acl_set_file (name, ACL_TYPE_ACCESS, acl)
 565      and           acl_set_file (name, ACL_TYPE_DEFAULT, acl)
 566      have the same effect as
 567                    acl_set_file (name, ACL_TYPE_EXTENDED, acl):
 568      Each of these calls sets the file's ACL.  */
 569 
 570   if (ctx->acl == NULL)
 571     {
 572       acl_t acl;
 573 
 574       /* Remove ACLs if the file has ACLs.  */
 575       if (HAVE_ACL_GET_FD && desc != -1)
 576         acl = acl_get_fd (desc);
 577       else
 578         acl = acl_get_file (name, ACL_TYPE_EXTENDED);
 579       if (acl)
 580         {
 581           acl_free (acl);
 582 
 583           acl = acl_init (0);
 584           if (acl)
 585             {
 586               if (HAVE_ACL_SET_FD && desc != -1)
 587                 ret = acl_set_fd (desc, acl);
 588               else
 589                 ret = acl_set_file (name, ACL_TYPE_EXTENDED, acl);
 590               acl_free (acl);
 591             }
 592           else
 593             ret = -1;
 594         }
 595     }
 596   else
 597     {
 598       if (HAVE_ACL_SET_FD && desc != -1)
 599         ret = acl_set_fd (desc, ctx->acl);
 600       else
 601         ret = acl_set_file (name, ACL_TYPE_EXTENDED, ctx->acl);
 602       if (ret != 0)
 603         {
 604           if (! acl_errno_valid (errno)
 605               && ! acl_extended_nontrivial (ctx->acl))
 606             ret = 0;
 607         }
 608     }
 609   *acls_set = true;
 610 
 611 #  endif
 612 
 613 # elif defined GETACL /* Solaris, Cygwin, not HP-UX */
 614 
 615   /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
 616      of Unixware.  The acl() call returns the access and default ACL both
 617      at once.  */
 618 
 619   /* If both ace_entries and entries are available, try SETACL before
 620      ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL
 621      can.  */
 622 
 623   if (from_mode)
 624     return set_acls_from_mode (name, desc, ctx->mode, must_chmod);
 625 
 626   if (ret == 0 && ctx->count)
 627     {
 628       if (desc != -1)
 629         ret = facl (desc, SETACL, ctx->count, ctx->entries);
 630       else
 631         ret = acl (name, SETACL, ctx->count, ctx->entries);
 632       if (ret < 0)
 633         {
 634           if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
 635               && acl_nontrivial (ctx->count, ctx->entries) == 0)
 636             ret = 0;
 637         }
 638       else
 639         *acls_set = true;
 640     }
 641 
 642 #  ifdef ACE_GETACL
 643   if (ret == 0 && ctx->ace_count)
 644     {
 645       if (desc != -1)
 646         ret = facl (desc, ACE_SETACL, ctx->ace_count, ctx->ace_entries);
 647       else
 648         ret = acl (name, ACE_SETACL, ctx->ace_count, ctx->ace_entries);
 649       if (ret < 0)
 650         {
 651           if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP)
 652               && acl_ace_nontrivial (ctx->ace_count, ctx->ace_entries) == 0)
 653             ret = 0;
 654         }
 655       else
 656         *acls_set = true;
 657     }
 658 #  endif
 659 
 660 # elif HAVE_GETACL /* HP-UX */
 661 
 662   if (from_mode)
 663     ret = context_acl_from_mode (ctx, name, desc);
 664 
 665   if (ret == 0 && ctx->count > 0)
 666     {
 667       if (desc != -1)
 668         ret = fsetacl (desc, ctx->count, ctx->entries);
 669       else
 670         ret = setacl (name, ctx->count, ctx->entries);
 671       if (ret < 0)
 672         {
 673           if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
 674               && (from_mode || !acl_nontrivial (ctx->count, ctx->entries)))
 675             ret = 0;
 676         }
 677       else
 678         *acls_set = true;
 679     }
 680 
 681 #  if HAVE_ACLV_H
 682   if (from_mode)
 683     ret = context_aclv_from_mode (ctx);
 684 
 685   if (ret == 0 && ctx->aclv_count > 0)
 686     {
 687       ret = acl ((char *) name, ACL_SET, ctx->aclv_count, ctx->aclv_entries);
 688       if (ret < 0)
 689         {
 690           if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
 691               && (from_mode || !aclv_nontrivial (ctx->aclv_count, ctx->aclv_entries)))
 692             ret = 0;
 693         }
 694       else
 695         *acls_set = true;
 696     }
 697 #  endif
 698 
 699 # elif HAVE_ACLX_GET && ACL_AIX_WIP /* AIX */
 700 
 701   /* TODO: Implement setting ACLs once get_permissions() reads them. */
 702 
 703   if (from_mode)
 704     ret = set_acls_from_mode (name, desc, mode, must_chmod);
 705 
 706 # elif HAVE_STATACL /* older AIX */
 707 
 708   if (from_mode)
 709     ret = context_acl_from_mode (ctx);
 710 
 711   if (ret == 0 && ctx->have_u)
 712     {
 713       if (desc != -1)
 714         ret = fchacl (desc, &ctx->u.a, ctx->u.a.acl_len);
 715       else
 716         ret = chacl ((char *) name, &ctx->u.a, ctx->u.a.acl_len);
 717       if (ret < 0)
 718         {
 719           if (errno == ENOSYS && from_mode)
 720             ret = 0;
 721         }
 722       else
 723         *acls_set = true;
 724     }
 725 
 726 # elif HAVE_ACLSORT /* NonStop Kernel */
 727 
 728   if (from_mode)
 729     ret = context_acl_from_mode (ctx);
 730 
 731   if (ret == 0 && ctx->count)
 732     {
 733       ret = acl ((char *) name, ACL_SET, ctx->count, ctx->entries);
 734       if (ret != 0)
 735         {
 736           if (!acl_nontrivial (ctx->count, ctx->entries))
 737             ret = 0;
 738         }
 739       else
 740         *acls_set = true;
 741     }
 742 
 743 # else  /* No ACLs */
 744 
 745   /* Nothing to do. */
 746 
 747 # endif
 748 
 749   return ret;
 750 }
 751 #endif
 752 
 753 /* If DESC is a valid file descriptor use fchmod to change the
 754    file's mode to MODE on systems that have fchmod. On systems
 755    that don't have fchmod and if DESC is invalid, use chmod on
 756    NAME instead.
 757    Return 0 if successful.  Return -1 and set errno upon failure.  */
 758 
 759 int
 760 chmod_or_fchmod (const char *name, int desc, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 761 {
 762   if (HAVE_FCHMOD && desc != -1)
 763     return fchmod (desc, mode);
 764   else
 765     return chmod (name, mode);
 766 }
 767 
 768 /* Set the permissions in CTX on a file. If DESC is a valid file descriptor,
 769    use file descriptor operations, else use filename based operations on NAME.
 770    If access control lists are not available, fchmod the target file to the
 771    mode in CTX.  Also sets the non-permission bits of the destination file
 772    (S_ISUID, S_ISGID, S_ISVTX) to those from the mode in CTX if any are set.
 773    Return 0 if successful.  Return -1 and set errno upon failure.  */
 774 
 775 int
 776 set_permissions (struct permission_context *ctx, const char *name, int desc)
     /* [previous][next][first][last][top][bottom][index][help] */
 777 {
 778   _GL_UNUSED bool acls_set = false;
 779   bool early_chmod;
 780   bool must_chmod = false;
 781   int ret = 0;
 782 
 783 #if USE_ACL
 784 # if HAVE_STATACL
 785   /* older AIX */
 786   /* There is no need to call chmod_or_fchmod, since the mode
 787      bits S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL.  */
 788 
 789   early_chmod = false;
 790 # else
 791   /* All other platforms */
 792   /* On Cygwin, it is necessary to call chmod before acl, because
 793      chmod can change the contents of the ACL (in ways that don't
 794      change the allowed accesses, but still visible).  */
 795 
 796   early_chmod = (! MODE_INSIDE_ACL || (ctx->mode & (S_ISUID | S_ISGID | S_ISVTX)));
 797 # endif
 798 #else
 799   /* No ACLs */
 800 
 801   early_chmod = true;
 802 #endif
 803 
 804   if (early_chmod)
 805     {
 806       ret = chmod_or_fchmod (name, desc, ctx->mode);
 807       if (ret != 0)
 808         return -1;
 809     }
 810 
 811 #if USE_ACL
 812   ret = set_acls (ctx, name, desc, false, &must_chmod, &acls_set);
 813   if (! acls_set)
 814     {
 815       int saved_errno = ret ? errno : 0;
 816 
 817       /* If we can't set an acl which we expect to be able to set, try setting
 818          the permissions to ctx->mode. Due to possible inherited permissions,
 819          we cannot simply chmod.  */
 820 
 821       ret = set_acls (ctx, name, desc, true, &must_chmod, &acls_set);
 822       if (! acls_set)
 823         must_chmod = true;
 824 
 825       if (saved_errno)
 826         {
 827           errno = saved_errno;
 828           ret = -1;
 829         }
 830     }
 831 #endif
 832 
 833   if (must_chmod && ! early_chmod)
 834     {
 835       int saved_errno = ret ? errno : 0;
 836 
 837       ret = chmod_or_fchmod (name, desc, ctx->mode);
 838 
 839       if (saved_errno)
 840         {
 841           errno = saved_errno;
 842           ret = -1;
 843         }
 844     }
 845 
 846   return ret;
 847 }

/* [previous][next][first][last][top][bottom][index][help] */