static uint32_t spoolss_format_sd(smb_sd_t *sd) { smb_fssd_t fs_sd; acl_t *acl; uint32_t status = ERROR_SUCCESS; if (acl_fromtext("everyone@:full_set::allow", &acl) != 0) { smb_tracef("spoolss_format_sd: NOT_ENOUGH_MEMORY"); return (ERROR_NOT_ENOUGH_MEMORY); } smb_fssd_init(&fs_sd, SMB_ALL_SECINFO, SMB_FSSD_FLAGS_DIR); fs_sd.sd_uid = 0; fs_sd.sd_gid = 0; fs_sd.sd_zdacl = acl; fs_sd.sd_zsacl = NULL; status = smb_sd_fromfs(&fs_sd, sd); if (status != NT_STATUS_SUCCESS) { smb_tracef("spoolss_format_sd: %u", status); status = ERROR_ACCESS_DENIED; } smb_fssd_term(&fs_sd); return (status); }
int acl_parse(const char *acltextp, acl_t **aclp) { int error; yyinteractive = 1; error = acl_fromtext(acltextp, aclp); yyinteractive = 0; return (error); }
aclent_t * aclfromtext(char *aclstr, int *aclcnt) { acl_t *aclp; aclent_t *aclentp; int error; error = acl_fromtext(aclstr, &aclp); if (error) return (NULL); aclentp = aclp->acl_aclp; aclp->acl_aclp = NULL; *aclcnt = aclp->acl_cnt; acl_free(aclp); return (aclentp); }
static uint32_t srvsvc_sd_get_autohome(const smb_share_t *si, smb_sd_t *sd) { smb_fssd_t fs_sd; acl_t *acl; uint32_t status; if (acl_fromtext("owner@:rwxpdDaARWcCos::allow", &acl) != 0) return (ERROR_NOT_ENOUGH_MEMORY); smb_fssd_init(&fs_sd, SMB_ALL_SECINFO, SMB_FSSD_FLAGS_DIR); fs_sd.sd_uid = si->shr_uid; fs_sd.sd_gid = si->shr_gid; fs_sd.sd_zdacl = acl; fs_sd.sd_zsacl = NULL; status = smb_sd_fromfs(&fs_sd, sd); status = srvsvc_sd_status_to_error(status); smb_fssd_term(&fs_sd); return (status); }
compare_acls(acl_t acl, struct archive_test_acl_t *myacls, int n) #endif { int *marker; int matched; int i; #if HAVE_SUN_ACL int e; aclent_t *acl_entry; #else int entry_id = ACL_FIRST_ENTRY; acl_entry_t acl_entry; #endif /* Count ACL entries in myacls array and allocate an indirect array. */ marker = malloc(sizeof(marker[0]) * n); if (marker == NULL) return; for (i = 0; i < n; i++) marker[i] = i; /* * Iterate over acls in system acl object, try to match each * one with an item in the myacls array. */ #if HAVE_SUN_ACL for(e = 0; e < acl->acl_cnt; e++) { acl_entry = &((aclent_t *)acl->acl_aclp)[e]; #else while (1 == acl_get_entry(acl, entry_id, &acl_entry)) { /* After the first time... */ entry_id = ACL_NEXT_ENTRY; #endif /* Search for a matching entry (tag and qualifier) */ for (i = 0, matched = 0; i < n && !matched; i++) { if (acl_match(acl_entry, &myacls[marker[i]])) { /* We found a match; remove it. */ marker[i] = marker[n - 1]; n--; matched = 1; } } /* TODO: Print out more details in this case. */ failure("ACL entry on file that shouldn't be there"); assert(matched == 1); } /* Dump entries in the myacls array that weren't in the system acl. */ for (i = 0; i < n; ++i) { failure(" ACL entry missing from file: " "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n", myacls[marker[i]].type, myacls[marker[i]].permset, myacls[marker[i]].tag, myacls[marker[i]].qual, myacls[marker[i]].name); assert(0); /* Record this as a failure. */ } free(marker); } #endif /* * Verify ACL restore-to-disk. This test is Platform-specific. */ DEFINE_TEST(test_acl_platform_posix1e_restore) { #if !HAVE_SUN_ACL && !HAVE_POSIX_ACL skipping("POSIX.1e ACLs are not supported on this platform"); #else /* HAVE_SUN_ACL || HAVE_POSIX_ACL */ struct stat st; struct archive *a; struct archive_entry *ae; int n, fd; char *func; #if HAVE_SUN_ACL acl_t *acl, *acl2; #else acl_t acl; #endif /* * First, do a quick manual set/read of ACL data to * verify that the local filesystem does support ACLs. * If it doesn't, we'll simply skip the remaining tests. */ #if HAVE_SUN_ACL n = acl_fromtext("user::rwx,user:1:rw-,group::rwx,group:15:r-x,other:rwx,mask:rwx", &acl); failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); #else acl = acl_from_text("u::rwx,u:1:rw,g::rwx,g:15:rx,o::rwx,m::rwx"); failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); assert((void *)acl != NULL); #endif /* Create a test file and try ACL on it. */ fd = open("pretest", O_WRONLY | O_CREAT | O_EXCL, 0777); failure("Could not create test file?!"); if (!assert(fd >= 0)) { acl_free(acl); return; } #if HAVE_SUN_ACL n = facl_get(fd, 0, &acl2); if (n != 0) { close(fd); acl_free(acl); } if (errno == ENOSYS) { skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } failure("facl_get(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); if (acl2->acl_type != ACLENT_T) { acl_free(acl2); skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } acl_free(acl2); func = "facl_set()"; n = facl_set(fd, acl); #else func = "acl_set_fd()"; n = acl_set_fd(fd, acl); #endif acl_free(acl); if (n != 0) { #if HAVE_SUN_ACL if (errno == ENOSYS) #else if (errno == EOPNOTSUPP || errno == EINVAL) #endif { close(fd); skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } } failure("%s: errno = %d (%s)", func, errno, strerror(errno)); assertEqualInt(0, n); #if HAVE_SUN_ACL #endif close(fd); /* Create a write-to-disk object. */ assert(NULL != (a = archive_write_disk_new())); archive_write_disk_set_options(a, ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL); /* Populate an archive entry with some metadata, including ACL info */ ae = archive_entry_new(); assert(ae != NULL); archive_entry_set_pathname(ae, "test0"); archive_entry_set_mtime(ae, 123456, 7890); archive_entry_set_size(ae, 0); assertEntrySetAcls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); archive_entry_free(ae); /* Close the archive. */ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); assertEqualInt(ARCHIVE_OK, archive_write_free(a)); /* Verify the data on disk. */ assertEqualInt(0, stat("test0", &st)); assertEqualInt(st.st_mtime, 123456); #if HAVE_SUN_ACL n = acl_get("test0", 0, &acl); failure("acl_get(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); #else acl = acl_get_file("test0", ACL_TYPE_ACCESS); failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno)); assert(acl != (acl_t)NULL); #endif compare_acls(acl, acls2, sizeof(acls2)/sizeof(acls2[0])); acl_free(acl); #endif /* HAVE_SUN_ACL || HAVE_POSIX_ACL */ } /* * Verify ACL read-from-disk. This test is Platform-specific. */ DEFINE_TEST(test_acl_platform_posix1e_read) { #if !HAVE_SUN_ACL && !HAVE_POSIX_ACL skipping("POSIX.1e ACLs are not supported on this platform"); #else struct archive *a; struct archive_entry *ae; int n, fd, flags, dflags; char *func, *acl_text; const char *acl1_text, *acl2_text, *acl3_text; #if HAVE_SUN_ACL acl_t *acl, *acl1, *acl2, *acl3; #else acl_t acl1, acl2, acl3; #endif /* * Manually construct a directory and two files with * different ACLs. This also serves to verify that ACLs * are supported on the local filesystem. */ /* Create a test file f1 with acl1 */ #if HAVE_SUN_ACL acl1_text = "user::rwx," "group::rwx," "other:rwx," "user:1:rw-," "group:15:r-x," "mask:rwx"; n = acl_fromtext(acl1_text, &acl1); failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); #else acl1_text = "user::rwx\n" "group::rwx\n" "other::rwx\n" "user:1:rw-\n" "group:15:r-x\n" "mask::rwx"; acl1 = acl_from_text(acl1_text); failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); assert((void *)acl1 != NULL); #endif fd = open("f1", O_WRONLY | O_CREAT | O_EXCL, 0777); failure("Could not create test file?!"); if (!assert(fd >= 0)) { acl_free(acl1); return; } #if HAVE_SUN_ACL /* Check if Solaris filesystem supports POSIX.1e ACLs */ n = facl_get(fd, 0, &acl); if (n != 0) close(fd); if (n != 0 && errno == ENOSYS) { acl_free(acl1); skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } failure("facl_get(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); if (acl->acl_type != ACLENT_T) { acl_free(acl); acl_free(acl1); close(fd); skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } func = "facl_set()"; n = facl_set(fd, acl1); #else func = "acl_set_fd()"; n = acl_set_fd(fd, acl1); #endif acl_free(acl1); if (n != 0) { #if HAVE_SUN_ACL if (errno == ENOSYS) #else if (errno == EOPNOTSUPP || errno == EINVAL) #endif { close(fd); skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } } failure("%s: errno = %d (%s)", func, errno, strerror(errno)); assertEqualInt(0, n); close(fd); assertMakeDir("d", 0700); /* * Create file d/f1 with acl2 * * This differs from acl1 in the u:1: and g:15: permissions. * * This file deliberately has the same name but a different ACL. * Github Issue #777 explains how libarchive's directory traversal * did not always correctly enter directories before attempting * to read ACLs, resulting in reading the ACL from a like-named * file in the wrong directory. */ #if HAVE_SUN_ACL acl2_text = "user::rwx," "group::rwx," "other:---," "user:1:r--," "group:15:r--," "mask:rwx"; n = acl_fromtext(acl2_text, &acl2); failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); #else acl2_text = "user::rwx\n" "group::rwx\n" "other::---\n" "user:1:r--\n" "group:15:r--\n" "mask::rwx"; acl2 = acl_from_text(acl2_text); failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); assert((void *)acl2 != NULL); #endif fd = open("d/f1", O_WRONLY | O_CREAT | O_EXCL, 0777); failure("Could not create test file?!"); if (!assert(fd >= 0)) { acl_free(acl2); return; } #if HAVE_SUN_ACL func = "facl_set()"; n = facl_set(fd, acl2); #else func = "acl_set_fd()"; n = acl_set_fd(fd, acl2); #endif acl_free(acl2); if (n != 0) close(fd); failure("%s: errno = %d (%s)", func, errno, strerror(errno)); assertEqualInt(0, n); close(fd); /* Create nested directory d2 with default ACLs */ assertMakeDir("d/d2", 0755); #if HAVE_SUN_ACL acl3_text = "user::rwx," "group::r-x," "other:r-x," "user:2:r--," "group:16:-w-," "mask:rwx," "default:user::rwx," "default:user:1:r--," "default:group::r-x," "default:group:15:r--," "default:mask:rwx," "default:other:r-x"; n = acl_fromtext(acl3_text, &acl3); failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); #else acl3_text = "user::rwx\n" "user:1:r--\n" "group::r-x\n" "group:15:r--\n" "mask::rwx\n" "other::r-x"; acl3 = acl_from_text(acl3_text); failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); assert((void *)acl3 != NULL); #endif #if HAVE_SUN_ACL func = "acl_set()"; n = acl_set("d/d2", acl3); #else func = "acl_set_file()"; n = acl_set_file("d/d2", ACL_TYPE_DEFAULT, acl3); #endif acl_free(acl3); failure("%s: errno = %d (%s)", func, errno, strerror(errno)); assertEqualInt(0, n); /* Create a read-from-disk object. */ assert(NULL != (a = archive_read_disk_new())); assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, ".")); assert(NULL != (ae = archive_entry_new())); #if HAVE_SUN_ACL flags = ARCHIVE_ENTRY_ACL_TYPE_POSIX1E | ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA | ARCHIVE_ENTRY_ACL_STYLE_SOLARIS; dflags = flags; #else flags = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; dflags = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; #endif /* Walk the dir until we see both of the files */ while (ARCHIVE_OK == archive_read_next_header2(a, ae)) { archive_read_disk_descend(a); if (strcmp(archive_entry_pathname(ae), "./f1") == 0) { acl_text = archive_entry_acl_to_text(ae, NULL, flags); assertEqualString(acl_text, acl1_text); free(acl_text); } else if (strcmp(archive_entry_pathname(ae), "./d/f1") == 0) { acl_text = archive_entry_acl_to_text(ae, NULL, flags); assertEqualString(acl_text, acl2_text); free(acl_text); } else if (strcmp(archive_entry_pathname(ae), "./d/d2") == 0) { acl_text = archive_entry_acl_to_text(ae, NULL, dflags); assertEqualString(acl_text, acl3_text); free(acl_text); } } archive_entry_free(ae); assertEqualInt(ARCHIVE_OK, archive_free(a)); #endif }
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 {