int qset_acl (char const *name, int desc, mode_t mode) { #if USE_ACL # if HAVE_ACL_GET_FILE /* POSIX 1003.1e draft 17 (abandoned) specific version. */ /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */ # if MODE_INSIDE_ACL /* Linux, FreeBSD, IRIX, Tru64 */ /* We must also have acl_from_text and acl_delete_def_file. (acl_delete_def_file could be emulated with acl_init followed by acl_set_file, but acl_set_file with an empty acl is unspecified.) */ # ifndef HAVE_ACL_FROM_TEXT # error Must have acl_from_text (see POSIX 1003.1e draft 17). # endif # ifndef HAVE_ACL_DELETE_DEF_FILE # error Must have acl_delete_def_file (see POSIX 1003.1e draft 17). # endif acl_t acl; int ret; if (HAVE_ACL_FROM_MODE) /* Linux */ { acl = acl_from_mode (mode); if (!acl) return -1; } else /* FreeBSD, IRIX, Tru64 */ { /* If we were to create the ACL using the functions acl_init(), acl_create_entry(), acl_set_tag_type(), acl_set_qualifier(), acl_get_permset(), acl_clear_perm[s](), acl_add_perm(), we would need to create a qualifier. I don't know how to do this. So create it using acl_from_text(). */ # if HAVE_ACL_FREE_TEXT /* Tru64 */ char acl_text[] = "u::---,g::---,o::---,"; # else /* FreeBSD, IRIX */ char acl_text[] = "u::---,g::---,o::---"; # endif if (mode & S_IRUSR) acl_text[ 3] = 'r'; if (mode & S_IWUSR) acl_text[ 4] = 'w'; if (mode & S_IXUSR) acl_text[ 5] = 'x'; if (mode & S_IRGRP) acl_text[10] = 'r'; if (mode & S_IWGRP) acl_text[11] = 'w'; if (mode & S_IXGRP) acl_text[12] = 'x'; if (mode & S_IROTH) acl_text[17] = 'r'; if (mode & S_IWOTH) acl_text[18] = 'w'; if (mode & S_IXOTH) acl_text[19] = 'x'; acl = acl_from_text (acl_text); if (!acl) return -1; } if (HAVE_ACL_SET_FD && desc != -1) ret = acl_set_fd (desc, acl); else ret = acl_set_file (name, ACL_TYPE_ACCESS, acl); if (ret != 0) { int saved_errno = errno; acl_free (acl); if (ACL_NOT_WELL_SUPPORTED (errno)) return chmod_or_fchmod (name, desc, mode); else { errno = saved_errno; return -1; } } else acl_free (acl); if (S_ISDIR (mode) && acl_delete_def_file (name)) return -1; if (mode & (S_ISUID | S_ISGID | S_ISVTX)) { /* We did not call chmod so far, so the special bits have not yet been set. */ return chmod_or_fchmod (name, desc, mode); } return 0; # else /* !MODE_INSIDE_ACL */ /* MacOS X */ # if !HAVE_ACL_TYPE_EXTENDED # error Must have ACL_TYPE_EXTENDED # endif /* On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS) and acl_get_file (name, ACL_TYPE_DEFAULT) always return NULL / EINVAL. You have to use acl_get_file (name, ACL_TYPE_EXTENDED) or acl_get_fd (open (name, ...)) to retrieve an ACL. On the other hand, acl_set_file (name, ACL_TYPE_ACCESS, acl) and acl_set_file (name, ACL_TYPE_DEFAULT, acl) have the same effect as acl_set_file (name, ACL_TYPE_EXTENDED, acl): Each of these calls sets the file's ACL. */ acl_t acl; int ret; /* Remove the ACL if the file has ACLs. */ if (HAVE_ACL_GET_FD && desc != -1) acl = acl_get_fd (desc); else acl = acl_get_file (name, ACL_TYPE_EXTENDED); if (acl) { acl_free (acl); acl = acl_init (0); if (acl) { if (HAVE_ACL_SET_FD && desc != -1) ret = acl_set_fd (desc, acl); else ret = acl_set_file (name, ACL_TYPE_EXTENDED, acl); if (ret != 0) { int saved_errno = errno; acl_free (acl); if (ACL_NOT_WELL_SUPPORTED (saved_errno)) return chmod_or_fchmod (name, desc, mode); else { errno = saved_errno; return -1; } } acl_free (acl); } } /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */ return chmod_or_fchmod (name, desc, mode); # endif # elif HAVE_ACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */ # if defined ACL_NO_TRIVIAL /* Solaris 10 (newer version), which has additional API declared in <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial, acl_fromtext, ...). */ acl_t *aclp; char acl_text[] = "user::---,group::---,mask:---,other:---"; int ret; int saved_errno; if (mode & S_IRUSR) acl_text[ 6] = 'r'; if (mode & S_IWUSR) acl_text[ 7] = 'w'; if (mode & S_IXUSR) acl_text[ 8] = 'x'; if (mode & S_IRGRP) acl_text[17] = acl_text[26] = 'r'; if (mode & S_IWGRP) acl_text[18] = acl_text[27] = 'w'; if (mode & S_IXGRP) acl_text[19] = acl_text[28] = 'x'; if (mode & S_IROTH) acl_text[36] = 'r'; if (mode & S_IWOTH) acl_text[37] = 'w'; if (mode & S_IXOTH) acl_text[38] = 'x'; if (acl_fromtext (acl_text, &aclp) != 0) { errno = ENOMEM; return -1; } ret = (desc < 0 ? acl_set (name, aclp) : facl_set (desc, aclp)); saved_errno = errno; acl_free (aclp); if (ret < 0) { if (saved_errno == ENOSYS || saved_errno == EOPNOTSUPP) return chmod_or_fchmod (name, desc, mode); errno = saved_errno; return -1; } if (mode & (S_ISUID | S_ISGID | S_ISVTX)) { /* We did not call chmod so far, so the special bits have not yet been set. */ return chmod_or_fchmod (name, desc, mode); } return 0; # else /* Solaris, Cygwin, general case */ # ifdef ACE_GETACL /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4 file systems (whereas the other ones are used in UFS file systems). */ /* The flags in the ace_t structure changed in a binary incompatible way when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> version 1.15. How to distinguish the two conventions at runtime? We fetch the existing ACL. In the old convention, usually three ACEs have a_flags = ACE_OWNER / ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400. In the new convention, these values are not used. */ int convention; { int count; ace_t *entries; for (;;) { if (desc != -1) count = facl (desc, ACE_GETACLCNT, 0, NULL); else count = acl (name, ACE_GETACLCNT, 0, NULL); if (count <= 0) { convention = -1; break; } entries = (ace_t *) malloc (count * sizeof (ace_t)); if (entries == NULL) { errno = ENOMEM; return -1; } if ((desc != -1 ? facl (desc, ACE_GETACL, count, entries) : acl (name, ACE_GETACL, count, entries)) == count) { int i; convention = 0; for (i = 0; i < count; i++) if (entries[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_OTHER)) { convention = 1; break; } free (entries); break; } /* Huh? The number of ACL entries changed since the last call. Repeat. */ free (entries); } } if (convention >= 0) { ace_t entries[3]; int ret; if (convention) { /* Running on Solaris 10. */ entries[0].a_type = ALLOW; entries[0].a_flags = ACE_OWNER; entries[0].a_who = 0; /* irrelevant */ entries[0].a_access_mask = (mode >> 6) & 7; entries[1].a_type = ALLOW; entries[1].a_flags = ACE_GROUP; entries[1].a_who = 0; /* irrelevant */ entries[1].a_access_mask = (mode >> 3) & 7; entries[2].a_type = ALLOW; entries[2].a_flags = ACE_OTHER; entries[2].a_who = 0; entries[2].a_access_mask = mode & 7; } else {
int CheckDefaultClearACL(char *file_path, Attributes a, Promise *pp) { acl_t acl_existing; acl_t acl_empty; acl_entry_t ace_dummy; int retv; int result = false; acl_existing = NULL; acl_empty = NULL; if ((acl_existing = acl_get_file(file_path, ACL_TYPE_DEFAULT)) == NULL) { CfOut(OUTPUT_LEVEL_ERROR, "acl_get_file", "Unable to read default acl for %s", file_path); return false; } retv = acl_get_entry(acl_existing, ACL_FIRST_ENTRY, &ace_dummy); switch (retv) { case -1: CfOut(OUTPUT_LEVEL_VERBOSE, "acl_get_entry", "Couldn't retrieve ACE for %s", file_path); result = false; break; case 0: // no entries, as desired cfPS(OUTPUT_LEVEL_INFORM, CF_NOP, "", pp, a, "-> Default ACL on \"%s\" needs no modification.", file_path); result = true; break; case 1: // entries exist, set empty ACL if ((acl_empty = acl_init(0)) == NULL) { CfOut(OUTPUT_LEVEL_ERROR, "", "Could not reinitialize ACL for %s", file_path); result = false; break; } switch (a.transaction.action) { case cfa_warn: cfPS(OUTPUT_LEVEL_ERROR, CF_WARN, "", pp, a, " !! Default ACL on \"%s\" needs to be cleared", file_path); break; case cfa_fix: if (!DONTDO) { if (acl_set_file(file_path, ACL_TYPE_DEFAULT, acl_empty) != 0) { CfOut(OUTPUT_LEVEL_ERROR, "", "Could not reset ACL for %s", file_path); result = false; break; } } cfPS(OUTPUT_LEVEL_INFORM, CF_CHG, "", pp, a, "-> Default ACL on \"%s\" successfully cleared", file_path); result = true; break; default: ProgrammingError("Cfengine: internal error: illegal file action\n"); result = false; } break; default: result = false; } acl_free(acl_empty); acl_free(acl_existing); return result; }
static unsigned int call_syscall(struct syscall_desc *scall, char *argv[]) { struct stat64 sb; long long flags; unsigned int i; char *endp; int name, rval; union { char *str; long long num; } args[MAX_ARGS]; #ifdef HAS_FREEBSD_ACL int entry_id = ACL_FIRST_ENTRY; acl_t acl, newacl; acl_entry_t entry, newentry; #endif /* * Verify correctness of the arguments. */ for (i = 0; i < sizeof(args)/sizeof(args[0]); i++) { if (scall->sd_args[i] == TYPE_NONE) { if (argv[i] == NULL || strcmp(argv[i], ":") == 0) break; fprintf(stderr, "too many arguments [%s]\n", argv[i]); exit(1); } else { if (argv[i] == NULL || strcmp(argv[i], ":") == 0) { if (scall->sd_args[i] & TYPE_OPTIONAL) break; fprintf(stderr, "too few arguments\n"); exit(1); } if ((scall->sd_args[i] & TYPE_MASK) == TYPE_STRING) { if (strcmp(argv[i], "NULL") == 0) args[i].str = NULL; else if (strcmp(argv[i], "DEADCODE") == 0) args[i].str = (void *)0xdeadc0de; else args[i].str = argv[i]; } else if ((scall->sd_args[i] & TYPE_MASK) == TYPE_NUMBER) { args[i].num = strtoll(argv[i], &endp, 0); if (*endp != '\0' && !isspace((unsigned char)*endp)) { fprintf(stderr, "invalid argument %u, number expected [%s]\n", i, endp); exit(1); } } else if ((scall->sd_args[i] & TYPE_MASK) == TYPE_DESCRIPTOR) { if (strcmp(argv[i], "AT_FDCWD") == 0) { args[i].num = AT_FDCWD; } else if (strcmp(argv[i], "BADFD") == 0) { /* In case AT_FDCWD is -1 on some systems... */ if (AT_FDCWD == -1) args[i].num = -2; else args[i].num = -1; } else { int pos; pos = strtoll(argv[i], &endp, 0); if (*endp != '\0' && !isspace((unsigned char)*endp)) { fprintf(stderr, "invalid argument %u, number expected [%s]\n", i, endp); exit(1); } args[i].num = descriptor_get(pos); } } } } /* * Call the given syscall. */ #define NUM(n) (args[(n)].num) #define STR(n) (args[(n)].str) switch (scall->sd_action) { case ACTION_OPEN: flags = str2flags(open_flags, STR(1)); if (flags & O_CREAT) { if (i == 2) { fprintf(stderr, "too few arguments\n"); exit(1); } rval = open(STR(0), (int)flags, (mode_t)NUM(2)); } else { if (i == 3) { fprintf(stderr, "too many arguments\n"); exit(1); } rval = open(STR(0), (int)flags); } if (rval >= 0) descriptor_add(rval); break; case ACTION_OPENAT: flags = str2flags(open_flags, STR(2)); if (flags & O_CREAT) { if (i == 3) { fprintf(stderr, "too few arguments\n"); exit(1); } rval = openat(NUM(0), STR(1), (int)flags, (mode_t)NUM(3)); } else { if (i == 4) { fprintf(stderr, "too many arguments\n"); exit(1); } rval = openat(NUM(0), STR(1), (int)flags); } if (rval >= 0) descriptor_add(rval); break; case ACTION_CREATE: rval = open(STR(0), O_CREAT | O_EXCL, (mode_t)NUM(1)); if (rval >= 0) close(rval); break; case ACTION_UNLINK: rval = unlink(STR(0)); break; case ACTION_UNLINKAT: rval = unlinkat(NUM(0), STR(1), (int)str2flags(unlinkat_flags, STR(2))); break; case ACTION_MKDIR: rval = mkdir(STR(0), (mode_t)NUM(1)); break; case ACTION_MKDIRAT: rval = mkdirat(NUM(0), STR(1), (mode_t)NUM(2)); break; case ACTION_RMDIR: rval = rmdir(STR(0)); break; case ACTION_LINK: rval = link(STR(0), STR(1)); break; case ACTION_LINKAT: rval = linkat(NUM(0), STR(1), NUM(2), STR(3), (int)str2flags(linkat_flags, STR(4))); break; case ACTION_SYMLINK: rval = symlink(STR(0), STR(1)); break; case ACTION_SYMLINKAT: rval = symlinkat(STR(0), NUM(1), STR(2)); break; case ACTION_RENAME: rval = rename(STR(0), STR(1)); break; case ACTION_RENAMEAT: rval = renameat(NUM(0), STR(1), NUM(2), STR(3)); break; case ACTION_MKFIFO: rval = mkfifo(STR(0), (mode_t)NUM(1)); break; case ACTION_MKFIFOAT: rval = mkfifoat(NUM(0), STR(1), (mode_t)NUM(2)); break; case ACTION_MKNOD: case ACTION_MKNODAT: { mode_t ntype; dev_t dev; int fa; switch (scall->sd_action) { case ACTION_MKNOD: fa = 0; break; case ACTION_MKNODAT: fa = 1; break; default: abort(); } dev = makedev(NUM(fa + 3), NUM(fa + 4)); if (strcmp(STR(fa + 1), "c") == 0) /* character device */ ntype = S_IFCHR; else if (strcmp(STR(fa + 1), "b") == 0) /* block device */ ntype = S_IFBLK; else if (strcmp(STR(fa + 1), "f") == 0) /* fifo special */ ntype = S_IFIFO; else if (strcmp(STR(fa + 1), "d") == 0) /* directory */ ntype = S_IFDIR; else if (strcmp(STR(fa + 1), "o") == 0) /* regular file */ ntype = S_IFREG; else { fprintf(stderr, "wrong argument 1\n"); exit(1); } switch (scall->sd_action) { case ACTION_MKNOD: rval = mknod(STR(0), ntype | NUM(2), dev); break; case ACTION_MKNODAT: rval = mknodat(NUM(0), STR(1), ntype | NUM(3), dev); break; default: abort(); } break; } case ACTION_BIND: { struct sockaddr_un sunx; sunx.sun_family = AF_UNIX; strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1); sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; rval = socket(AF_UNIX, SOCK_STREAM, 0); if (rval < 0) break; rval = bind(rval, (struct sockaddr *)&sunx, sizeof(sunx)); break; } #ifdef HAS_BINDAT case ACTION_BINDAT: { struct sockaddr_un sunx; sunx.sun_family = AF_UNIX; strncpy(sunx.sun_path, STR(1), sizeof(sunx.sun_path) - 1); sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; rval = socket(AF_UNIX, SOCK_STREAM, 0); if (rval < 0) break; rval = bindat(NUM(0), rval, (struct sockaddr *)&sunx, sizeof(sunx)); break; } #endif case ACTION_CONNECT: { struct sockaddr_un sunx; sunx.sun_family = AF_UNIX; strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1); sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; rval = socket(AF_UNIX, SOCK_STREAM, 0); if (rval < 0) break; rval = connect(rval, (struct sockaddr *)&sunx, sizeof(sunx)); break; } #ifdef HAS_CONNECTAT case ACTION_CONNECTAT: { struct sockaddr_un sunx; sunx.sun_family = AF_UNIX; strncpy(sunx.sun_path, STR(1), sizeof(sunx.sun_path) - 1); sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; rval = socket(AF_UNIX, SOCK_STREAM, 0); if (rval < 0) break; rval = connectat(NUM(0), rval, (struct sockaddr *)&sunx, sizeof(sunx)); break; } #endif case ACTION_CHMOD: rval = chmod(STR(0), (mode_t)NUM(1)); break; case ACTION_FCHMOD: rval = fchmod(NUM(0), (mode_t)NUM(1)); break; #ifdef HAS_LCHMOD case ACTION_LCHMOD: rval = lchmod(STR(0), (mode_t)NUM(1)); break; #endif case ACTION_FCHMODAT: rval = fchmodat(NUM(0), STR(1), (mode_t)NUM(2), str2flags(fchmodat_flags, STR(3))); break; case ACTION_CHOWN: rval = chown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2)); break; case ACTION_FCHOWN: rval = fchown(NUM(0), (uid_t)NUM(1), (gid_t)NUM(2)); break; case ACTION_LCHOWN: rval = lchown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2)); break; case ACTION_FCHOWNAT: rval = fchownat(NUM(0), STR(1), (uid_t)NUM(2), (gid_t)NUM(3), (int)str2flags(fchownat_flags, STR(4))); break; #ifdef HAS_CHFLAGS case ACTION_CHFLAGS: rval = chflags(STR(0), (unsigned long)str2flags(chflags_flags, STR(1))); break; #endif #ifdef HAS_FCHFLAGS case ACTION_FCHFLAGS: rval = fchflags(NUM(0), (unsigned long)str2flags(chflags_flags, STR(1))); break; #endif #ifdef HAS_LCHFLAGS case ACTION_LCHFLAGS: rval = lchflags(STR(0), (int)str2flags(chflags_flags, STR(1))); break; #endif case ACTION_TRUNCATE: rval = truncate64(STR(0), NUM(1)); break; case ACTION_FTRUNCATE: rval = ftruncate64(NUM(0), NUM(1)); break; case ACTION_STAT: rval = stat64(STR(0), &sb); if (rval == 0) { show_stats(&sb, STR(1)); return (i); } break; case ACTION_FSTAT: rval = fstat64(NUM(0), &sb); if (rval == 0) { show_stats(&sb, STR(1)); return (i); } break; case ACTION_LSTAT: rval = lstat64(STR(0), &sb); if (rval == 0) { show_stats(&sb, STR(1)); return (i); } break; case ACTION_FSTATAT: rval = fstatat(NUM(0), STR(1), &sb, (int)str2flags(fstatat_flags, STR(2))); if (rval == 0) { show_stats(&sb, STR(3)); return (i); } break; case ACTION_PATHCONF: case ACTION_FPATHCONF: case ACTION_LPATHCONF: { long lrval; name = str2name(pathconf_names, STR(1)); if (name == -1) { fprintf(stderr, "unknown name %s", STR(1)); exit(1); } errno = 0; switch (scall->sd_action) { case ACTION_PATHCONF: lrval = pathconf(STR(0), name); break; case ACTION_FPATHCONF: lrval = fpathconf(NUM(0), name); break; case ACTION_LPATHCONF: lrval = lpathconf(STR(0), name); break; default: abort(); } if (lrval == -1 && errno == 0) { printf("unlimited\n"); return (i); } else if (lrval >= 0) { printf("%ld\n", lrval); return (i); } rval = -1; break; } #ifdef HAS_FREEBSD_ACL case ACTION_PREPENDACL: rval = -1; acl = acl_get_file(STR(0), ACL_TYPE_NFS4); if (acl == NULL) break; newacl = acl_from_text(STR(1)); if (acl == NULL) break; while (acl_get_entry(newacl, entry_id, &newentry) == 1) { entry_id = ACL_NEXT_ENTRY; if (acl_create_entry_np(&acl, &entry, 0)) break; if (acl_copy_entry(entry, newentry)) break; } rval = acl_set_file(STR(0), ACL_TYPE_NFS4, acl); break; case ACTION_READACL: acl = acl_get_file(STR(0), ACL_TYPE_NFS4); if (acl == NULL) rval = -1; else rval = 0; break; #endif case ACTION_WRITE: rval = write(NUM(0), STR(1), strlen(STR(1))); break; default: fprintf(stderr, "unsupported syscall\n"); exit(1); } #undef STR #undef NUM if (rval < 0) { const char *serrno; serrno = err2str(errno); fprintf(stderr, "%s returned %d\n", scall->sd_name, rval); printf("%s\n", serrno); exit(1); } printf("0\n"); return (i); }
static int qcopy_acl (const char *src_name, int source_desc, const char *dst_name, int dest_desc, mode_t mode) { #if USE_ACL && HAVE_ACL_GET_FILE /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */ # if MODE_INSIDE_ACL /* Linux, FreeBSD, IRIX, Tru64 */ acl_t acl; int ret; if (HAVE_ACL_GET_FD && source_desc != -1) acl = acl_get_fd (source_desc); else acl = acl_get_file (src_name, ACL_TYPE_ACCESS); if (acl == NULL) { if (ACL_NOT_WELL_SUPPORTED (errno)) return qset_acl (dst_name, dest_desc, mode); else return -2; } if (HAVE_ACL_SET_FD && dest_desc != -1) ret = acl_set_fd (dest_desc, acl); else ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl); if (ret != 0) { int saved_errno = errno; if (ACL_NOT_WELL_SUPPORTED (errno) && !acl_access_nontrivial (acl)) { acl_free (acl); return chmod_or_fchmod (dst_name, dest_desc, mode); } else { acl_free (acl); chmod_or_fchmod (dst_name, dest_desc, mode); errno = saved_errno; return -1; } } else acl_free (acl); if (mode & (S_ISUID | S_ISGID | S_ISVTX)) { /* We did not call chmod so far, and either the mode and the ACL are separate or special bits are to be set which don't fit into ACLs. */ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) return -1; } if (S_ISDIR (mode)) { acl = acl_get_file (src_name, ACL_TYPE_DEFAULT); if (acl == NULL) return -2; if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl)) { int saved_errno = errno; acl_free (acl); errno = saved_errno; return -1; } else acl_free (acl); } return 0; # else /* !MODE_INSIDE_ACL */ /* MacOS X */ # if !HAVE_ACL_TYPE_EXTENDED # error Must have ACL_TYPE_EXTENDED # endif /* On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS) and acl_get_file (name, ACL_TYPE_DEFAULT) always return NULL / EINVAL. You have to use acl_get_file (name, ACL_TYPE_EXTENDED) or acl_get_fd (open (name, ...)) to retrieve an ACL. On the other hand, acl_set_file (name, ACL_TYPE_ACCESS, acl) and acl_set_file (name, ACL_TYPE_DEFAULT, acl) have the same effect as acl_set_file (name, ACL_TYPE_EXTENDED, acl): Each of these calls sets the file's ACL. */ acl_t acl; int ret; if (HAVE_ACL_GET_FD && source_desc != -1) acl = acl_get_fd (source_desc); else acl = acl_get_file (src_name, ACL_TYPE_EXTENDED); if (acl == NULL) { if (ACL_NOT_WELL_SUPPORTED (errno)) return qset_acl (dst_name, dest_desc, mode); else return -2; } if (HAVE_ACL_SET_FD && dest_desc != -1) ret = acl_set_fd (dest_desc, acl); else ret = acl_set_file (dst_name, ACL_TYPE_EXTENDED, acl); if (ret != 0) { int saved_errno = errno; if (ACL_NOT_WELL_SUPPORTED (errno) && !acl_extended_nontrivial (acl)) { acl_free (acl); return chmod_or_fchmod (dst_name, dest_desc, mode); } else { acl_free (acl); chmod_or_fchmod (dst_name, dest_desc, mode); errno = saved_errno; return -1; } } else acl_free (acl); /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */ return chmod_or_fchmod (dst_name, dest_desc, mode); # endif #elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ # if defined ACL_NO_TRIVIAL /* Solaris 10 (newer version), which has additional API declared in <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial, acl_fromtext, ...). */ int ret; acl_t *aclp = NULL; ret = (source_desc < 0 ? acl_get (src_name, ACL_NO_TRIVIAL, &aclp) : facl_get (source_desc, ACL_NO_TRIVIAL, &aclp)); if (ret != 0 && errno != ENOSYS) return -2; ret = qset_acl (dst_name, dest_desc, mode); if (ret != 0) return -1; if (aclp) { ret = (dest_desc < 0 ? acl_set (dst_name, aclp) : facl_set (dest_desc, aclp)); if (ret != 0) { int saved_errno = errno; acl_free (aclp); errno = saved_errno; return -1; } acl_free (aclp); } return 0; # else /* Solaris, Cygwin, general case */ /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions of Unixware. The acl() call returns the access and default ACL both at once. */ # ifdef ACE_GETACL int ace_count; ace_t *ace_entries; # endif int count; aclent_t *entries; int did_chmod; int saved_errno; int ret; # ifdef ACE_GETACL /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4 file systems (whereas the other ones are used in UFS file systems). There is an API pathconf (name, _PC_ACL_ENABLED) fpathconf (desc, _PC_ACL_ENABLED) that allows to determine which of the two kinds of ACLs is supported for the given file. But some file systems may implement this call incorrectly, so better not use it. When fetching the source ACL, we simply fetch both ACL types. When setting the destination ACL, we try either ACL types, assuming that the kernel will translate the ACL from one form to the other. (See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view> the description of ENOTSUP.) */ for (;;) { ace_count = (source_desc != -1 ? facl (source_desc, ACE_GETACLCNT, 0, NULL) : acl (src_name, ACE_GETACLCNT, 0, NULL)); if (ace_count < 0) { if (errno == ENOSYS || errno == EINVAL) { ace_count = 0; ace_entries = NULL; break; } else return -2; } if (ace_count == 0) { ace_entries = NULL; break; } ace_entries = (ace_t *) malloc (ace_count * sizeof (ace_t)); if (ace_entries == NULL) { errno = ENOMEM; return -2; } if ((source_desc != -1 ? facl (source_desc, ACE_GETACL, ace_count, ace_entries) : acl (src_name, ACE_GETACL, ace_count, ace_entries)) == ace_count) break; /* Huh? The number of ACL entries changed since the last call. Repeat. */ } # endif for (;;) { count = (source_desc != -1 ? facl (source_desc, GETACLCNT, 0, NULL) : acl (src_name, GETACLCNT, 0, NULL)); if (count < 0) { if (errno == ENOSYS || errno == ENOTSUP) { count = 0; entries = NULL; break; } else return -2; } if (count == 0) { entries = NULL; break; } entries = (aclent_t *) malloc (count * sizeof (aclent_t)); if (entries == NULL) { errno = ENOMEM; return -2; } if ((source_desc != -1 ? facl (source_desc, GETACL, count, entries) : acl (src_name, GETACL, count, entries)) == count) break; /* Huh? The number of ACL entries changed since the last call. Repeat. */ } /* Is there an ACL of either kind? */ # ifdef ACE_GETACL if (ace_count == 0) # endif if (count == 0) return qset_acl (dst_name, dest_desc, mode); did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */ saved_errno = 0; /* the first non-ignorable error code */ if (!MODE_INSIDE_ACL) { /* On Cygwin, it is necessary to call chmod before acl, because chmod can change the contents of the ACL (in ways that don't change the allowed accesses, but still visible). */ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) saved_errno = errno; did_chmod = 1; } /* If both ace_entries and entries are available, try SETACL before ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL can. */ if (count > 0) { ret = (dest_desc != -1 ? facl (dest_desc, SETACL, count, entries) : acl (dst_name, SETACL, count, entries)); if (ret < 0 && saved_errno == 0) { saved_errno = errno; if (errno == ENOSYS && !acl_nontrivial (count, entries)) saved_errno = 0; } else did_chmod = 1; } free (entries); # ifdef ACE_GETACL if (ace_count > 0) { ret = (dest_desc != -1 ? facl (dest_desc, ACE_SETACL, ace_count, ace_entries) : acl (dst_name, ACE_SETACL, ace_count, ace_entries)); if (ret < 0 && saved_errno == 0) { saved_errno = errno; if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP) && !acl_ace_nontrivial (ace_count, ace_entries)) saved_errno = 0; } } free (ace_entries); # endif if (MODE_INSIDE_ACL && did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0)) { /* We did not call chmod so far, and either the mode and the ACL are separate or special bits are to be set which don't fit into ACLs. */ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) { if (saved_errno == 0) saved_errno = errno; } } if (saved_errno) { errno = saved_errno; return -1; } return 0; # endif #elif USE_ACL && HAVE_GETACL /* HP-UX */ int count; struct acl_entry entries[NACLENTRIES]; int ret; for (;;) { count = (source_desc != -1 ? fgetacl (source_desc, 0, NULL) : getacl (src_name, 0, NULL)); if (count < 0) { if (errno == ENOSYS || errno == EOPNOTSUPP) { count = 0; break; } else return -2; } if (count == 0) break; if (count > NACLENTRIES) /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */ abort (); if ((source_desc != -1 ? fgetacl (source_desc, count, entries) : getacl (src_name, count, entries)) == count) break; /* Huh? The number of ACL entries changed since the last call. Repeat. */ } if (count == 0) return qset_acl (dst_name, dest_desc, mode); ret = (dest_desc != -1 ? fsetacl (dest_desc, count, entries) : setacl (dst_name, count, entries)); if (ret < 0) { int saved_errno = errno; if (errno == ENOSYS || errno == EOPNOTSUPP) { struct stat source_statbuf; if ((source_desc != -1 ? fstat (source_desc, &source_statbuf) : stat (src_name, &source_statbuf)) == 0) { if (!acl_nontrivial (count, entries, &source_statbuf)) return chmod_or_fchmod (dst_name, dest_desc, mode); } else saved_errno = errno; } chmod_or_fchmod (dst_name, dest_desc, mode); errno = saved_errno; return -1; } if (mode & (S_ISUID | S_ISGID | S_ISVTX)) { /* We did not call chmod so far, and either the mode and the ACL are separate or special bits are to be set which don't fit into ACLs. */ return chmod_or_fchmod (dst_name, dest_desc, mode); } return 0; #elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */ /* TODO */ #elif USE_ACL && HAVE_STATACL /* older AIX */ union { struct acl a; char room[4096]; } u; int ret; if ((source_desc != -1 ? fstatacl (source_desc, STX_NORMAL, &u.a, sizeof (u)) : statacl (src_name, STX_NORMAL, &u.a, sizeof (u))) < 0) return -2; ret = (dest_desc != -1 ? fchacl (dest_desc, &u.a, u.a.acl_len) : chacl (dst_name, &u.a, u.a.acl_len)); if (ret < 0) { int saved_errno = errno; chmod_or_fchmod (dst_name, dest_desc, mode); errno = saved_errno; return -1; } /* No need to call chmod_or_fchmod at this point, since the mode bits S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL. */ return 0; #else return qset_acl (dst_name, dest_desc, mode); #endif }
int main(int argc, char *argv[]) { acl_t acl; acl_type_t type; acl_entry_t entry; acl_tag_t tag; uid_t *uidp; gid_t *gidp; acl_permset_t permset; char *name; int entryId, permVal, opt; type = ACL_TYPE_ACCESS; while ((opt = getopt(argc, argv, "d")) != -1) { switch (opt) { case 'd': type = ACL_TYPE_DEFAULT; break; case '?': usageError(argv[0]); } } if (optind + 1 != argc) usageError(argv[0]); acl = acl_get_file(argv[optind], type); if (acl == NULL) errExit("acl_get_file"); /* Walk through each entry in this ACL */ for (entryId = ACL_FIRST_ENTRY; ; entryId = ACL_NEXT_ENTRY) { if (acl_get_entry(acl, entryId, &entry) != 1) break; /* Exit on error or no more entries */ /* Retrieve and display tag type */ if (acl_get_tag_type(entry, &tag) == -1) errExit("acl_get_tag_type"); printf("%-12s", (tag == ACL_USER_OBJ) ? "user_obj" : (tag == ACL_USER) ? "user" : (tag == ACL_GROUP_OBJ) ? "group_obj" : (tag == ACL_GROUP) ? "group" : (tag == ACL_MASK) ? "mask" : (tag == ACL_OTHER) ? "other" : "???"); /* Retrieve and display optional tag qualifier */ if (tag == ACL_USER) { uidp = acl_get_qualifier(entry); if (uidp == NULL) errExit("acl_get_qualifier"); name = groupNameFromId(*uidp); if (name == NULL) printf("%-8d ", *uidp); else printf("%-8s ", name); if (acl_free(uidp) == -1) errExit("acl_free"); } else if (tag == ACL_GROUP) { gidp = acl_get_qualifier(entry); if (gidp == NULL) errExit("acl_get_qualifier"); name = groupNameFromId(*gidp); if (name == NULL) printf("%-8d ", *gidp); else printf("%-8s ", name); if (acl_free(gidp) == -1) errExit("acl_free"); } else { printf(" "); } /* Retrieve and display permissions */ if (acl_get_permset(entry, &permset) == -1) errExit("acl_get_permset"); permVal = acl_get_perm(permset, ACL_READ); if (permVal == -1) errExit("acl_get_perm - ACL_READ"); printf("%c", (permVal == 1) ? 'r' : '-'); permVal = acl_get_perm(permset, ACL_WRITE); if (permVal == -1) errExit("acl_get_perm - ACL_WRITE"); printf("%c", (permVal == 1) ? 'w' : '-'); permVal = acl_get_perm(permset, ACL_EXECUTE); if (permVal == -1) errExit("acl_get_perm - ACL_EXECUTE"); printf("%c", (permVal == 1) ? 'x' : '-'); printf("\n"); } if (acl_free(acl) == -1) errExit("acl_free"); exit(EXIT_SUCCESS); }
static int CheckDefaultEqualsAccessACL(EvalContext *ctx, const char *file_path, Attributes a, const Promise *pp, PromiseResult *result) { acl_t acl_access; acl_t acl_default; int equals; int retval = false; acl_access = NULL; acl_default = NULL; if ((acl_access = acl_get_file(file_path, ACL_TYPE_ACCESS)) == NULL) { Log(LOG_LEVEL_ERR, "Could not find an ACL for '%s'. (acl_get_file: %s)", file_path, GetErrorStr()); return false; } acl_default = acl_get_file(file_path, ACL_TYPE_DEFAULT); if (acl_default == NULL) { Log(LOG_LEVEL_ERR, "Could not find default ACL for '%s'. (acl_get_file: %s)", file_path, GetErrorStr()); acl_free(acl_access); return false; } equals = ACLEquals(acl_access, acl_default); switch (equals) { case 0: // they equal, as desired cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_NOOP, pp, a, "Default ACL on '%s' needs no modification.", file_path); retval = true; break; case 1: // set access ACL as default ACL switch (a.transaction.action) { case cfa_warn: cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_WARN, pp, a, "Default ACL on '%s' needs to be copied from access ACL.", file_path); *result = PromiseResultUpdate(*result, PROMISE_RESULT_WARN); break; case cfa_fix: if (!DONTDO) { if ((acl_set_file(file_path, ACL_TYPE_DEFAULT, acl_access)) != 0) { Log(LOG_LEVEL_ERR, "Could not set default ACL to access"); acl_free(acl_access); acl_free(acl_default); return false; } } cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_CHANGE, pp, a, "Default ACL on '%s' successfully copied from access ACL.", file_path); *result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE); retval = true; break; default: ProgrammingError("CFEngine: internal error: illegal file action"); retval = false; } break; default: retval = false; Log(LOG_LEVEL_ERR, "Unable to compare access and default ACEs"); } acl_free(acl_access); acl_free(acl_default); return retval; }
/* * This function is a copy of the same function in udev, written by Kay * Sievers, you can find it in udev in extras/udev-acl/udev-acl.c */ static int set_facl(const char* filename, uid_t uid, int add) { int get; acl_t acl; acl_entry_t entry = NULL; acl_entry_t e; acl_permset_t permset; int ret; /* don't touch ACLs for root */ if (uid == 0) return 0; /* read current record */ acl = acl_get_file(filename, ACL_TYPE_ACCESS); if (!acl) return -1; /* locate ACL_USER entry for uid */ get = acl_get_entry(acl, ACL_FIRST_ENTRY, &e); while (get == 1) { acl_tag_t t; acl_get_tag_type(e, &t); if (t == ACL_USER) { uid_t *u; u = (uid_t*)acl_get_qualifier(e); if (u == NULL) { ret = -1; goto out; } if (*u == uid) { entry = e; acl_free(u); break; } acl_free(u); } get = acl_get_entry(acl, ACL_NEXT_ENTRY, &e); } /* remove ACL_USER entry for uid */ if (!add) { if (entry == NULL) { ret = 0; goto out; } acl_delete_entry(acl, entry); goto update; } /* create ACL_USER entry for uid */ if (entry == NULL) { ret = acl_create_entry(&acl, &entry); if (ret != 0) goto out; acl_set_tag_type(entry, ACL_USER); acl_set_qualifier(entry, &uid); } /* add permissions for uid */ acl_get_permset(entry, &permset); acl_add_perm(permset, ACL_READ|ACL_WRITE); update: /* update record */ acl_calc_mask(&acl); ret = acl_set_file(filename, ACL_TYPE_ACCESS, acl); if (ret != 0) goto out; out: acl_free(acl); return ret; }
int devnode_acl(const char *path, bool flush, bool del, uid_t old_uid, bool add, uid_t new_uid) { acl_t acl; int r = 0; bool changed = false; assert(path); acl = acl_get_file(path, ACL_TYPE_ACCESS); if (!acl) return -errno; if (flush) { r = flush_acl(acl); if (r < 0) goto finish; if (r > 0) changed = true; } else if (del && old_uid > 0) { acl_entry_t entry; r = acl_find_uid(acl, old_uid, &entry); if (r < 0) goto finish; if (r > 0) { if (acl_delete_entry(acl, entry) < 0) { r = -errno; goto finish; } changed = true; } } if (add && new_uid > 0) { acl_entry_t entry; acl_permset_t permset; int rd, wt; r = acl_find_uid(acl, new_uid, &entry); if (r < 0) goto finish; if (r == 0) { if (acl_create_entry(&acl, &entry) < 0) { r = -errno; goto finish; } if (acl_set_tag_type(entry, ACL_USER) < 0 || acl_set_qualifier(entry, &new_uid) < 0) { r = -errno; goto finish; } } if (acl_get_permset(entry, &permset) < 0) { r = -errno; goto finish; } rd = acl_get_perm(permset, ACL_READ); if (rd < 0) { r = -errno; goto finish; } wt = acl_get_perm(permset, ACL_WRITE); if (wt < 0) { r = -errno; goto finish; } if (!rd || !wt) { if (acl_add_perm(permset, ACL_READ|ACL_WRITE) < 0) { r = -errno; goto finish; } changed = true; } } if (!changed) goto finish; if (acl_calc_mask(&acl) < 0) { r = -errno; goto finish; } if (acl_set_file(path, ACL_TYPE_ACCESS, acl) < 0) { r = -errno; goto finish; } r = 0; finish: acl_free(acl); return r; }
int main (int argc, char *argv[]) { if (argc != 4) { usage(argv[0]); } char mode; if (strcmp(argv[1], "u") == 0) { mode = 'u'; } else if (strcmp(argv[1], "g") == 0) { mode = 'g'; } else { usage(argv[0]); } uid_t uid; gid_t gid; if (mode == 'u') { uid = userIdFromName(argv[2]); if (uid == -1) { errExit("couldn't find user %s\n", argv[2]); } } else { // mode == 'g' gid = groupIdFromName(argv[2]); if (gid == -1) { errExit("couldn't find group %s\n", argv[2]); } } char *filepath = argv[3]; struct stat stats; if (stat(filepath, &stats) == -1) { errExit("stat\n"); } acl_t acl = acl_get_file(filepath, ACL_TYPE_ACCESS); if (acl == NULL) { errExit("acl_get_file\n"); } acl_entry_t entry; acl_tag_t tag; int entryId; int mask_found = 0; acl_entry_t mask; for (entryId = ACL_FIRST_ENTRY; ; entryId = ACL_NEXT_ENTRY) { if (acl_get_entry(acl, entryId, &entry) == 1) { break; } if ((tag = acl_get_tag_type(entry, &tag)) == -1) { errExit("acl_get_tag_type\n"); } if (tag == ACL_MASK) { mask_found = 1; mask = entry; break; } } acl_entry_t needle; uid_t *uid_p; gid_t *gid_p; for (entryId = ACL_FIRST_ENTRY; ; entryId = ACL_NEXT_ENTRY) { if (acl_get_entry(acl, entryId, &entry) != 1) { errExit( "couldn't find an entry for the specified %s\n", mode == 'u' ? "user" : "group" ); } if (acl_get_tag_type(entry, &tag) == -1) { errExit("acl_get_tag_type\n"); } if (mode == 'u') { if (uid == stats.st_uid && tag == ACL_USER_OBJ) { needle = entry; break; } if (tag != ACL_USER) { continue; } uid_p = acl_get_qualifier(entry); if (uid_p == NULL) { errExit("acl_get_qualifier\n"); } if (*uid_p == uid) { needle = entry; break; } } if (mode == 'g') { if (gid == stats.st_gid && tag == ACL_GROUP_OBJ) { needle = entry; break; } if (tag != ACL_GROUP) { continue; } gid_p = acl_get_qualifier(entry); if (gid_p == NULL) { errExit("acl_get_qualifier\n"); } if (*gid_p == gid) { needle = entry; break; } } } acl_permset_t needle_perms; if (acl_get_permset(needle, &needle_perms) == -1) { errExit("acl_get_permset\n"); } printPerms(needle_perms); printf("\n"); if (mask_found && !(mode == 'u' && uid == stats.st_uid && tag == ACL_USER_OBJ)) { acl_permset_t mask_perms; if (acl_get_permset(mask, &mask_perms) == -1) { errExit("acl_get_permset\n"); } printf("Effective permissions: "); if (maskPermset(needle_perms, mask_perms) == -1) { errExit("maskPermset\n"); } printPerms(needle_perms); printf("\n"); } exit(EXIT_SUCCESS); }
int modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int position, int inheritance_level, int follow) { acl_t oacl = NULL; unsigned aindex = 0, flag_new_acl = 0; acl_entry_t newent = NULL; acl_entry_t entry = NULL; unsigned retval = 0; extern int chmod_fflag; /* XXX acl_get_file() returns a zero entry ACL if an ACL was previously * associated with the file, and has had its entries removed. * However, POSIX 1003.1e states that a zero entry ACL should be * returned if the caller asks for ACL_TYPE_DEFAULT, and no ACL is * associated with the path; it * does not specifically state that a request for ACL_TYPE_EXTENDED * should not return a zero entry ACL, however. */ /* Determine if we've been given a zero entry ACL, or create an ACL if * none exists. There are some issues to consider here: Should we create * a zero-entry ACL for a delete or check canonicity operation? */ if (path == NULL) chmod_usage(); if (optflags & ACL_CLEAR_FLAG) { filesec_t fsec = filesec_init(); if (fsec == NULL) { // err(1, "filesec_init() failed"); fprintf(stderr, "chmod: filesec_init() failed: %s\n", strerror(errno)); pthread_exit(NULL); } if (filesec_set_property(fsec, FILESEC_ACL, _FILESEC_REMOVE_ACL) != 0) { // err(1, "filesec_set_property() failed"); fprintf(stderr, "chmod: filesec_set_property() failed: %s\n", strerror(errno)); pthread_exit(NULL); } if (follow) { if (chmodx_np(path, fsec) != 0) { if (!chmod_fflag) { // warn("Failed to clear ACL on file %s", path); fprintf(stderr, "chmod: Failed to clear ACL on file %s: %s\n", path, strerror(errno)); } retval = 1; } } else { int fd = open(path, O_SYMLINK); if (fd != -1) { if (fchmodx_np(fd, fsec) != 0) { if (!chmod_fflag) { fprintf(stderr, "chmod: Failed to clear ACL on file %s: %s\n", path, strerror(errno)); // warn("Failed to clear ACL on file %s", path); } retval = 1; } close(fd); } else { if (!chmod_fflag) { // warn("Failed to open file %s", path); fprintf(stderr, "chmod: Failed to open file %s: %s\n", path, strerror(errno)); } retval = 1; } } filesec_free(fsec); return (retval); } if (optflags & ACL_FROM_STDIN) { oacl = acl_dup(modifier); } else { if (follow) { oacl = acl_get_file(path, ACL_TYPE_EXTENDED); } else { int fd = open(path, O_SYMLINK); if (fd != -1) { oacl = acl_get_fd_np(fd, ACL_TYPE_EXTENDED); close(fd); } } if ((oacl == NULL) || (acl_get_entry(oacl,ACL_FIRST_ENTRY, &newent) != 0)) { if ((oacl = acl_init(1)) == NULL) { // err(1, "acl_init() failed"); fprintf(stderr, "chmod: acl_init() failed: %s\n", strerror(errno)); pthread_exit(NULL); } flag_new_acl = 1; position = 0; } if ((0 == flag_new_acl) && (optflags & (ACL_REMOVE_INHERIT_FLAG | ACL_REMOVE_INHERITED_ENTRIES))) { acl_t facl = NULL; if ((facl = acl_init(1)) == NULL) { //err(1, "acl_init() failed"); fprintf(stderr, "chmod: acl_init() failed: %s\n", strerror(errno)); pthread_exit(NULL); } for (aindex = 0; acl_get_entry(oacl, (entry == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY), &entry) == 0; aindex++) { acl_flagset_t eflags; acl_entry_t fent = NULL; if (acl_get_flagset_np(entry, &eflags) != 0) { fprintf(stderr, "chmod: Unable to obtain flagset: %s\n", strerror(errno)); pthread_exit(NULL); // err(1, "Unable to obtain flagset"); } if (acl_get_flag_np(eflags, ACL_ENTRY_INHERITED)) { if (optflags & ACL_REMOVE_INHERIT_FLAG) { acl_delete_flag_np(eflags, ACL_ENTRY_INHERITED); acl_set_flagset_np(entry, eflags); acl_create_entry(&facl, &fent); acl_copy_entry(fent, entry); } } else { acl_create_entry(&facl, &fent); acl_copy_entry(fent, entry); } } if (oacl) acl_free(oacl); oacl = facl; } else if (optflags & ACL_TO_STDOUT) { ssize_t len; /* need to get printacl() from ls(1) */ char *text = acl_to_text(oacl, &len); puts(text); acl_free(text); } else if (optflags & ACL_CHECK_CANONICITY) { if (flag_new_acl) { // warnx("No ACL currently associated with file '%s'", path); fprintf(stderr, "chmod: No ACL currently associated with file '%s'\n", path); } retval = is_canonical(oacl); } else if ((optflags & ACL_SET_FLAG) && (position == -1) && (!is_canonical(oacl))) { // warnx("The specified file '%s' does not have an ACL in canonical order, please specify a position with +a# ", path); fprintf(stderr, "chmod: The specified file '%s' does not have an ACL in canonical order, please specify a position with +a# \n", path); retval = 1; } else if (((optflags & ACL_DELETE_FLAG) && (position != -1)) || (optflags & ACL_CHECK_CANONICITY)) { retval = modify_acl(&oacl, NULL, optflags, position, inheritance_level, flag_new_acl, path); } else if ((optflags & (ACL_REMOVE_INHERIT_FLAG|ACL_REMOVE_INHERITED_ENTRIES)) && flag_new_acl) { // warnx("No ACL currently associated with file '%s'", path); fprintf(stderr, "chmod: No ACL currently associated with file '%s'\n", path); retval = 1; } else { if (!modifier) { /* avoid bus error in acl_get_entry */ // errx(1, "Internal error: modifier should not be NULL"); fprintf(stderr, "Internal error: modifier should not be NULL\n"); pthread_exit(NULL); } for (aindex = 0; acl_get_entry(modifier, (entry == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY), &entry) == 0; aindex++) { retval += modify_acl(&oacl, entry, optflags, position, inheritance_level, flag_new_acl, path); } } } /* XXX Potential race here, since someone else could've modified or * read the ACL on this file (with the intention of modifying it) in * the interval from acl_get_file() to acl_set_file(); we can * minimize one aspect of this window by comparing the original acl * to a fresh one from acl_get_file() but we could consider a * "changeset" mechanism, common locking strategy, or kernel * supplied reservation mechanism to prevent this race. */ if (!(optflags & (ACL_TO_STDOUT|ACL_CHECK_CANONICITY))) { int status = -1; if (follow) { status = acl_set_file(path, ACL_TYPE_EXTENDED, oacl); } else { int fd = open(path, O_SYMLINK); if (fd != -1) { status = acl_set_fd_np(fd, oacl, ACL_TYPE_EXTENDED); close(fd); } } if (status != 0) { if (!chmod_fflag) fprintf(stderr, "chmod: Failed to set ACL on file '%s': %s\n", path, strerror(errno)); // warn("Failed to set ACL on file '%s'", path); retval = 1; } } if (oacl) acl_free(oacl); return retval; }
int rpmVerifyFile(const rpmts ts, const rpmfi fi, rpmVerifyAttrs * res, rpmVerifyAttrs omitMask) { rpm_mode_t fmode = rpmfiFMode(fi); rpmfileAttrs fileAttrs = rpmfiFFlags(fi); rpmVerifyAttrs flags = rpmfiVFlags(fi); const char * fn = rpmfiFN(fi); struct stat sb; int rc; *res = RPMVERIFY_NONE; /* * Check to see if the file was installed - if not pretend all is OK. */ switch (rpmfiFState(fi)) { case RPMFILE_STATE_NETSHARED: case RPMFILE_STATE_REPLACED: case RPMFILE_STATE_NOTINSTALLED: case RPMFILE_STATE_WRONGCOLOR: return 0; break; case RPMFILE_STATE_NORMAL: break; } if (fn == NULL || lstat(fn, &sb) != 0) { *res |= RPMVERIFY_LSTATFAIL; return 1; } /* * Not all attributes of non-regular files can be verified. */ if (S_ISDIR(sb.st_mode)) flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_LINKTO | RPMVERIFY_CAPS); else if (S_ISLNK(sb.st_mode)) { flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_MODE | RPMVERIFY_CAPS); #if CHOWN_FOLLOWS_SYMLINK flags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP); #endif } else if (S_ISFIFO(sb.st_mode)) flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_LINKTO | RPMVERIFY_CAPS); else if (S_ISCHR(sb.st_mode)) flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_LINKTO | RPMVERIFY_CAPS); else if (S_ISBLK(sb.st_mode)) flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_LINKTO | RPMVERIFY_CAPS); else flags &= ~(RPMVERIFY_LINKTO); /* * Content checks of %ghost files are meaningless. */ if (fileAttrs & RPMFILE_GHOST) flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_LINKTO); /* * Don't verify any features in omitMask. */ flags &= ~(omitMask | RPMVERIFY_FAILURES); if (flags & RPMVERIFY_MD5) { const unsigned char *digest; pgpHashAlgo algo; size_t diglen; /* XXX If --nomd5, then prelinked library sizes are not corrected. */ if ((digest = rpmfiFDigest(fi, &algo, &diglen))) { unsigned char fdigest[diglen]; rpm_loff_t fsize; rc = rpmDoDigest(algo, fn, 0, fdigest, &fsize); sb.st_size = fsize; if (rc) { *res |= (RPMVERIFY_READFAIL|RPMVERIFY_MD5); } else if (memcmp(fdigest, digest, diglen)) { *res |= RPMVERIFY_MD5; } } else { *res |= RPMVERIFY_MD5; } } if (flags & RPMVERIFY_LINKTO) { char linkto[1024+1]; int size = 0; if ((size = readlink(fn, linkto, sizeof(linkto)-1)) == -1) *res |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO); else { const char * flink = rpmfiFLink(fi); linkto[size] = '\0'; if (flink == NULL || strcmp(linkto, flink)) *res |= RPMVERIFY_LINKTO; } } if (flags & RPMVERIFY_FILESIZE) { if (sb.st_size != rpmfiFSize(fi)) *res |= RPMVERIFY_FILESIZE; } if (flags & RPMVERIFY_MODE) { rpm_mode_t metamode = fmode; rpm_mode_t filemode; /* * Platforms (like AIX) where sizeof(rpm_mode_t) != sizeof(mode_t) * need the (rpm_mode_t) cast here. */ filemode = (rpm_mode_t)sb.st_mode; /* * Comparing the type of %ghost files is meaningless, but perms are OK. */ if (fileAttrs & RPMFILE_GHOST) { metamode &= ~0xf000; filemode &= ~0xf000; } if (metamode != filemode) *res |= RPMVERIFY_MODE; #if WITH_ACL /* * For now, any non-default acl's on a file is a difference as rpm * cannot have set them. */ acl_t facl = acl_get_file(fn, ACL_TYPE_ACCESS); if (facl) { if (acl_equiv_mode(facl, NULL) == 1) { *res |= RPMVERIFY_MODE; } acl_free(facl); } #endif } if (flags & RPMVERIFY_RDEV) { if (S_ISCHR(fmode) != S_ISCHR(sb.st_mode) || S_ISBLK(fmode) != S_ISBLK(sb.st_mode)) { *res |= RPMVERIFY_RDEV; } else if (S_ISDEV(fmode) && S_ISDEV(sb.st_mode)) { rpm_rdev_t st_rdev = (sb.st_rdev & 0xffff); rpm_rdev_t frdev = (rpmfiFRdev(fi) & 0xffff); if (st_rdev != frdev) *res |= RPMVERIFY_RDEV; } } #if WITH_CAP if (flags & RPMVERIFY_CAPS) { /* * Empty capability set ("=") is not exactly the same as no * capabilities at all but suffices for now... */ cap_t cap, fcap; cap = cap_from_text(rpmfiFCaps(fi)); if (!cap) { cap = cap_from_text("="); } fcap = cap_get_file(fn); if (!fcap) { fcap = cap_from_text("="); } if (cap_compare(cap, fcap) != 0) *res |= RPMVERIFY_CAPS; cap_free(fcap); cap_free(cap); } #endif if ((flags & RPMVERIFY_MTIME) && (sb.st_mtime != rpmfiFMtime(fi))) { /* Filter out timestamp differences of shared files */ rpmdbMatchIterator mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, fn, 0); if (rpmdbGetIteratorCount(mi) < 2) *res |= RPMVERIFY_MTIME; rpmdbFreeIterator(mi); } if (flags & RPMVERIFY_USER) { const char * name = uidToUname(sb.st_uid); const char * fuser = rpmfiFUser(fi); if (name == NULL || fuser == NULL || strcmp(name, fuser)) *res |= RPMVERIFY_USER; } if (flags & RPMVERIFY_GROUP) { const char * name = gidToGname(sb.st_gid); const char * fgroup = rpmfiFGroup(fi); if (name == NULL || fgroup == NULL || strcmp(name, fgroup)) *res |= RPMVERIFY_GROUP; } return 0; }
static int print_acl(char *path, acl_type_t type, int hflag, int iflag, int nflag, int qflag, int vflag) { struct stat sb; acl_t acl; char *acl_text; int error, flags = 0, ret; if (hflag) error = lstat(path, &sb); else error = stat(path, &sb); if (error == -1) { warn("%s: stat() failed", path); return(-1); } if (hflag) ret = lpathconf(path, _PC_ACL_NFS4); else ret = pathconf(path, _PC_ACL_NFS4); if (ret > 0) { if (type == ACL_TYPE_DEFAULT) { warnx("%s: there are no default entries in NFSv4 ACLs", path); return (-1); } type = ACL_TYPE_NFS4; } else if (ret < 0 && errno != EINVAL) { warn("%s: pathconf(..., _PC_ACL_NFS4) failed", path); return (-1); } if (more_than_one) printf("\n"); else more_than_one++; if (!qflag) printf("# file: %s\n# owner: %s\n# group: %s\n", path, getuname(sb.st_uid), getgname(sb.st_gid)); if (hflag) acl = acl_get_link_np(path, type); else acl = acl_get_file(path, type); if (!acl) { if (errno != EOPNOTSUPP) { warn("%s", path); return(-1); } errno = 0; if (type == ACL_TYPE_DEFAULT) return(0); acl = acl_from_stat(sb); if (!acl) { warn("%s: acl_from_stat() failed", path); return(-1); } } if (iflag) flags |= ACL_TEXT_APPEND_ID; if (nflag) flags |= ACL_TEXT_NUMERIC_IDS; if (vflag) flags |= ACL_TEXT_VERBOSE; acl_text = acl_to_text_np(acl, 0, flags); if (!acl_text) { warn("%s: acl_to_text_np() failed", path); return(-1); } printf("%s", acl_text); (void)acl_free(acl); (void)acl_free(acl_text); return(0); }
int file_has_acl (char const *name, struct stat const *sb) { #if USE_ACL if (! S_ISLNK (sb->st_mode)) { # if HAVE_ACL_GET_FILE /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */ int ret; if (HAVE_ACL_EXTENDED_FILE) /* Linux */ { /* On Linux, acl_extended_file is an optimized function: It only makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for ACL_TYPE_DEFAULT. */ ret = acl_extended_file (name); } else /* FreeBSD, MacOS X, IRIX, Tru64 */ { # if HAVE_ACL_TYPE_EXTENDED /* MacOS X */ /* On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS) and acl_get_file (name, ACL_TYPE_DEFAULT) always return NULL / EINVAL. There is no point in making these two useless calls. The real ACL is retrieved through acl_get_file (name, ACL_TYPE_EXTENDED). */ acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED); if (acl) { ret = acl_extended_nontrivial (acl); acl_free (acl); } else ret = -1; # else /* FreeBSD, IRIX, Tru64 */ acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS); if (acl) { int saved_errno; ret = acl_access_nontrivial (acl); saved_errno = errno; acl_free (acl); errno = saved_errno; # if HAVE_ACL_FREE_TEXT /* Tru64 */ /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always returns NULL with errno not set. There is no point in making this call. */ # else /* FreeBSD, IRIX */ /* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS) and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory either both succeed or both fail; it depends on the file system. Therefore there is no point in making the second call if the first one already failed. */ if (ret == 0 && S_ISDIR (sb->st_mode)) { acl = acl_get_file (name, ACL_TYPE_DEFAULT); if (acl) { ret = (0 < acl_entries (acl)); acl_free (acl); } else ret = -1; } # endif } else ret = -1; # endif } if (ret < 0) return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1; return ret; # elif HAVE_ACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */ # if defined ACL_NO_TRIVIAL /* Solaris 10 (newer version), which has additional API declared in <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial, acl_fromtext, ...). */ return acl_trivial (name); # else /* Solaris, Cygwin, general case */ /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions of Unixware. The acl() call returns the access and default ACL both at once. */ int count; { aclent_t *entries; for (;;) { count = acl (name, GETACLCNT, 0, NULL); if (count < 0) { if (errno == ENOSYS || errno == ENOTSUP) break; else return -1; } if (count == 0) break; /* Don't use MIN_ACL_ENTRIES: It's set to 4 on Cygwin, but Cygwin returns only 3 entries for files with no ACL. But this is safe: If there are more than 4 entries, there cannot be only the "user::", "group::", "other:", and "mask:" entries. */ if (count > 4) return 1; entries = (aclent_t *) malloc (count * sizeof (aclent_t)); if (entries == NULL) { errno = ENOMEM; return -1; } if (acl (name, GETACL, count, entries) == count) { if (acl_nontrivial (count, entries)) { free (entries); return 1; } free (entries); break; } /* Huh? The number of ACL entries changed since the last call. Repeat. */ free (entries); } } # ifdef ACE_GETACL /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4 file systems (whereas the other ones are used in UFS file systems). */ { ace_t *entries; for (;;) { count = acl (name, ACE_GETACLCNT, 0, NULL); if (count < 0) { if (errno == ENOSYS || errno == EINVAL) break; else return -1; } if (count == 0) break; /* If there are more than 3 entries, there cannot be only the ACE_OWNER, ACE_GROUP, ACE_OTHER entries. */ if (count > 3) return 1; entries = (ace_t *) malloc (count * sizeof (ace_t)); if (entries == NULL) { errno = ENOMEM; return -1; } if (acl (name, ACE_GETACL, count, entries) == count) { if (acl_ace_nontrivial (count, entries)) { free (entries); return 1; } free (entries); break; } /* Huh? The number of ACL entries changed since the last call. Repeat. */ free (entries); } } # endif return 0; # endif # elif HAVE_GETACL /* HP-UX */ int count; struct acl_entry entries[NACLENTRIES]; for (;;) { count = getacl (name, 0, NULL); if (count < 0) return (errno == ENOSYS || errno == EOPNOTSUPP ? 0 : -1); if (count == 0) return 0; if (count > NACLENTRIES) /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */ abort (); /* If there are more than 3 entries, there cannot be only the (uid,%), (%,gid), (%,%) entries. */ if (count > 3) return 1; if (getacl (name, count, entries) == count) { struct stat statbuf; if (stat (name, &statbuf) < 0) return -1; return acl_nontrivial (count, entries, &statbuf); } /* Huh? The number of ACL entries changed since the last call. Repeat. */ } # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */ acl_type_t type; char aclbuf[1024]; void *acl = aclbuf; size_t aclsize = sizeof (aclbuf); mode_t mode; for (;;) { /* The docs say that type being 0 is equivalent to ACL_ANY, but it is not true, in AIX 5.3. */ type.u64 = ACL_ANY; if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0) break; if (errno != ENOSPC) { if (acl != aclbuf) { int saved_errno = errno; free (acl); errno = saved_errno; } return -1; } aclsize = 2 * aclsize; if (acl != aclbuf) free (acl); acl = malloc (aclsize); if (acl == NULL) { errno = ENOMEM; return -1; } } if (type.u64 == ACL_AIXC) { int result = acl_nontrivial ((struct acl *) acl); if (acl != aclbuf) free (acl); return result; } else if (type.u64 == ACL_NFS4) { int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl); if (acl != aclbuf) free (acl); return result; } else { /* A newer type of ACL has been introduced in the system. We should better support it. */ if (acl != aclbuf) free (acl); errno = EINVAL; return -1; } # elif HAVE_STATACL /* older AIX */ union { struct acl a; char room[4096]; } u; if (statacl (name, STX_NORMAL, &u.a, sizeof (u)) < 0) return -1; return acl_nontrivial (&u.a); # endif } #endif return 0; }
int acl_search_groups(const char *path, char ***ret_groups) { _cleanup_strv_free_ char **g = NULL; _cleanup_(acl_freep) acl_t acl = NULL; bool ret = false; acl_entry_t entry; int r; assert(path); acl = acl_get_file(path, ACL_TYPE_DEFAULT); if (!acl) return -errno; r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); for (;;) { _cleanup_(acl_free_gid_tpp) gid_t *gid = NULL; acl_tag_t tag; if (r < 0) return -errno; if (r == 0) break; if (acl_get_tag_type(entry, &tag) < 0) return -errno; if (tag != ACL_GROUP) goto next; gid = acl_get_qualifier(entry); if (!gid) return -errno; if (in_gid(*gid) > 0) { if (!ret_groups) return true; ret = true; } if (ret_groups) { char *name; name = gid_to_name(*gid); if (!name) return -ENOMEM; r = strv_consume(&g, name); if (r < 0) return r; } next: r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry); } if (ret_groups) *ret_groups = TAKE_PTR(g); return ret; }
int file_has_acl (char const *name, struct stat const *sb) { #if USE_ACL if (! S_ISLNK (sb->st_mode)) { # if HAVE_ACL_GET_FILE /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */ int ret; if (HAVE_ACL_EXTENDED_FILE) /* Linux */ { /* On Linux, acl_extended_file is an optimized function: It only makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for ACL_TYPE_DEFAULT. */ ret = acl_extended_file (name); } else /* FreeBSD, Mac OS X, IRIX, Tru64 */ { # if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */ /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS) and acl_get_file (name, ACL_TYPE_DEFAULT) always return NULL / EINVAL. There is no point in making these two useless calls. The real ACL is retrieved through acl_get_file (name, ACL_TYPE_EXTENDED). */ acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED); if (acl) { ret = acl_extended_nontrivial (acl); acl_free (acl); } else ret = -1; # else /* FreeBSD, IRIX, Tru64 */ acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS); if (acl) { int saved_errno; ret = acl_access_nontrivial (acl); saved_errno = errno; acl_free (acl); errno = saved_errno; # if HAVE_ACL_FREE_TEXT /* Tru64 */ /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always returns NULL with errno not set. There is no point in making this call. */ # else /* FreeBSD, IRIX */ /* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS) and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory either both succeed or both fail; it depends on the file system. Therefore there is no point in making the second call if the first one already failed. */ if (ret == 0 && S_ISDIR (sb->st_mode)) { acl = acl_get_file (name, ACL_TYPE_DEFAULT); if (acl) { ret = (0 < acl_entries (acl)); acl_free (acl); } else ret = -1; } # endif } else ret = -1; # endif } if (ret < 0) return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1; return ret; # elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ # if defined ACL_NO_TRIVIAL /* Solaris 10 (newer version), which has additional API declared in <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial, acl_fromtext, ...). */ return acl_trivial (name); # else /* Solaris, Cygwin, general case */ /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions of Unixware. The acl() call returns the access and default ACL both at once. */ { /* Initially, try to read the entries into a stack-allocated buffer. Use malloc if it does not fit. */ enum { alloc_init = 4000 / sizeof (aclent_t), /* >= 3 */ alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (aclent_t)) }; aclent_t buf[alloc_init]; size_t alloc = alloc_init; aclent_t *entries = buf; aclent_t *malloced = NULL; int count; for (;;) { count = acl (name, GETACL, alloc, entries); if (count < 0 && errno == ENOSPC) { /* Increase the size of the buffer. */ free (malloced); if (alloc > alloc_max / 2) { errno = ENOMEM; return -1; } alloc = 2 * alloc; /* <= alloc_max */ entries = malloced = (aclent_t *) malloc (alloc * sizeof (aclent_t)); if (entries == NULL) { errno = ENOMEM; return -1; } continue; } break; } if (count < 0) { if (errno == ENOSYS || errno == ENOTSUP) ; else { int saved_errno = errno; free (malloced); errno = saved_errno; return -1; } } else if (count == 0) ; else { /* Don't use MIN_ACL_ENTRIES: It's set to 4 on Cygwin, but Cygwin returns only 3 entries for files with no ACL. But this is safe: If there are more than 4 entries, there cannot be only the "user::", "group::", "other:", and "mask:" entries. */ if (count > 4) { free (malloced); return 1; } if (acl_nontrivial (count, entries)) { free (malloced); return 1; } } free (malloced); } # ifdef ACE_GETACL /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4 file systems (whereas the other ones are used in UFS file systems). */ { /* Initially, try to read the entries into a stack-allocated buffer. Use malloc if it does not fit. */ enum { alloc_init = 4000 / sizeof (ace_t), /* >= 3 */ alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t)) }; ace_t buf[alloc_init]; size_t alloc = alloc_init; ace_t *entries = buf; ace_t *malloced = NULL; int count; for (;;) { count = acl (name, ACE_GETACL, alloc, entries); if (count < 0 && errno == ENOSPC) { /* Increase the size of the buffer. */ free (malloced); if (alloc > alloc_max / 2) { errno = ENOMEM; return -1; } alloc = 2 * alloc; /* <= alloc_max */ entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t)); if (entries == NULL) { errno = ENOMEM; return -1; } continue; } break; } if (count < 0) { if (errno == ENOSYS || errno == EINVAL) ; else { int saved_errno = errno; free (malloced); errno = saved_errno; return -1; } } else if (count == 0) ; else { /* In the old (original Solaris 10) convention: If there are more than 3 entries, there cannot be only the ACE_OWNER, ACE_GROUP, ACE_OTHER entries. In the newer Solaris 10 and Solaris 11 convention: If there are more than 6 entries, there cannot be only the ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with NEW_ACE_ACCESS_DENIED_ACE_TYPE. */ if (count > 6) { free (malloced); return 1; } if (acl_ace_nontrivial (count, entries)) { free (malloced); return 1; } } free (malloced); } # endif return 0; # endif # elif HAVE_GETACL /* HP-UX */ { struct acl_entry entries[NACLENTRIES]; int count; count = getacl (name, NACLENTRIES, entries); if (count < 0) { /* ENOSYS is seen on newer HP-UX versions. EOPNOTSUPP is typically seen on NFS mounts. ENOTSUP was seen on Quantum StorNext file systems (cvfs). */ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP) ; else return -1; } else if (count == 0) return 0; else /* count > 0 */ { if (count > NACLENTRIES) /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */ abort (); /* If there are more than 3 entries, there cannot be only the (uid,%), (%,gid), (%,%) entries. */ if (count > 3) return 1; { struct stat statbuf; if (stat (name, &statbuf) < 0) return -1; return acl_nontrivial (count, entries, &statbuf); } } } # if HAVE_ACLV_H /* HP-UX >= 11.11 */ { struct acl entries[NACLVENTRIES]; int count; count = acl ((char *) name, ACL_GET, NACLVENTRIES, entries); if (count < 0) { /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23. EINVAL is seen on NFS in HP-UX 11.31. */ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) ; else return -1; } else if (count == 0) return 0; else /* count > 0 */ { if (count > NACLVENTRIES) /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */ abort (); /* If there are more than 4 entries, there cannot be only the four base ACL entries. */ if (count > 4) return 1; return aclv_nontrivial (count, entries); } } # endif # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */ acl_type_t type; char aclbuf[1024]; void *acl = aclbuf; size_t aclsize = sizeof (aclbuf); mode_t mode; for (;;) { /* The docs say that type being 0 is equivalent to ACL_ANY, but it is not true, in AIX 5.3. */ type.u64 = ACL_ANY; if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0) break; if (errno == ENOSYS) return 0; if (errno != ENOSPC) { if (acl != aclbuf) { int saved_errno = errno; free (acl); errno = saved_errno; } return -1; } aclsize = 2 * aclsize; if (acl != aclbuf) free (acl); acl = malloc (aclsize); if (acl == NULL) { errno = ENOMEM; return -1; } } if (type.u64 == ACL_AIXC) { int result = acl_nontrivial ((struct acl *) acl); if (acl != aclbuf) free (acl); return result; } else if (type.u64 == ACL_NFS4) { int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl); if (acl != aclbuf) free (acl); return result; } else { /* A newer type of ACL has been introduced in the system. We should better support it. */ if (acl != aclbuf) free (acl); errno = EINVAL; return -1; } # elif HAVE_STATACL /* older AIX */ union { struct acl a; char room[4096]; } u; if (statacl (name, STX_NORMAL, &u.a, sizeof (u)) < 0) return -1; return acl_nontrivial (&u.a); # elif HAVE_ACLSORT /* NonStop Kernel */ { struct acl entries[NACLENTRIES]; int count; count = acl ((char *) name, ACL_GET, NACLENTRIES, entries); if (count < 0) { if (errno == ENOSYS || errno == ENOTSUP) ; else return -1; } else if (count == 0) return 0; else /* count > 0 */ { if (count > NACLENTRIES) /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */ abort (); /* If there are more than 4 entries, there cannot be only the four base ACL entries. */ if (count > 4) return 1; return acl_nontrivial (count, entries); } } # endif } #endif return 0; }
int copy_acl (const char *src_name, int source_desc, const char *dst_name, int dest_desc, mode_t mode) { int ret; #if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && HAVE_ACL_FREE /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */ acl_t acl; if (HAVE_ACL_GET_FD && source_desc != -1) acl = acl_get_fd (source_desc); else acl = acl_get_file (src_name, ACL_TYPE_ACCESS); if (acl == NULL) { if (ACL_NOT_WELL_SUPPORTED (errno)) return set_acl (dst_name, dest_desc, mode); else { error (0, errno, "%s", quote (src_name)); return -1; } } if (HAVE_ACL_SET_FD && dest_desc != -1) ret = acl_set_fd (dest_desc, acl); else ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl); if (ret != 0) { int saved_errno = errno; if (ACL_NOT_WELL_SUPPORTED (errno)) { int n = acl_entries (acl); acl_free (acl); /* On most hosts with MODE_INSIDE_ACL an ACL is trivial if n == 3, and it cannot be less than 3. On IRIX 6.5 it is also trivial if n == -1. For simplicity and safety, assume the ACL is trivial if n <= 3. Also see file-has-acl.c for some of the other possibilities; it's not clear whether that complexity is needed here. */ if (n <= 3 * MODE_INSIDE_ACL) { if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) saved_errno = errno; else return 0; } else chmod_or_fchmod (dst_name, dest_desc, mode); } else { acl_free (acl); chmod_or_fchmod (dst_name, dest_desc, mode); } error (0, saved_errno, _("preserving permissions for %s"), quote (dst_name)); return -1; } else acl_free (acl); if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX))) { /* We did not call chmod so far, and either the mode and the ACL are separate or special bits are to be set which don't fit into ACLs. */ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) { error (0, errno, _("preserving permissions for %s"), quote (dst_name)); return -1; } } if (S_ISDIR (mode)) { acl = acl_get_file (src_name, ACL_TYPE_DEFAULT); if (acl == NULL) { error (0, errno, "%s", quote (src_name)); return -1; } if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl)) { error (0, errno, _("preserving permissions for %s"), quote (dst_name)); acl_free (acl); return -1; } else acl_free (acl); } return 0; #else # if USE_ACL && defined ACL_NO_TRIVIAL /* Solaris 10 NFSv4 ACLs. */ acl_t *aclp = NULL; ret = (source_desc < 0 ? acl_get (src_name, ACL_NO_TRIVIAL, &aclp) : facl_get (source_desc, ACL_NO_TRIVIAL, &aclp)); if (ret != 0 && errno != ENOSYS) { error (0, errno, "%s", quote (src_name)); return ret; } # endif ret = qset_acl (dst_name, dest_desc, mode); if (ret != 0) error (0, errno, _("preserving permissions for %s"), quote (dst_name)); # if USE_ACL && defined ACL_NO_TRIVIAL if (ret == 0 && aclp) { ret = (dest_desc < 0 ? acl_set (dst_name, aclp) : facl_set (dest_desc, aclp)); if (ret != 0) error (0, errno, _("preserving permissions for %s"), quote (dst_name)); acl_free (aclp); } # endif return ret; #endif }
/* Obtain the ACL of the given file in long text form. @param path Path to the file @param text Will hold the result. This is a managed object which finally has to be freed by a call to this function with bit15 of flag. @param flag Bitfield for control purposes bit0= obtain default ACL rather than access ACL behave like bit4 if ACL is empty bit4= set *text = NULL and return 2 if the ACL matches st_mode permissions. bit5= in case of symbolic link: inquire link target bit15= free text and return 1 @return 1 ok 2 only st_mode permissions exist and bit 4 is set or empty ACL and bit0 is set 0 ACL support not enabled at compile time or filesystem does not support ACL -1 failure of system ACL service (see errno) -2 attempt to inquire ACL of a symbolic link without bit4 or bit5 resp. with no suitable link target */ int aaip_get_acl_text(char *path, char **text, int flag) { #ifdef Libisofs_with_aaip_acL acl_t acl= NULL; struct stat stbuf; int ret; if(flag & (1 << 15)) { if(*text != NULL) acl_free(*text); *text= NULL; return(1); } *text= NULL; if(flag & 32) ret= stat(path, &stbuf); else ret= lstat(path, &stbuf); if(ret == -1) return(-1); if((stbuf.st_mode & S_IFMT) == S_IFLNK) { if(flag & 16) return(2); return(-2); } acl= acl_get_file(path, (flag & 1) ? ACL_TYPE_DEFAULT : ACL_TYPE_ACCESS); if(acl == NULL) { if(errno == ENOTSUP) { /* filesystem does not support ACL */ if(flag & 16) return(2); /* >>> ??? fake ACL from POSIX permissions ? */; return(0); } return(-1); } *text= acl_to_text(acl, NULL); acl_free(acl); if(*text == NULL) return(-1); if(flag & 16) { ret = aaip_cleanout_st_mode(*text, &(stbuf.st_mode), 2); if(!(ret & (7 | 64))) (*text)[0]= 0; } if(flag & (1 | 16)) { if((*text)[0] == 0 || strcmp(*text, "\n") == 0) { acl_free(*text); *text= NULL; return(2); } } return(1); #else /* Libisofs_with_aaip_acL */ return(0); #endif /* ! Libisofs_with_aaip_acL */ }
int main (int argc, char *argv[]) { acl_t acl; acl_type_t type; acl_entry_t entry; acl_tag_t tag; uid_t *uid_p; gid_t *gid_p; acl_permset_t permset; char *name_p; int entryId, permVal, opt; type = ACL_TYPE_ACCESS; while ((opt = getopt (argc, argv, "d")) != -1) { switch (opt) { case 'd': type = ACL_TYPE_DEFAULT; break; case '?': usage (argv[0]); return 1; } } if (optind + 1 != argc) { usage (argv[0]); return 1; } acl = acl_get_file (argv[optind], type); if (acl == NULL) { perror ("acl_get_file()"); return 1; } for (entryId=ACL_FIRST_ENTRY; ; entryId=ACL_NEXT_ENTRY) { if (acl_get_entry (acl, entryId, &entry) != 1) break; if (acl_get_tag_type (entry, &tag) == -1) { perror ("acl_get_tag_type()"); return 1; } printf ("%-12s", (tag == ACL_USER_OBJ)? "user_obj" : (tag == ACL_USER)? "user" : (tag == ACL_GROUP_OBJ)? "group_obj" : (tag == ACL_GROUP)? "group" : (tag == ACL_MASK)? "mask" : (tag == ACL_OTHER)? "other" : "???"); // optional user/group ACLs if (tag == ACL_USER) { uid_p = acl_get_qualifier (entry); if (uid_p == NULL) { perror ("acl_get_qualifier()"); return 1; } name_p = user_name_from_id (*uid_p); if (name_p == NULL) printf ("\t\t%d", *uid_p); else printf ("\t\t%s", name_p); if (acl_free (uid_p) == -1) perror ("acl_free (uid_p)"); } else if (tag == ACL_GROUP) { gid_p = acl_get_qualifier (entry); if (gid_p == NULL) { perror ("acl_get_qualifier()"); return 1; } name_p = group_name_from_id (*gid_p); if (name_p == NULL) printf ("\t\t%d", *gid_p); else printf ("\t\t%s", name_p); if (acl_free (gid_p) == -1) perror ("acl_free (gid_p)"); } else printf ("\t\t"); // permissions if (acl_get_permset (entry, &permset) == -1) { perror ("acl_get_permset()"); return 1; } if ((permVal = acl_get_perm (permset, ACL_READ)) == -1) { perror ("acl_get_perm (ACL_READ)"); return 1; } printf ("\t\t%c", (permVal == 1)? 'r' : '-'); if ((permVal = acl_get_perm (permset, ACL_WRITE)) == -1) { perror ("acl_get_perm (ACL_WRITE)"); return 1; } printf ("%c", (permVal == 1)? 'w' : '-'); if ((permVal = acl_get_perm (permset, ACL_EXECUTE)) == -1) { perror ("acl_get_perm (ACL_EXECUTE)"); return 1; } printf ("%c", (permVal == 1)? 'x' : '-'); printf ("\n"); } if (acl_free (acl) == -1) { perror ("acl_free (acl)"); return 1; } return 0; }
static int setup_acls(struct archive_read_disk *a, struct archive_entry *entry, int *fd) { const char *accpath; acl_t acl; #if HAVE_ACL_IS_TRIVIAL_NP int r; #endif accpath = archive_entry_sourcepath(entry); if (accpath == NULL) accpath = archive_entry_pathname(entry); archive_entry_acl_clear(entry); /* Try NFS4 ACL first. */ if (*fd >= 0) acl = acl_get_fd(*fd); #if HAVE_ACL_GET_LINK_NP else if (!a->follow_symlinks) acl = acl_get_link_np(accpath, ACL_TYPE_NFS4); #else else if ((!a->follow_symlinks) && (archive_entry_filetype(entry) == AE_IFLNK)) /* We can't get the ACL of a symlink, so we assume it can't have one. */ acl = NULL; #endif else acl = acl_get_file(accpath, ACL_TYPE_NFS4); #if HAVE_ACL_IS_TRIVIAL_NP /* Ignore "trivial" ACLs that just mirror the file mode. */ acl_is_trivial_np(acl, &r); if (r) { acl_free(acl); acl = NULL; } #endif if (acl != NULL) { translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4); acl_free(acl); return (ARCHIVE_OK); } /* Retrieve access ACL from file. */ if (*fd >= 0) acl = acl_get_fd(*fd); #if HAVE_ACL_GET_LINK_NP else if (!a->follow_symlinks) acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS); #else else if ((!a->follow_symlinks) && (archive_entry_filetype(entry) == AE_IFLNK)) /* We can't get the ACL of a symlink, so we assume it can't have one. */ acl = NULL; #endif else acl = acl_get_file(accpath, ACL_TYPE_ACCESS); if (acl != NULL) { translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_ACCESS); acl_free(acl); } /* Only directories can have default ACLs. */ if (S_ISDIR(archive_entry_mode(entry))) { acl = acl_get_file(accpath, ACL_TYPE_DEFAULT); if (acl != NULL) { translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT); acl_free(acl); } } return (ARCHIVE_OK); }
static int CheckPosixLinuxACEs(EvalContext *ctx, Rlist *aces, AclMethod method, const char *file_path, acl_type_t acl_type, Attributes a, const Promise *pp, PromiseResult *result) { acl_t acl_existing; acl_t acl_new; acl_t acl_tmp; acl_entry_t ace_parsed; acl_entry_t ace_current; acl_permset_t perms; char *cf_ace; int retv; int has_mask; Rlist *rp; char *acl_type_str; acl_new = NULL; acl_existing = NULL; acl_tmp = NULL; has_mask = false; acl_type_str = acl_type == ACL_TYPE_ACCESS ? "Access" : "Default"; // read existing acl if ((acl_existing = acl_get_file(file_path, acl_type)) == NULL) { Log(LOG_LEVEL_VERBOSE, "No ACL for '%s' could be read. (acl_get_file: %s)", file_path, GetErrorStr()); return false; } // allocate memory for temp ace (it needs to reside in a temp acl) if ((acl_tmp = acl_init(1)) == NULL) { Log(LOG_LEVEL_ERR, "New ACL could not be allocated (acl_init: %s)", GetErrorStr()); acl_free((void *) acl_existing); return false; } if (acl_create_entry(&acl_tmp, &ace_parsed) != 0) { Log(LOG_LEVEL_ERR, "New ACL could not be allocated (acl_create_entry: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); return false; } // copy existing aces if we are appending if (method == ACL_METHOD_APPEND) { if ((acl_new = acl_dup(acl_existing)) == NULL) { Log(LOG_LEVEL_ERR, "Error copying existing ACL (acl_dup: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); return false; } } else // overwrite existing acl { if ((acl_new = acl_init(5)) == NULL) // TODO: Always OK with 5 here ? { Log(LOG_LEVEL_ERR, "New ACL could not be allocated (acl_init: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); return false; } } for (rp = aces; rp != NULL; rp = rp->next) { cf_ace = RlistScalarValue(rp); if (!ParseEntityPosixLinux(&cf_ace, ace_parsed, &has_mask)) { Log(LOG_LEVEL_ERR, "Error parsing entity in 'cf_ace'."); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } // check if an ACE with this entity-type and id already exist in the Posix Linux ACL ace_current = FindACE(acl_new, ace_parsed); // create new entry in ACL if it did not exist if (ace_current == NULL) { if (acl_create_entry(&acl_new, &ace_current) != 0) { Log(LOG_LEVEL_ERR, "Failed to allocate ace (acl_create_entry: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } // copy parsed entity-type and id if (acl_copy_entry(ace_current, ace_parsed) != 0) { Log(LOG_LEVEL_ERR, "Error copying Linux entry in 'cf_ace' (acl_copy_entry: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } // clear ace_current's permissions to avoid ace_parsed from last // loop iteration to be taken into account when applying mode below if ((acl_get_permset(ace_current, &perms) != 0)) { Log(LOG_LEVEL_ERR, "Error obtaining permset for 'ace_current' (acl_get_permset: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } if (acl_clear_perms(perms) != 0) { Log(LOG_LEVEL_ERR, "Error clearing permset for 'ace_current'. (acl_clear_perms: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } } // mode string should be prefixed with an entry seperator if (*cf_ace != ':') { Log(LOG_LEVEL_ERR, "No separator before mode-string in 'cf_ace'"); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } cf_ace += 1; if (acl_get_permset(ace_current, &perms) != 0) { Log(LOG_LEVEL_ERR, "Error obtaining permset for 'cf_ace'"); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } if (!ParseModePosixLinux(cf_ace, perms)) { Log(LOG_LEVEL_ERR, "Error parsing mode-string in 'cf_ace'"); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } // only allow permissions exist on posix acls, so we do // not check what follows next } // if no mask exists, calculate one (or both?): run acl_calc_mask and add one if (!has_mask) { if (acl_calc_mask(&acl_new) != 0) { Log(LOG_LEVEL_ERR, "Error calculating new acl mask"); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } } if ((retv = ACLEquals(acl_existing, acl_new)) == -1) { Log(LOG_LEVEL_ERR, "Error while comparing existing and new ACL, unable to repair."); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } if (retv == 1) // existing and new acl differ, update existing { switch (a.transaction.action) { case cfa_warn: cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_WARN, pp, a, "%s ACL on file '%s' needs to be updated", acl_type_str, file_path); *result = PromiseResultUpdate(*result, PROMISE_RESULT_WARN); break; case cfa_fix: if (!DONTDO) { if ((retv = acl_set_file(file_path, acl_type, acl_new)) != 0) { Log(LOG_LEVEL_ERR, "Error setting new %s ACL on file '%s' (acl_set_file: %s), are required ACEs present ?", acl_type_str, file_path, GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } } cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_CHANGE, pp, a, "%s ACL on '%s' successfully changed.", acl_type_str, file_path); *result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE); break; default: ProgrammingError("CFEngine: internal error: illegal file action"); } } else { cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_NOOP, pp, a, "'%s' ACL on '%s' needs no modification.", acl_type_str, file_path); } acl_free((void *) acl_existing); acl_free((void *) acl_new); acl_free((void *) acl_tmp); return true; }
int CopyACLs(const char *src, const char *dst) { acl_t acls; struct stat statbuf; int ret; acls = acl_get_file(src, ACL_TYPE_ACCESS); if (!acls) { if (errno == ENOTSUP) { return true; } else { Log(LOG_LEVEL_ERR, "Can't copy ACLs from '%s'. (acl_get_file: %s)", src, GetErrorStr()); return false; } } ret = acl_set_file(dst, ACL_TYPE_ACCESS, acls); acl_free(acls); if (ret != 0) { if (errno == ENOTSUP) { return true; } else { Log(LOG_LEVEL_ERR, "Can't copy ACLs to '%s'. (acl_set_file: %s)", dst, GetErrorStr()); return false; } } if (stat(src, &statbuf) != 0) { Log(LOG_LEVEL_ERR, "Can't copy ACLs from '%s'. (stat: %s)", src, GetErrorStr()); return false; } if (!S_ISDIR(statbuf.st_mode)) { return true; } // For directory, copy default ACL too. acls = acl_get_file(src, ACL_TYPE_DEFAULT); if (!acls) { Log(LOG_LEVEL_ERR, "Can't copy ACLs from '%s'. (acl_get_file: %s)", src, GetErrorStr()); return false; } ret = acl_set_file(dst, ACL_TYPE_DEFAULT, acls); acl_free(acls); if (ret != 0) { Log(LOG_LEVEL_ERR, "Can't copy ACLs to '%s'. (acl_set_file: %s)", dst, GetErrorStr()); return false; } return true; }
int CheckDefaultClearACL(EvalContext *ctx, const char *file_path, Attributes a, const Promise *pp, PromiseResult *result) { acl_t acl_existing; acl_t acl_empty; acl_entry_t ace_dummy; int retv; int retval = false; acl_existing = NULL; acl_empty = NULL; if ((acl_existing = acl_get_file(file_path, ACL_TYPE_DEFAULT)) == NULL) { Log(LOG_LEVEL_ERR, "Unable to read default acl for '%s'. (acl_get_file: %s)", file_path, GetErrorStr()); return false; } retv = acl_get_entry(acl_existing, ACL_FIRST_ENTRY, &ace_dummy); switch (retv) { case -1: Log(LOG_LEVEL_VERBOSE, "Couldn't retrieve ACE for '%s'. (acl_get_entry: %s)", file_path, GetErrorStr()); retval = false; break; case 0: // no entries, as desired cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_NOOP, pp, a, "Default ACL on '%s' needs no modification.", file_path); retval = true; break; case 1: // entries exist, set empty ACL if ((acl_empty = acl_init(0)) == NULL) { Log(LOG_LEVEL_ERR, "Could not reinitialize ACL for '%s'. (acl_init: %s)", file_path, GetErrorStr()); retval = false; break; } switch (a.transaction.action) { case cfa_warn: cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_WARN, pp, a, "Default ACL on '%s' needs to be cleared", file_path); *result = PromiseResultUpdate(*result, PROMISE_RESULT_WARN); break; case cfa_fix: if (!DONTDO) { if (acl_set_file(file_path, ACL_TYPE_DEFAULT, acl_empty) != 0) { Log(LOG_LEVEL_ERR, "Could not reset ACL for %s", file_path); retval = false; break; } } cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_CHANGE, pp, a, "Default ACL on '%s' successfully cleared", file_path); *result = PromiseResultUpdate(*result, PROMISE_RESULT_WARN); retval = true; break; default: ProgrammingError("CFEngine: internal error: illegal file action"); retval = false; } break; default: retval = false; } acl_free(acl_empty); acl_free(acl_existing); return retval; }
int main(int argc, char *argv[]) { Boolean recalcMask, useDefaultACL; Boolean modifyACL, removeACL, removeDefaultACL, checkValidity; int optCnt, j, opt, numEntries, en; acl_type_t type; char *aclSpec; acl_t acl; acl_entry_t entry; struct AccessControlEntry aclist[MAX_ENTRIES]; if (argc < 2 || strcmp(argv[1], "--help") == 0) usageError(argv[0], NULL, FALSE); /* Parse command-line options */ recalcMask = TRUE; useDefaultACL = FALSE; modifyACL = FALSE; removeACL = FALSE; checkValidity = FALSE; removeDefaultACL = FALSE; optCnt = 0; while ((opt = getopt(argc, argv, "m:x:kdnV:")) != -1) { switch (opt) { case 'm': modifyACL = TRUE; aclSpec = optarg; optCnt++; break; case 'x': removeACL = TRUE; aclSpec = optarg; optCnt++; break; case 'k': removeDefaultACL = TRUE; optCnt++; break; case 'V': checkValidity = TRUE; aclSpec = optarg; optCnt++; break; case 'd': useDefaultACL = TRUE; break; case 'n': recalcMask = FALSE; break; default: usageError(argv[0], "Bad option\n", TRUE); break; } } if (optCnt != 1) usageError(argv[0], "Specify exactly one of -m, -x, -k, or -V\n", TRUE); if (checkValidity && useDefaultACL) usageError(argv[0], "Can't specify -d with -V\n", TRUE); if (checkValidity) { if (parseACL(aclSpec, aclist, TRUE) == -1) { fatal("Bad ACL entry specification"); } else { printf("ACL is valid\n"); exit(EXIT_SUCCESS); } } if (modifyACL || removeACL) { numEntries = parseACL(aclSpec, aclist, modifyACL); if (numEntries == -1) usageError(argv[0], "Bad ACL specification\n", TRUE); } type = useDefaultACL ? ACL_TYPE_DEFAULT : ACL_TYPE_ACCESS; /* Perform the operation on each file argument */ for (j = optind; j < argc; j++) { if (removeDefaultACL) { if (acl_delete_def_file(argv[j]) == -1) errExit("acl_delete_def_file: %s", argv[j]); } else if (modifyACL || removeACL) { acl = acl_get_file(argv[j], type); if (acl == NULL) errExit("acl_get_file"); /* Apply each of the entries in 'aclist' to the current file */ for (en = 0; en < numEntries; en++) { entry = findEntry(acl, aclist[en].tag, aclist[en].qual); if (removeACL) { if (entry != NULL) if (acl_delete_entry(acl, entry) == -1) errExit("acl_delete_entry"); } else { /* modifyACL */ if (entry == NULL) { /* Entry didn't exist in ACL -- create a new entry with required tag and qualifier */ if (acl_create_entry(&acl, &entry) == -1) errExit("acl_create_entry"); if (acl_set_tag_type(entry, aclist[en].tag) == -1) errExit("acl_set_tag_type"); if (aclist[en].tag == ACL_USER || aclist[en].tag == ACL_GROUP) if (acl_set_qualifier(entry, &aclist[en].qual) == -1) errExit("acl_set_qualifier"); } setPerms(entry, aclist[en].perms); } /* Recalculate the mask entry if requested */ if (recalcMask) if (acl_calc_mask(&acl) == -1) errExit("acl_calc_mask"); /* Update the file ACL */ if (acl_valid(acl) == -1) errExit("acl_valid"); if (acl_set_file(argv[j], type, acl) == -1) errExit("acl_set_file"); } if (acl_free(acl) == -1) errExit("acl_free"); } else { fatal("Bad logic!"); } } exit(EXIT_SUCCESS); }
int main (int argc, char *argv[]) { const char *file1; const char *file2; set_program_name (argv[0]); ASSERT (argc == 3); file1 = argv[1]; file2 = argv[2]; /* Compare the contents of the two files. */ { size_t size1; char *contents1; size_t size2; char *contents2; contents1 = read_file (file1, &size1); if (contents1 == NULL) { fprintf (stderr, "error reading file %s: errno = %d\n", file1, errno); fflush (stderr); abort (); } contents2 = read_file (file2, &size2); if (contents2 == NULL) { fprintf (stderr, "error reading file %s: errno = %d\n", file2, errno); fflush (stderr); abort (); } if (size2 != size1) { fprintf (stderr, "files %s and %s have different sizes\n", file1, file2); fflush (stderr); abort (); } if (memcmp (contents1, contents2, size1) != 0) { fprintf (stderr, "files %s and %s have different contents\n", file1, file2); fflush (stderr); abort (); } } /* Compare the access permissions of the two files, including ACLs. */ { struct stat statbuf1; struct stat statbuf2; if (stat (file1, &statbuf1) < 0) { fprintf (stderr, "error accessing file %s: errno = %d\n", file1, errno); fflush (stderr); abort (); } if (stat (file2, &statbuf2) < 0) { fprintf (stderr, "error accessing file %s: errno = %d\n", file2, errno); fflush (stderr); abort (); } if (statbuf1.st_mode != statbuf2.st_mode) { fprintf (stderr, "files %s and %s have different access modes: %03o and %03o\n", file1, file2, (unsigned int) statbuf1.st_mode, (unsigned int) statbuf2.st_mode); return 1; } } { #if HAVE_ACL_GET_FILE /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */ static const int types[] = { ACL_TYPE_ACCESS # if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */ , ACL_TYPE_EXTENDED # endif }; int t; for (t = 0; t < sizeof (types) / sizeof (types[0]); t++) { int type = types[t]; acl_t acl1; char *text1; int errno1; acl_t acl2; char *text2; int errno2; acl1 = acl_get_file (file1, type); if (acl1 == (acl_t)NULL) { text1 = NULL; errno1 = errno; } else { text1 = acl_to_text (acl1, NULL); if (text1 == NULL) errno1 = errno; else errno1 = 0; } acl2 = acl_get_file (file2, type); if (acl2 == (acl_t)NULL) { text2 = NULL; errno2 = errno; } else { text2 = acl_to_text (acl2, NULL); if (text2 == NULL) errno2 = errno; else errno2 = 0; } if (acl1 != (acl_t)NULL) { if (acl2 != (acl_t)NULL) { if (text1 != NULL) { if (text2 != NULL) { if (strcmp (text1, text2) != 0) { fprintf (stderr, "files %s and %s have different ACLs:\n%s\n%s\n", file1, file2, text1, text2); return 1; } } else { fprintf (stderr, "file %s has a valid ACL, but file %s has an invalid ACL\n", file1, file2); return 1; } } else { if (text2 != NULL) { fprintf (stderr, "file %s has an invalid ACL, but file %s has a valid ACL\n", file1, file2); return 1; } else { if (errno1 != errno2) { fprintf (stderr, "files %s and %s have differently invalid ACLs, errno = %d vs. %d\n", file1, file2, errno1, errno2); return 1; } } } } else { fprintf (stderr, "file %s has an ACL, but file %s has no ACL\n", file1, file2); return 1; } } else { if (acl2 != (acl_t)NULL) { fprintf (stderr, "file %s has no ACL, but file %s has an ACL\n", file1, file2); return 1; } } } #elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ int count1; int count2; count1 = acl (file1, GETACLCNT, 0, NULL); if (count1 < 0 && errno == ENOSYS) /* Can happen on Solaris 10 with ZFS */ count1 = 0; count2 = acl (file2, GETACLCNT, 0, NULL); if (count2 < 0 && errno == ENOSYS) /* Can happen on Solaris 10 with ZFS */ count2 = 0; if (count1 < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file1); fflush (stderr); abort (); } if (count2 < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file2); fflush (stderr); abort (); } if (count1 != count2) { fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n", file1, file2, count1, count2); return 1; } else { aclent_t *entries1 = XNMALLOC (count1, aclent_t); aclent_t *entries2 = XNMALLOC (count2, aclent_t); int i; if (count1 > 0 && acl (file1, GETACL, count1, entries1) < count1) { fprintf (stderr, "error retrieving the ACLs of file %s\n", file1); fflush (stderr); abort (); } if (count2 > 0 && acl (file2, GETACL, count2, entries2) < count1) { fprintf (stderr, "error retrieving the ACLs of file %s\n", file2); fflush (stderr); abort (); } for (i = 0; i < count1; i++) { if (entries1[i].a_type != entries2[i].a_type) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n", file1, file2, i, entries1[i].a_type, entries2[i].a_type); return 1; } if (entries1[i].a_id != entries2[i].a_id) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n", file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id); return 1; } if (entries1[i].a_perm != entries2[i].a_perm) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n", file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm); return 1; } } } # ifdef ACE_GETACL count1 = acl (file1, ACE_GETACLCNT, 0, NULL); if (count1 < 0 && errno == EINVAL) count1 = 0; count2 = acl (file2, ACE_GETACLCNT, 0, NULL); if (count2 < 0 && errno == EINVAL) count2 = 0; if (count1 < 0) { fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file1); fflush (stderr); abort (); } if (count2 < 0) { fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file2); fflush (stderr); abort (); } { ace_t *entries1 = XNMALLOC (count1, ace_t); ace_t *entries2 = XNMALLOC (count2, ace_t); int ret; int i; ret = acl (file1, ACE_GETACL, count1, entries1); if (ret < 0 && errno == EINVAL) count1 = 0; else if (ret < count1) { fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file1); fflush (stderr); abort (); } ret = acl (file2, ACE_GETACL, count2, entries2); if (ret < 0 && errno == EINVAL) count2 = 0; else if (ret < count2) { fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file2); fflush (stderr); abort (); } if (count1 != count2) { fprintf (stderr, "files %s and %s have different number of ACE-ACLs: %d and %d\n", file1, file2, count1, count2); return 1; } for (i = 0; i < count1; i++) { if (entries1[i].a_type != entries2[i].a_type) { fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different types %d and %d\n", file1, file2, i, entries1[i].a_type, entries2[i].a_type); return 1; } if (entries1[i].a_who != entries2[i].a_who) { fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different ids %d and %d\n", file1, file2, i, (int)entries1[i].a_who, (int)entries2[i].a_who); return 1; } if (entries1[i].a_access_mask != entries2[i].a_access_mask) { fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different access masks %03o and %03o\n", file1, file2, i, (unsigned int) entries1[i].a_access_mask, (unsigned int) entries2[i].a_access_mask); return 1; } if (entries1[i].a_flags != entries2[i].a_flags) { fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different flags 0x%x and 0x%x\n", file1, file2, i, (unsigned int) entries1[i].a_flags, (unsigned int) entries2[i].a_flags); return 1; } } } # endif #elif HAVE_GETACL /* HP-UX */ int count1; int count2; count1 = getacl (file1, 0, NULL); if (count1 < 0 && (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)) count1 = 0; count2 = getacl (file2, 0, NULL); if (count2 < 0 && (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)) count2 = 0; if (count1 < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file1); fflush (stderr); abort (); } if (count2 < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file2); fflush (stderr); abort (); } if (count1 != count2) { fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n", file1, file2, count1, count2); return 1; } else if (count1 > 0) { struct acl_entry *entries1 = XNMALLOC (count1, struct acl_entry); struct acl_entry *entries2 = XNMALLOC (count2, struct acl_entry); int i; if (getacl (file1, count1, entries1) < count1) { fprintf (stderr, "error retrieving the ACLs of file %s\n", file1); fflush (stderr); abort (); } if (getacl (file2, count2, entries2) < count1) { fprintf (stderr, "error retrieving the ACLs of file %s\n", file2); fflush (stderr); abort (); } for (i = 0; i < count1; i++) { if (entries1[i].uid != entries2[i].uid) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different uids %d and %d\n", file1, file2, i, (int)entries1[i].uid, (int)entries2[i].uid); return 1; } if (entries1[i].gid != entries2[i].gid) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different gids %d and %d\n", file1, file2, i, (int)entries1[i].gid, (int)entries2[i].gid); return 1; } if (entries1[i].mode != entries2[i].mode) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n", file1, file2, i, (unsigned int) entries1[i].mode, (unsigned int) entries2[i].mode); return 1; } } } # if HAVE_ACLV_H /* HP-UX >= 11.11 */ { struct acl dummy_entries[NACLVENTRIES]; count1 = acl ((char *) file1, ACL_CNT, NACLVENTRIES, dummy_entries); if (count1 < 0 && (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)) count1 = 0; count2 = acl ((char *) file2, ACL_CNT, NACLVENTRIES, dummy_entries); if (count2 < 0 && (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)) count2 = 0; } if (count1 < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file1); fflush (stderr); abort (); } if (count2 < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file2); fflush (stderr); abort (); } if (count1 != count2) { fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n", file1, file2, count1, count2); return 1; } else if (count1 > 0) { struct acl *entries1 = XNMALLOC (count1, struct acl); struct acl *entries2 = XNMALLOC (count2, struct acl); int i; if (acl ((char *) file1, ACL_GET, count1, entries1) < count1) { fprintf (stderr, "error retrieving the ACLs of file %s\n", file1); fflush (stderr); abort (); } if (acl ((char *) file2, ACL_GET, count2, entries2) < count1) { fprintf (stderr, "error retrieving the ACLs of file %s\n", file2); fflush (stderr); abort (); } for (i = 0; i < count1; i++) { if (entries1[i].a_type != entries2[i].a_type) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n", file1, file2, i, entries1[i].a_type, entries2[i].a_type); return 1; } if (entries1[i].a_id != entries2[i].a_id) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n", file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id); return 1; } if (entries1[i].a_perm != entries2[i].a_perm) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n", file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm); return 1; } } } # endif #elif HAVE_ACLX_GET /* AIX */ acl_type_t type1; char acl1[1000]; size_t aclsize1 = sizeof (acl1); mode_t mode1; char text1[1000]; size_t textsize1 = sizeof (text1); acl_type_t type2; char acl2[1000]; size_t aclsize2 = sizeof (acl2); mode_t mode2; char text2[1000]; size_t textsize2 = sizeof (text2); /* The docs say that type1 being 0 is equivalent to ACL_ANY, but it is not true, in AIX 5.3. */ type1.u64 = ACL_ANY; if (aclx_get (file1, 0, &type1, acl1, &aclsize1, &mode1) < 0) { if (errno == ENOSYS) text1[0] = '\0'; else { fprintf (stderr, "error accessing the ACLs of file %s\n", file1); fflush (stderr); abort (); } } else if (aclx_printStr (text1, &textsize1, acl1, aclsize1, type1, file1, 0) < 0) { fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file1); fflush (stderr); abort (); } /* The docs say that type2 being 0 is equivalent to ACL_ANY, but it is not true, in AIX 5.3. */ type2.u64 = ACL_ANY; if (aclx_get (file2, 0, &type2, acl2, &aclsize2, &mode2) < 0) { if (errno == ENOSYS) text2[0] = '\0'; else { fprintf (stderr, "error accessing the ACLs of file %s\n", file2); fflush (stderr); abort (); } } else if (aclx_printStr (text2, &textsize2, acl2, aclsize2, type2, file2, 0) < 0) { fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file2); fflush (stderr); abort (); } if (strcmp (text1, text2) != 0) { fprintf (stderr, "files %s and %s have different ACLs:\n%s\n%s\n", file1, file2, text1, text2); return 1; } #elif HAVE_STATACL /* older AIX */ union { struct acl a; char room[4096]; } acl1; union { struct acl a; char room[4096]; } acl2; unsigned int i; if (statacl (file1, STX_NORMAL, &acl1.a, sizeof (acl1)) < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file1); fflush (stderr); abort (); } if (statacl (file2, STX_NORMAL, &acl2.a, sizeof (acl2)) < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file2); fflush (stderr); abort (); } if (acl1.a.acl_len != acl2.a.acl_len) { fprintf (stderr, "files %s and %s have different ACL lengths: %u and %u\n", file1, file2, acl1.a.acl_len, acl2.a.acl_len); return 1; } if (acl1.a.acl_mode != acl2.a.acl_mode) { fprintf (stderr, "files %s and %s have different ACL modes: %03o and %03o\n", file1, file2, acl1.a.acl_mode, acl2.a.acl_mode); return 1; } if (acl1.a.u_access != acl2.a.u_access || acl1.a.g_access != acl2.a.g_access || acl1.a.o_access != acl2.a.o_access) { fprintf (stderr, "files %s and %s have different ACL access masks: %03o %03o %03o and %03o %03o %03o\n", file1, file2, acl1.a.u_access, acl1.a.g_access, acl1.a.o_access, acl2.a.u_access, acl2.a.g_access, acl2.a.o_access); return 1; } if (memcmp (acl1.a.acl_ext, acl2.a.acl_ext, acl1.a.acl_len) != 0) { fprintf (stderr, "files %s and %s have different ACL entries\n", file1, file2); return 1; } #elif HAVE_ACLSORT /* NonStop Kernel */ int count1; int count2; count1 = acl ((char *) file1, ACL_CNT, NACLENTRIES, NULL); count2 = acl ((char *) file2, ACL_CNT, NACLENTRIES, NULL); if (count1 < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file1); fflush (stderr); abort (); } if (count2 < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file2); fflush (stderr); abort (); } if (count1 != count2) { fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n", file1, file2, count1, count2); return 1; } else if (count1 > 0) { struct acl *entries1 = XNMALLOC (count1, struct acl); struct acl *entries2 = XNMALLOC (count2, struct acl); int i; if (acl ((char *) file1, ACL_GET, count1, entries1) < count1) { fprintf (stderr, "error retrieving the ACLs of file %s\n", file1); fflush (stderr); abort (); } if (acl ((char *) file2, ACL_GET, count2, entries2) < count1) { fprintf (stderr, "error retrieving the ACLs of file %s\n", file2); fflush (stderr); abort (); } for (i = 0; i < count1; i++) { if (entries1[i].a_type != entries2[i].a_type) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n", file1, file2, i, entries1[i].a_type, entries2[i].a_type); return 1; } if (entries1[i].a_id != entries2[i].a_id) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n", file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id); return 1; } if (entries1[i].a_perm != entries2[i].a_perm) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n", file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm); return 1; } } } #endif } return 0; }
static int CheckDefaultEqualsAccessACL(char *file_path, Attributes a, Promise *pp) { acl_t acl_access; acl_t acl_default; int equals; int result = false; acl_access = NULL; acl_default = NULL; if ((acl_access = acl_get_file(file_path, ACL_TYPE_ACCESS)) == NULL) { CfOut(OUTPUT_LEVEL_ERROR, "acl_get_file", "Could not find an ACL for %s", file_path); return false; } acl_default = acl_get_file(file_path, ACL_TYPE_DEFAULT); if (acl_default == NULL) { CfOut(OUTPUT_LEVEL_ERROR, "acl_get_file", "Could not find default ACL for %s", file_path); acl_free(acl_access); return false; } equals = ACLEquals(acl_access, acl_default); switch (equals) { case 0: // they equal, as desired cfPS(OUTPUT_LEVEL_INFORM, CF_NOP, "", pp, a, "-> Default ACL on \"%s\" needs no modification.", file_path); result = true; break; case 1: // set access ACL as default ACL switch (a.transaction.action) { case cfa_warn: cfPS(OUTPUT_LEVEL_ERROR, CF_WARN, "", pp, a, " !! Default ACL on \"%s\" needs to be copied from access ACL.", file_path); break; case cfa_fix: if (!DONTDO) { if ((acl_set_file(file_path, ACL_TYPE_DEFAULT, acl_access)) != 0) { CfOut(OUTPUT_LEVEL_ERROR, "", "!! Could not set default ACL to access"); acl_free(acl_access); acl_free(acl_default); return false; } } cfPS(OUTPUT_LEVEL_INFORM, CF_CHG, "", pp, a, "-> Default ACL on \"%s\" successfully copied from access ACL.", file_path); result = true; break; default: ProgrammingError("Cfengine: internal error: illegal file action\n"); result = false; } break; default: result = false; CfOut(OUTPUT_LEVEL_ERROR, "", "!! Unable to compare access and default ACEs"); } acl_free(acl_access); acl_free(acl_default); return result; }
MateVFSResult file_get_acl (const char *path, MateVFSFileInfo *info, struct stat *statbuf, MateVFSContext *context) { #ifdef HAVE_SOLARIS_ACL int re; int aclcnt; aclent_t *aclp; if (info->acl != NULL) { mate_vfs_acl_clear (info->acl); } else { info->acl = mate_vfs_acl_new (); } aclcnt = acl (path, GETACLCNT, 0, NULL); if (aclcnt < 0) { return aclerrno_to_vfserror (errno); } if (aclcnt < MIN_ACL_ENTRIES) { return MATE_VFS_ERROR_INTERNAL; } aclp = (aclent_t *)malloc(sizeof (aclent_t) * aclcnt); if (aclp == NULL) { return MATE_VFS_ERROR_NO_MEMORY; } errno = 0; re = acl (path, GETACL, aclcnt, aclp); if (re < 0) { return aclerrno_to_vfserror (errno); } re = solaris_acl_read (info->acl, aclp, aclcnt, FALSE); if (re < 0) { return MATE_VFS_ERROR_INTERNAL; } info->valid_fields |= MATE_VFS_FILE_INFO_FIELDS_ACL; free (aclp); return MATE_VFS_OK; #elif defined(HAVE_POSIX_ACL) acl_t p_acl; int n; if (info->acl != NULL) { mate_vfs_acl_clear (info->acl); } else { info->acl = mate_vfs_acl_new (); } p_acl = acl_get_file (path, ACL_TYPE_ACCESS); n = posix_acl_read (info->acl, p_acl, FALSE); if (p_acl) { acl_free (p_acl); } if (S_ISDIR (statbuf->st_mode)) { p_acl = acl_get_file (path, ACL_TYPE_DEFAULT); n += posix_acl_read (info->acl, p_acl, TRUE); if (p_acl) { acl_free (p_acl); } } if (n > 0) { info->valid_fields |= MATE_VFS_FILE_INFO_FIELDS_ACL; } else { g_object_unref (info->acl); info->acl = NULL; } return MATE_VFS_OK; #else return MATE_VFS_ERROR_NOT_SUPPORTED; #endif }
static int32_t aacls(xar_file_t f, const char *file) { #ifdef HAVE_SYS_ACL_H #if !defined(__APPLE__) acl_t a; const char *type; xar_prop_get(f, "type", &type); if( !type || (strcmp(type, "symlink") == 0) ) return 0; a = acl_get_file(file, ACL_TYPE_DEFAULT); if( a ) { char *t; acl_entry_t e; /* If the acl is empty, or not valid, skip it */ if( acl_get_entry(a, ACL_FIRST_ENTRY, &e) != 1 ) goto NEXT; t = acl_to_text(a, NULL); if( t ) { xar_prop_set(f, "acl/default", t); acl_free(t); } acl_free(a); } NEXT: a = acl_get_file(file, ACL_TYPE_ACCESS); if( a ) { char *t; acl_entry_t e; /* If the acl is empty, or not valid, skip it */ if( acl_get_entry(a, ACL_FIRST_ENTRY, &e) != 1 ) goto DONE; t = acl_to_text(a, NULL); if( t ) { xar_prop_set(f, "acl/access", t); acl_free(t); } acl_free(a); } DONE: #else /* !__AAPLE__ */ acl_entry_t e = NULL; acl_t a; int i; a = acl_get_file(file, ACL_TYPE_EXTENDED); if( !a ) return 0; for( i = 0; acl_get_entry(a, e == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY, &e) == 0; i++ ) { char *t; t = acl_to_text(a, NULL); if( t ) { xar_prop_set(f, "acl/appleextended", t); acl_free(t); } } acl_free(a); #endif /* !__APPLE__ */ #endif return 0; }